KVM-XJ تصحيح ساخن
dump_tool.py يقوم تلقائيًا بالعثور على الإزاحات، كيفية استخدامه انظر إلى الكود بنفسك
نظرة عامة على الثغرة
CVE-2026-53359 (Januscape) هي ثغرة استخدام بعد التحرير (UAF) في KVM Shadow MMU لنواة لينكس.
- زمن الكمون: 16 عامًا (أغسطس 2010 حتى يوليو 2026)
- نطاق التأثير: جميع أنظمة Intel/AMD x86 مع تفعيل المحاكاة الافتراضية المتداخلة
- مستوى الخطورة: عالٍ، يمكن لمستخدم root داخل VM الهروب إلى المضيف والحصول على صلاحيات root على المضيف
- طريقة الاستغلال: انهيار نواة المضيف (DoS) أو هروب كامل من الجهاز الافتراضي (لا يوجد POC عام)
مبدأ الثغرة
عندما تبحث دالة kvm_mmu_get_page() في جدول التجزئة عن صفحة جدول ظل قابلة لإعادة الاستخدام، فإنها تقارن فقط gfn (رقم إطار الصفحة الفيزيائية للضيف)، دون مقارنة role (دور الجدول/دور MMU)، مما يؤدي إلى إعادة استخدام خاطئة لجدول غير متطابق في الدور، مما يسبب UAF.
قبل الإصلاح (به ثغرة):
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ تجاوز جدول التجزئة │
│ if (child->gfn == gfn) │
│ return child ← يقارن gfn فقط! │
│ إعادة استخدام حتى لو لم يتطابق الدور → UAF! │
│ تخصيص صفحة جديدة (آمن) │
└──────────────────────────────────────┘
في commit النواة الرئيسية 81ccda30b4e8 تمت إضافة سطر لمقارنة role:
// قبل الإصلاح
if (... && spte_to_child_sp(*sptep)->gfn == gfn)
// بعد الإصلاح
if (... && spte_to_child_sp(*sptep)->gfn == gfn
&& spte_to_child_sp(*sptep)->role.word == role.word)
طريقي في الإصلاح
الطريقة: تصحيح ثنائي ساخن عبر text_poke (تصحيح NOP)
بدون تعديل كود مصدر النواة، وبدون استبدال الدوال، بل تعديل تعليمات الثغرة مباشرة في ذاكرة النواة العاملة.
المبدأ
على المستوى الثنائي:
الإزاحة 0x104: 49 39 47 28 cmp %rax, 0x28(%r15) ← مقارنة gfn
الإزاحة 0x108: 0f 84 9f 01 00 00 je +0x19f ← إذا تطابق اقفز لإعادة الاستخدام
بعد التصحيح:
الإزاحة 0x108: 66 0f 1f 44 00 00 NOP × 6 ← لا يفعل شيئًا
بعد الإصلاح:
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ تجاوز جدول التجزئة │
│ if (child->gfn == gfn) │
│ NOP (القفزة مُزالت، تمر عبرها) │
│ تخصيص صفحة جديدة (إجبار المسار الآمن) │
│ → لا إعادة استخدام = لا UAF = تم إصلاح الثغرة │
└──────────────────────────────────────┘
التنفيذ التقني
- العثور على عنوان دالة
kvm_mmu_get_page عبر kallsyms_lookup_name
- العثور على دالة
text_poke عبر kallsyms_lookup_name (واجهة برمجية للتعديل الساخن على كود النواة)
- استخدام
stop_machine لإيقاف جميع وحدات المعالجة المركزية مؤقتًا لضمان سلامة التعديل
- استخدام
text_poke لاستبدال تعليمة je ذات 6 بايت بتعليمة NOP ذات 6 بايت
- عند الإلغاء، استخدام
text_poke لاستعادة التعليمات الأصلية
لماذا لا تُستخدم الحلول الأخرى
تقييم التأثير
متطلبات النشر
| الشرط | الوصف |
|---|
| إصدار النواة | Linux 4.18+ (CentOS 8 / RHEL 8 / Rocky 8 وغيرها) |
| بيئة الترجمة | kernel-devel + gcc + make |
|
الترجمة والتحميل
# الترجمة
make
# تحميل التصحيح الساخن
insmod KVM-XJ.ko
# عرض الحالة
dmesg | grep KVM-XJ
cat /sys/module/kvm_intel/parameters/nested # يجب أن يظل 1
lsmod | grep KVM_XJ
# الإلغاء (استعادة الكود الأصلي)
rmmod KVM_XJ
التوافق مع النوى الأخرى
تختلف تحسينات الترجمة بين إصدارات النواة المختلفة، وكذلك إزاحة تعليمة je. استخدم dump_tool.py للتحليل التلقائي:
# 1. تنزيل kvm.ko من المضيف
scp root@المضيف:/lib/modules/.../kvm.ko.xz .
xz -d kvm.ko.xz
# 2. تشغيل أداة التحليل
python dump_tool.py kvm.ko
# 3. ستقوم الأداة بإخراج إزاحة التصحيح، عدّل قيمة 0x108 في KVM-XJ.c
النوى التي تم التحقق منها
| إصدار النواة | إزاحة je | الحالة |
|---|
| 4.18.0-496.el8.x86_64 | 0x108 | تم اختباره |
| 4.18.0-358.el8.x86_64 | 0xe8 | تم اختباره |
ملاحظات
- من لا يعرف كيفية الاستخدام أو قراءة الكود، يُنصح بعدم استخدامه