
إثبات مفهوم مستقل لـ CVE-2026-86547، وهو إلغاء مرجع مؤشر NULL في mrubyc op_enter() حتى الإصدار 4.0.0.
OP_ENTER الخاص بـ mrubycإثبات مفهوم مستقل لـ CVE-2026-86547، وهو إلغاء الإشارة إلى مؤشر NULL في معالج op_enter() الخاص بـ mrubyc حتى الإصدار 4.0.0.
mrubyc هو تطبيق خفيف الوزن للغة Ruby مخصص للأنظمة المدمجة. تحتفظ آلة البايت كود الافتراضية الخاصة به بمؤشر إطار الاستدعاء الحالي في mrbc_vm.callinfo_tail. على المستوى الأعلى، يقوم mrbc_vm_begin() بتهيئة هذا المؤشر إلى NULL لأنه لا يوجد إطار استدعاء دالة بعد.
في تطبيق op_enter() المصاب في release4.0.0، يقرأ المعالج callinfo->reg_offset دون التحقق أولاً مما إذا كان vm->callinfo_tail يساوي NULL:
mrbc_callinfo *callinfo = vm->callinfo_tail;
int reg_offset = callinfo->reg_offset;
يمكن لبرنامج بايت كود .mrb مُصمَّم بعناية أن يضع OP_ENTER على المستوى الأعلى، مما يؤدي بالمفسّر إلى الوصول إلى هذا الكود مع callinfo_tail بقيمة NULL والانهيار عبر إلغاء الإشارة إلى مؤشر NULL.
CVE: CVE-2026-86547
النوع: CWE-476 — إلغاء الإشارة إلى مؤشر NULL
التأثير: التوافر / حجب الخدمة
المتأثر: mrubyc حتى 4.0.0
الخطورة: متوسطة، CVSS 6.9 (وفقاً للتنبيه)
يحاكي PoC تخطيطات mrbc_callinfo وmrbc_vm ذات الصلة ويعيد إنتاج الوصول المصاب إلى الذاكرة بشكل مستقل عن بيئة تشغيل mrubyc الكاملة.
يوضح مسارين:
callinfo_tail بقيمة NULL ويتم إلغاء الإشارة إلى callinfo->reg_offset دون حماية، مما ينتج عنه خطأ في التقسيم (segmentation fault).OP_ENTER على المستوى الأعلى بأمان، يليه اختبار تحكم يُظهر أن إطار استدعاء صالحاً لا يزال يعمل.يستخدم الـ harness الكلمة المفتاحية volatile على المؤشر المصاب و__builtin_trap() في وصفه لجعل أداة إعادة الإنتاج مناسبة للمراقبة القائمة على sanitizer. الوصول المصاب الفعلي هو قراءة callinfo->reg_offset.
gcc -O0 -g -o poc poc.c
./poc
النتيجة المتوقعة على المسار المصاب هي خطأ في التقسيم بعد:
[VULNERABLE PATH] op_enter without NULL guard
vm->callinfo_tail = NULL (top-level frame)
About to dereference NULL...
gcc -O0 -g -fsanitize=address -fno-omit-frame-pointer -o poc-asan poc.c
./poc-asan
يجب أن يُبلّغ الـ sanitizer عن SEGV على عنوان يقابل حقل reg_offset من قاعدة mrbc_callinfo بقيمة NULL. مع تخطيط البنية المستخدم هنا، يكون offsetof(mrbc_callinfo, reg_offset) مساوياً لـ 0x14.
./poc fixed
يتضمن الناتج المتوقع:
[FIXED PATH] op_enter with NULL guard
[GUARD] top-level OP_ENTER — rejected safely
[control, valid frame] reg_offset = 5
Fixed path: no crash.
يوجد المعالج المصاب الأصلي في src/vm.c في mrubyc release4.0.0، حول السطر 1537. العملية ذات الصلة هي إلغاء الإشارة المباشر إلى callinfo->reg_offset بعد إسناد vm->callinfo_tail إلى callinfo دون فحص NULL.
الكود المصدري بعد الإصلاح المشار إليه في البحث هو الـ commit 4261cf5e5ae5579e3110dab98a04b91c7d919429.
يوضح الـ harness المستقل خطأ الذاكرة الأساسي. في mrubyc نفسه، يتطلب المُشغِّل ملف بايت كود .mrb مُصمَّماً بعناية يحتوي على تعليمة OP_ENTER على المستوى الأعلى، خارج تعريف دالة. إذا قام تطبيق ما بتحميل وتنفيذ ملفات .mrb غير الموثوقة، فإن ملف بايت كود يتحكم فيه المهاجم يمكنه بالتالي إسقاط عملية المفسّر.
هذه حالة حجب خدمة. لا يدّعي البحث تنفيذ كود أو الكشف عن معلومات أو إفساد الذاكرة بما يتجاوز إلغاء الإشارة إلى NULL.
src/vm.csrc/vm.cOP_SUPER التي حفزت تدقيق op_enter()قصة الاكتشاف موثقة في: I Read Someone Else's Bug Report, Then Found The Same Missing Check In The Next Function Over.
كانت الملاحظة البحثية الرئيسية أن op_super() كان يفتقر إلى حماية NULL حول نفس الثابت vm->callinfo_tail. أظهر فحص معالج op_enter() المجاور أن نفس الافتراض كان موجوداً هناك دون الحماية المقابلة.