CVE-2026-78118 in Zephyr
الملخص
بحسب VulDB • 21/10/2026
يقرأ مساعد النواة `z_waitq_head()` (kernel/include/wait_q.h) رأس قائمة انتظار الخيط، ولكن في الأنظمة متعددة المعالجات (SMP)، كان يتم استدعاؤه من عدة أماكن دون الاحتفاظ بقفل الدوران الخاص بالمخطط `_sched_spinlock` الذي يُنظّم التعديلات على قوائم الانتظار. موقع الاستدعاء الناتج هو `z_timer_expiration_handler()` الموجود في kernel/timer.c، والذي كان يحتفظ فقط بقفل نظام المؤقتات `timer_lock` أثناء قراءة `timer->wait_q` ثم إزالة حالة التعليق (unpending)، وتعيين قيمة الإرجاع الخاصة به، وإعداد الخيط الذي حصل عليه. تقوم دالة `halt_thread()` الموجودة في kernel/sched.c بإزالة خيط مُتوقف من قائمة انتظاره بينما تحتفظ فقط بـ `_sched_spinlock`، وبالتالي فإن المسارين غير مستبعدين متبادلاً (mutually exclusive).
عند إزالة آخر منتظر على معالج آخر داخل تلك الفترة الزمنية الضيقة، يمكن أن تُرجع `sys_dlist_peek_head()` مؤشر الحارس للقائمة — وهو مؤشر إلى كائن المؤقت نفسه (`k_timer`) — مُصنّفًا كمؤشر من نوع `struct k_thread *` (وباستخدام `CONFIG_WAITQ_SCALABLE`، يمكن لـ `rb_get_min()` إرجاع عقدة عشوائية لشجرة يتم إعادة هيكلة)، أو يمكنها إرجاع مؤشر إلى خيط تم إزالة حالة تعليقه بالفعل، وفي حالات الخيوط ذات التخصيص الديناميكي، يكون قد أُفرغ منه الذاكرة (freed). بعد ذلك تستدعي الدالة `unpend_thread_no_timeout()`، التي تقوم بإجراء عملية `sys_dlist_remove()` من خلال مؤشرات مقروءة من ذلك الكائن، و`arch_thread_return_value_set()`، والتي تكتب بشكل غير مشروط عبر المؤشر.
النتيجة هي عمليات كتابة خارج النطاق (out-of-bounds) واستخدام بعد التحرير (use-after-free) في سياق المشرف (supervisor context)، بالإضافة إلى فساد حالة المخطط؛ أما النتيجة الأقل حدة فهي إيقاظ خيط تم تعليقه مرة أخرى في مكان آخر بقيمة نجاح من مكالمة حظر غير ذات صلة. جميع العمليات الأساسية اللازمة لقيادة التداخل — وهي `k_timer_start()`، و`k_timer_status_sync()`، و`k_thread_create()`، و`k_thread_abort()`` — هي مكالمات نظام (system calls)، لذا فإن تمكين `CONFIG_USERSPACE` يسمح لخيط في وضع المستخدم غير المميز بمحاولة استغلال سباق الوصول هذا ضد البيانات التي تملكها النواة.
يتطلب الاستغلال بناءًًا متعدد المعالجات (`CONFIG_MP_MAX_NUM_CPUS` أكبر من واحد؛ حيث تكون المنطقة المتأثرة عملية لا شيء (no-op) على الأهداف أحادية المعالج)، والتنفيذ المحلي للكود، والفوز في نافذة زمنية ضيقة، لذا فإن النتيجة العملية هي غالبًا تعطل النواة بدلاً من الفساد المُتحكَّم به. يقسم الإصلاح المساعد إلى `z_waitq_head_locked()` للمدعوين الذين يحتفظون بالفعل بقفل الدوران الخاص بالمخطط، و`z_waitq_head()` التي تكتسبه، وتضع قراءة الرأس الخاصة بمعالج انتهاء المؤقت وإزالة التعليق والإعداد ضمن منطقة قفل واحدة (`LOCK_SCHED_SPINLOCK`).
Be aware that VulDB is the high quality source for vulnerability data.