
pedit COW
CVE-2026-46331 (الملقب "pedit COW") هو ثغرة رفع صلاحية محلية في نواة لينكس ضمن نظام التحكم في حركة المرور. يمكن لمستخدم غير مميز (في نطاق شبكة غير مميز) تكوين فلتر act_pedit (محرر الحزم) لإحداث كتابة جزئية للنسخ عند الكتابة (COW) في ذاكرة التخزين المؤقت للصفحات. ونتيجة لذلك، تقوم النواة بكتابة بيانات يتحكم بها المهاجم في الصورة الذاكرية لملف دون وضع علامة على الصفحة كخاصة، مما يفسد النسخة المخبأة من ذلك الملف. بشكل حاسم، يتطلب الاستغلال فقط CAP_NET_ADMIN (يمكن الحصول عليها في نطاق مستخدم) ولا يعدّل الملف على القرص. عملياً، تم نشر إثبات المفهوم (PoC) عامل يُسمى packet_edit_meme في 17 يونيو 2026، يوضح كيفية استبدال صورة ذاكرة التخزين المؤقت لملف ثنائي setuid (مثل /bin/su) لإطلاق شل جذر. ينبع الثغرة من حساب غير صحيح لنطاق COW في tcf_pedit_act() وقد تم إصلاحه في النواة الرئيسية (4 يونيو 2026) عن طريق نقل التحقق من المنطقة القابلة للكتابة إلى الحلقة الخاصة بكل مفتاح.
act_pedit. الإصدارات المستقرة غير المُصححة (بما في ذلك نوى توزيعات عديدة) معرضة للثغرة.tc، ويستبدل نقطة الدخول ELF لملف ثنائي setuid في الذاكرة بكود شيل.skb_ensure_writable() داخل حلقة المفاتيح). كحل بديل، منع أو تفريغ وحدة act_pedit أو تعطيل نطاقات المستخدم غير المميزة (مثل sysctl user.max_user_namespaces=0). بعد التخفيف، إسقاط المخابئ (echo 3 > /proc/sys/vm/drop_caches) لإزالة أي صفحات مسمومة.يقدم هذا التقرير تحليلاً تقنياً مفصلاً لـ CVE-2026-46331: سببه، استغلاله، اكتشافه، واستراتيجيات المعالجة، مع مراجع لإشعارات البائعين، CVEs، والاستغلال العام.
تعريف: CVE-2026-46331 هو خلل في الكتابة خارج النطاق في النظام الفرعي مراقبة حركة المرور (net/sched) في نواة لينكس، وتحديداً في إجراء act_pedit (محرر الحزم). تقوم الدالة tcf_pedit_act() بحساب نطاق "النسخ عند الكتابة" لعمليات تحرير الحزم قبل التكرار على المفاتيح المكتوبة، باستخدام تلميح ثابت tcfp_off_max_hint. ومع ذلك، بعض المفاتيح (مثل تعديلات رأس TCP/UDP) تحدد إزاحة البايت النهائية فقط في وقت التشغيل. لا يقوم الكود أبداً بإعادة التحقق من قابلية الكتابة لهذه الإزاحات الديناميكية. ونتيجة لذلك، يمكن أن تحدث كتابات خارج المنطقة التي تم نسخها مسبقاً: جزء من كتابة الحزمة لا يتم جعله خاصاً أبداً، مما يؤدي إلى COW جزئي. تنتشر هذه الكتابة الخاطئة إلى ذاكرة التخزين المؤقت المشتركة لملف (إذا كانت مخازن الحزم تشير إلى صفحات ملف)، مما يفسد صورة الملف المخبأة.
خلفية: يسمح إجراء محرر الحزم (pedit) في لينكس للمسؤولين بإعادة كتابة بايتات عشوائية داخل رؤوس الحزم (طبقة الربط أو الشبكة أو النقل) أثناء مرور الحزم عبر فلتر tc مهيأ. يعمل بتحديد إزاحة (قد تكون مثبتة على رأس) وقيمة/قناع 32 بت. داخلياً، يعمل pedit على مخازن المقابس (sk_buff) ويجب جعل ذاكرة الحزم المستهدفة قابلة للكتابة قبل تعديلها (عبر skb_ensure_writable() بطريقة COW). من الناحية المثالية، يجب على النواة استنساخ (نسخة خاصة) أي صفحات مشتركة قبل الكتابة لتجنب تغيير الذاكرة المستخدمة في مكان آخر.
السبب الجذري: في tcf_pedit_act()، يحسب الكود النطاق القابل للكتابة مرة واحدة فقط مسبقاً، باستخدام tcfp_off_max_hint (أقصى إزاحة ثابتة). هذا التلميح لا يتضمن أي إزاحة رأس وقت التشغيل التي تضيفها المفاتيح المكتوبة عند معالجة الحزمة. المفاتيح مثل TCP أو UDP يمكنها حساب إزاحة بناءً على موقع رأس IP في وقت التشغيل (على سبيل المثال، إذا قام مفتاح سابق بنقل رأس الشبكة). وبالتالي، أثناء حلقة المفاتيح، قد تتجاوز الإزاحة الفعلية لمفتاح النطاق الذي تم تخصيصه مسبقاً كقابل للكتابة. ثم يكتب الكود في ذاكرة الحزمة عبر skb_store_bits()، ولكن نظراً لأن الصفحة خارج المنطقة التي تم نسخها مسبقاً لم تُجعل خاصة، فإن الكتابة تفسد صفحة لا تزال مشتركة مع ذاكرة التخزين المؤقت للصفحات. باختصار، "حساب نطاق الحزمة القابل للكتابة مبكراً جداً" يسبب كتابة خارج النطاق عبر الصفحات. كما أن الإزاحات السالبة (مثل تحرير رأس إيثرنت عند الدخول) لم تتم معالجتها بشكل صحيح، وحتى offset_valid() تفتقر إلى حماية ضد INT_MIN، مما يزيد من العيب.
لماذا يحدث: هذا الخلل هو في الأساس خطأ منطقي في حساب نطاق النسخ عند الكتابة. افترضت النواة أن أقصى إزاحة ثابتة (المعروفة وقت التحميل) كافية لجميع التعديلات. فشلت في تحديث نطاق COW عند تطبيق المفاتيح ذات الإزاحات الديناميكية فعلياً. بعد سلسلة من التعديلات المصفوفة، قد تقع الكتابة النهائية خارج المنطقة التي تم التحقق منها مسبقاً. نظراً لأن مخازن الحزم قد تشير إلى صفحات ملفات معممة في الذاكرة (مثلاً عبر آليات النسخ الصفري)، يمكن لهذه الكتابة "COW الجزئي" أن تصل إلى ذاكرة التخزين المؤقت لملف على القرص. عملياً، قد يستقبل إجراء محرر الحزم صفحات من sendfile أو splice؛ وبالتالي يمكن لعملية فلتر حزمة واحدة كتابة بيانات يختارها المهاجم بشكل غير مباشر في الصورة الذاكرية لملف، دون تغيير القرص.
المكونات وتدفق البيانات: يقع الكود المعرض للثغرة في النظام الفرعي net/sched في لينكس (act_pedit.c). عندما تتطابق حزمة مع قاعدة pedit مهيأة، يتم استدعاء tcf_pedit_act(). داخلياً تستدعي skb_ensure_writable(skb, X) مرة واحدة بالضبط، حيث X = tcfp_off_max_hint. هذا يجعل أول X بايت من الحزمة خاصة (مستنسخة عند الكتابة). ثم، في حلقة على كل مفتاح (عملية تحرير)، تحسب الإزاحة الفعلية للكتابة للمفتاح بإضافة إزاحة الرأس وقت التشغيل إلى الإزاحة المحددة للمفتاح، وتكتب قيمة 32 بت في الحزمة. في شبه كود:```c
u32 off_max = action->tcfp_off_max_hint;
skb_ensure_writable(skb, off_max);
for (i = 0; i < num_keys; i++) {
u32 hdr_off = compute_header_offset(skb, key[i].hdr_type);
u32 write_off = hdr_off + key[i].offset;
skb_store_bits(skb, write_off, &key[i].value, 4);
}
لأن `hdr_off` يُحسَب فقط عند معالجة كل مفتاح، فإن الاستدعاء الأولي لـ `skb_ensure_writable()` لم يأخذه في الحسبان. إذا تجاوز `hdr_off + key[i].offset` القيمة `off_max`، فإن الكود يتراجع إلى `skb_store_bits()` على الأجزاء (fragments) بدلاً من المنطقة الخطية الرئيسية، مما يعني أنه يكتب في صفحة لم تُجعل خاصة. هذه هي نقطة الفشل.
**سطح الهجوم:** الواجهة الوحيدة المطلوبة هي **مرشح tc** مع إجراء `pedit`، والذي يتطلب عادةً صلاحية **CAP_NET_ADMIN**. ومع ذلك، يمكن للمستخدمين العاديين الحصول على CAP_NET_ADMIN داخل مساحة اسم شبكة خاصة (استنساخ مساحة اسم المستخدم) دون امتيازات حقيقية. وبالتالي، يمكن لمستخدم غير مميز الدخول إلى مساحة اسم مستخدم+شبكة وإنشاء قاعدة `tc pedit` على loopback. يحدث الكتابة عند معالجة حزمة (عادةً ما يُولّد المهاجم حركة مرور على loopback لتفعيلها). يتم عبور حدود الثقة (مستخدم مقابل نواة) لأن النواة وثقت في إعداد COW الخاص بها، لكن الإزاحات التي قدمها المستخدم حطمت هذا الافتراض.
**الآلية الداخلية:** على جانب النواة، يظهر الثغرة كـ **كتابة خارج النطاق** (CWE-787). فهي تُفسد ذاكرة النواة التي تم تعيينها في مساحة المستخدم (ذاكرة تخزين صفحات الملفات). على وجه التحديد، يمكنها الكتابة فوق محتويات أي صفحة ملف تحدث مصادفةً أن تكون معينة في المخزن المؤقت للمقبس (socket buffer). في الإثبات العملي (proof-of-concept)، تم تعيين `/bin/su` في الذاكرة (mmapped) عن طريق إرساله إلى المخزن المؤقت للمقبس، لذا يقوم الاستغلال بقلب بايتات نقطة الدخول الخاصة به في الذاكرة. هذا لا يُعدّل الملف على القرص، لكن أي تنفيذ لاحق لهذا البرنامج الثنائي سيقرأ الصورة المسمومة من الذاكرة المخبأة. يُلاحظ تحليل المدونة:
> “نظرًا لأن skb يمكنه الرجوع إلى صفحات النسخ الصفري (zero-copy) المسحوبة عبر sendfile، فإن تلك الكتابة خارج النطاق يمكن أن تصل إلى ذاكرة مشتركة لصفحات الملفات (page-cache memory) تدعم ملفًا حقيقيًا. تعتقد النواة أنها جعلت ذاكرة الحزمة آمنة للتعديل؛ في الواقع، تصل الكتابة اللاحقة إلى المنطقة خارج ما جعلته خاصًا بالفعل.”
**حدود الثقة:** افترضت النواة خطأً أن `skb_ensure_writable()` (مسار COW السريع) سيضمن السلامة لجميع عمليات الكتابة اللاحقة. لم تقم بإعادة التحقق لكل مفتاح. يتحكم المستخدم فقط في تكوين مرشح الحزمة ومحتوى الحزمة؛ وقد منحت النواة ذلك (عبر مساحات أسماء الشبكة). بمجرد انتهاك هذه الثقة، هربت الكتابة إلى ذاكرة مدعومة بملفات كان يجب أن تكون محمية.
## تحليل السبب الجذري