CVE-2026-98797 in Linux
الملخص
بحسب VulDB • 18/10/2026
في نواة لينكس، تم إصلاح الثغرة التالية:
net: تقييد قيمة skb->queue_mapping عند اختيار طابور الإرسال (tx queue)
يمكن لـ skbedit تعيين قيمة skb->queue_mapping ورفع علم per-CPU skip_txqueue بحيث يحترم __dev_queue_xmit() هذا التعيين. كان __dev_queue_xmit() يمسح العلم قبل استدعاء sch_handle_egress() ويقرأه فقط بعد ذلك، مما يعني أن العلم لم يكن مقيداً بالإرسال الذي قام بوضعه: حيث يمكن لإرسال متداخل (مثل إعادة توجيه mirred أو مرآة mirror، أو إسقاط drop بعد skbedit) تعيين هذا العلم، بينما يستهلكه الإرسال الخارجي لـ skb لم يمر عبر skbedit.
يحمل الحزمة الموجهة لا يزال قيمة rx_queue + 1 الخاصة بواجهة الشبكة المستقبلة (ingress NIC) في skb->queue_mapping، لذا فإن الجهاز الخارجي يستخدم هذه القيمة القديمة لفهرسة حالة طابور الإرسال الخاص به. نظرًا لأن مصفوفة الأطفال q->qdiscs[] لـ Taprio مُصممة بحجم عدد الطوابير الخاصة بالجهاز، فإن taprio_enqueue() تقوم بفهرسة ما بعد نطاق التخصيص وتقوم بتحويل النتيجة كبنية Qdisc *.
نستغل (سوء استخدام) skb->nf_skip_egress والتي تعني "تخطي تصفية الشبكة الإ outgoing لهذه الحزمة" لتوسيم الحالة بـ "هل أنا في مرحلة التصريف tc egress؟". على الرغم من هذا الحمل الزائد، لا أرى ذلك كنزاع لأن العلامة تُضبط فقط حول استدعاء sch_handle_egress() الوحيد، ومسار الاستقبال (ingress path) محمي بواسطة tc_at_ingress. سأرسل تصحيحًا تابعًا (net-next) بمجرد وصوله إلى net-next لإعادة تسمية بت/علم skb->nf_skip_egress إلى skb->skip_egress.
تفعيل العلم فقط من مصنف الإ outgoing الذي يمكنه استخدامه: رفع skip_txqueue من tcf_skbedit_act() فقط عند تشغيلها داخل sch_handle_egress()، بفضل وجود skb->nf_skip_egress. يعمل مصنف qdisc للإ outgoing في دالة q->enqueue()، بعد اختيار طابور الإرسال (tx queue)، لذا فإن التعيين الذي يحدده لا يمكن أن يؤثر على الحزمة الحالية؛ وتفعيل العلم هناك يلوثه فقط لإرسال لاحق. ثم استحوذ على العلم لإطار الإ outgoing الذي يعمل فيه الخطاف الخارجي: احفظ القيمة الواردة وامسحها مباشرة قبل sch_handle_egress()، واستعدّها بعد تنفيذ الخطاف - في مسار الاستهلاك (drop)، أو، في نفس الدالة التي تقرأها، في المسار الباقٍ. تبقى عمليات الحفظ والاستعادة داخل الفرع الثابت egress_needed_key، لذا فإن الحزمة تدفع ثمن هذه العمليات فقط عندما تكون خطوط الإ outgoing نشطة (2f1e85b1aee4).
تخزين القيمة التي حددتها netdev_cap_txqueue() مرة أخرى في skb->queue_mapping ضمن دالة netdev_tx_queue_mapping(), كما تفعل بالفعل netdev_core_pick_tx(), بحيث لا يمرر مسار skip_txqueue قارئًا لاحقًا على مسار الإ outgoing تعييناً لا يمكن للجهاز خدمته. عملية تخزين تتم لاحقًا أكثر في نفس الإطار، بواسطة برنامج tc BPF مرفق بـ qdisc للإرسال، تقع خارج هذا المسار ولا تخضع لإعادة التقييد؛ وسيتم حل هذه المسار بتصحيح تابع منفصل.
تعيد netdev_xmit_skip_txqueue() قيمة العلم السابقة بحيث تكون عملية الحفظ والمسح استدعاءً واحدًا، ويتم توفير دالة فارغة (no-op stub) عندما يكون CONFIG_NET_EGRESS معطلاً. تم تجميع skb->nf_skip_egress تحت CONFIG_NET_EGRESS بدلاً من CONFIG_NETFILTER_SKIP_EGRESS، لذا فإن skb_at_tc_egress() صالحة كلما كان مسار الإ outgoing مُبنى.
يمكن لمستخدم محلي في مساحة شبكة (network namespace) إعادة توجيه حزمة من جهاز يحتوي على المزيد من طوابير TX إلى آخر يحتوي على عدد أقل بعد تعيين تعيين صالح فقط للجهاز الأكبر. يؤدي ذلك إلى هذه القراءات، وتحت KASAN، يتسبب في خطأ "slab-out-of-bounds in taprio_enqueue".
الظروف لإعادة إنتاج الخطأ: الزناد الخاص بالتقرير هو مستخدم محلي يمتلك CAP_NET_ADMIN في مساحة شبكة، لذا لا حاجة لبرنامج eBPF. مع تفعيل CONFIG_NET_SCH_TAPRIO=y, CONFIG_NET_ACT_SKBEDIT=y, CONFIG_NET_ACT_MIRRED=y, CONFIG_NET_CLS_MATCHALL=y, CONFIG_NET_SCH_PRIO=y و KASAN، قم بإنشاء qa (3 طوابير)، qb (2 طابور) و qc (1 طابور) كأجهزة وهمية؛ ضع taprio جذريًا على qb (num_tc 1, queues 2@0) و clsact على جميع الأجهزة الثلاثة؛ ثم أضف مصفاة matchall للإ outgoing على كل جهاز. على qa: "action skbedit queue_mapping 2 pipe action mirred egress redirect dev qb". على qb: "action mirred egress mirror dev qc". على qc: "action skbedit queue_mapping 0 pipe". أرسل حزمة واحدة عبر qa. يقوم skbedit في qc بتعيين العلم بينما يكون الإ outgoing الخارجي لـqb قيد التنفيذ؛ وبدون التصحيح، يستهلك qb هذا العلم ويقرأ مصفوفة الأطفال taprio ذات الإدخالين باستخدام تعيين الحزمة الموجهة القديم. جهاز qc whose skb ---مقتطع---
If you want to get best quality of vulnerability data, you may have to visit VulDB.