
بحث حول CVE-2026-43499 (GhostLock) على HUAWEI MatePad Pro 11 GOT-W29
سجل بحث لتصعيد الامتيازات على HUAWEI MatePad Pro 11 GOT-W29 (Qualcomm kona / Snapdragon 870, HarmonyOS 4.x, kernel
4.19.157-perf+) عبر CVE-2026-43499 (Linux rtmutex/futex-PI UAF, "GhostLock").
| العنصر | القيمة |
|---|---|
| الطراز | HUAWEI MatePad Pro 11 GOT-W29 (جهاز لوحي) |
| SoC | Qualcomm kona (SM8250, Snapdragon 870) |
| النظام | HarmonyOS 4.2 (104.2.0.237C00), الأصلي 4.0 (104.0.0.136) |
| النواة | 4.19.157-perf+ (بناء 2025-10-13) |
| VA | 39-بت، صفحات 4K، KASLR مفعّل |
CVE-2026-43499: الدالة remove_waiter() في kernel/locking/rtmutex.c تستخدم
في مسار التراجع لـ rt_mutex_start_proxy_lock() المتغير current بدلاً من waiter->task للتنظيف،
مما يسبب pi_blocked_on معلّقًا (UAF على المكدس). تؤثر على النوى 2.6.39 ~ 7.1 (النواة الحالية ضمن النطاق).
الإصلاح من المنبع: commit 3bfdc63936dd.
تم التحقق على هذا الجهاز: الكود المصدري rtmutex.c:1110-1112، فك تجميع boot.elf، والتشغيل على الجهاز الحقيقي — جميعها تم التحقق منها.
في بيئة shell (uid 2000) مع perf_event_paranoid=-1، يقوم perf_event_open(PERF_SAMPLE_IP, exclude_user=1) بأخذ عينات من عناوين نص النواة، وبمطابقتها مع إزاحات الرموز المعروفة نحصل على الـ slide.
samples=27651 kernel_ips=1685 lo=0xffffff948728176c hi=0xffffff9488ebfc7c
KASLR slide=0x147f200000 (40/40 IP 映射进内核文本区验证)
runtime _stext=0xffffff9487280800
الأداة: tools/perf_kaslr.c. شرط التشغيل: shell (Shizuku rish)، بدون اعتراض seccomp.
إنشاء حلقة PI تجعل FUTEX_CMP_REQUEUE_PI يُرجع -EDEADLK، وعند التراجع يتم تشغيل خطأ remove_waiter.
الترتيب الحرج: فوتكس الهدف لعملية الـ requeue يمتلكه الـ waiter المُعاد جدولته (futex2 = waiter_tid) → في task_blocks_on_rt_mutex يحدث owner == task → -EDEADLK.
[M] CMP_REQUEUE_PI ret=-1 errno=35 (EDEADLK!)
[W] WAIT_REQUEUE_PI ret=-1 errno=110 (ETIMEDOUT) ← waiter 返回
[M] waiter_returned=1 ← 留下悬空 pi_blocked_on
الأداة: tools/edeadlk_probe.c (البديل 8+2+1 = 11، أو 27).
الخطوة [7] من rt_mutex_adjust_prio_chain تنفذ rb_erase على fake waiter (مسار الطفل الأيسر الوحيد):
*(tree_left) = tree_pc (value→target) + كتابة تزايدية لـ __rb_change_child. جميع الإزاحات في target.h تم قياسها فعليًا من تفكيك boot.elf.
انظر target/got_w29_target.h. النقاط الأساسية:
تفكيك boot.elf لـ task_blocks_on_rt_mutex يُثبت: نواة هذا الجهاز تحتوي عند 0x3808-0x3868 على
فحص مبكر لـ owner==task (cmp owner,task; b.eq -> -EDEADLK)، وهو يعود قبل
كتابة task->pi_blocked_on (0x38d4 str x21,[x20,#0xa90]).
المشغّل القديم GOT-W29 جعل الـ waiter يمتلك futex2=waiter_tid (self-own) → يصيب هذا الفحص المبكر
تمامًا → لا يتم تعيين pi_blocked_on أبدًا → لا يوجد مؤشر معلّق. ملاحظات الجهاز (لا انهيار + boot_id لم يتغير)
تتوافق تمامًا مع "لا يوجد معلّق" — وضع الـ overlay كان تشخيصًا خاطئًا.
التشغيل الصحيح (مرجع smt878u، تم تنفيذه): حلقة PI — يمتلك الـ owner FUTEX_LOCK_PI(target) الهدفَ المُعاد جدولته؛ يمتلك الـ waiter فوتكس الـ chain؛ ثم يحجب الـ owner على الـ chain (الحلقة: waiter→target→owner→chain→waiter). عند الـ requeue يتحقق مسار الكشف rt_mutex_owner(chain)==top_task (الخطوة [6] من rtmutex) → -EDEADLK → عند التراجع يستخدم remove_waiter قيمة current الخاصة بالـ requeuer لمسح الشخص الخطأ → pi_blocked_on الخاص بالـ waiter يبقى معلقًا. يجب خفض أولوية الـ owner (nice=10) بحيث يختلف prio بعد الـ boost عن owner_waiter->prio، وإلا يحدث خروج مبكر في rt_mutex_waiter_equal.
عند shift=12 تقع الكلمات 6-7 (task/lock) من fake waiter في res_in[3..4] (منطقة تصفير النواة).
نستغل دلالات do_select: res_in[i] = in[i] & POLLIN-ready. نكتب SLIDE_INIT_TASK / fake_lock في in[3]/in[4]،
ونعيد توجيه جميع fds المقابلة عبر dup2 إلى "طرف قراءة أنبوب به بيانات" (جاهز EPOLLIN دائمًا) → ترميز دقيق
لـ res_in[3]=init_task و res_in[4]=fake_lock. الكلمات 3-5 (pi_tree) و 8-10 يمكن أن تكون صفرًا
(مسار القفل بدون مالك لا يستخدم pi_tree؛ prio/deadline تستبدلهما النواة في الخطوة [7]).
يرجع pselect فورًا بسبب fd الجاهز → يقوم الـ waiter بانتظار نشط في وضع المستخدم (تعطيل الإشارات، صفر استدعاءات نظام،
لمنع إعادة استخدام مكدس النواة من مسح fake waiter) حتى يكمل المستهلك. تم تنفيذ جدول 11-word HW_FUTEX_PI،
وفئتان من الـ fds، ومهلة انتظار العملية الأب (git diff).
*(boot_id)=DM(loggers[0][1]))،
يوجد فرق جزئي (off-by) بين stext=leaked-p0_alias_image_offset(NFULNL_LOGGER) و DM(_stext)؛
إذا استمرت مرحلة الجذر عبر physmap بالكامل (مساحة DM) فسيكون الناتج متسقًا ذاتيًا، وإلا فسنحتاج إلى استخدام slide وقت التشغيل من perf_event_open (متاح تحت rish).tools/cycle_probe (مجمّع مسبقًا): تحقق منخفض التكلفة من تشغيل cycle EDEADLK؛ بعد EDEADLK، إذا أدى استدعاء
sched_setattr على الـ waiter إلى حدوث consumer oops = وجود المؤشر المعلق + نجاح الـ overlay.build_tools/deploy_test.sh، ولاحظ ظهور slide-kaslr-ok أو consumer oops.tools/ 验证工具(perf KASLR, EDEADLK 探针, overlay 测试, kaslr.json)
target/ 全部实测偏移
exploit/ 移植的 slide.c(含 EDEADLK 触发改动)