
PoC وGDB script يساعدان في تفعيل CVE-2025-38352
برهان مفهوم (PoC) قابل لإعادة الإنتاج وسكربت تنسيق GDB آلي لـ CVE-2025-38352، وهي حالة تسابق من نوع Time-of-Check to Time-of-Use (TOCTOU) في النظام الفرعي لمؤقت CPU POSIX بنواة لينكس (kernel/time/posix-cpu-timers.c) تؤدي إلى استخدام بعد التحرير (UAF).
إخلاء مسؤولية: هذا المشروع لأغراض تعليمية ودفاعية وبحثية أمنية فقط. تم إجراء جميع الاختبارات وإعادة الإنتاج في جهاز افتراضي معزول ARM64 QEMU.
تنشئ العملية A العملية الابنة B.
تنشئ العملية B مؤقت CPU وتبدأ بالخروج، فتدخل حالة الزومبي. وبينما تخرج B، يصل مقاطعة مؤقت على نواة المعالج الخاصة بها. يدخل النواة سياق المقاطعة لمعالجة المؤقت، لكنه يحرر قفله مؤقتًا (unlock_task_sighand) لتجنب الجمود.
في الوقت نفسه تمامًا على نواة أخرى، تجمع العملية A العملية B الخارجة، فتنظف معالج إشارتها (sighand = NULL) وتزيل تجزئة PID الخاص بها.
يستدعي خيط آخر في B حذف المؤقت (posix_cpu_timer_del). يحاول البحث عن المهمة عبر PID الخاص بها والتحقق من معالج إشارتها، لكنه يجدهما قد تم تنظيفهما بالفعل / NULL. وبتفسيره الخاطئ أن المهمة ميتة تمامًا ولا يمكن أن تنطلق أي مؤقتات، يفترض أنه آمن ويحرر المؤقت من الذاكرة.
في هذه الأثناء، يستأنف معالج مقاطعة المؤقت على النواة الأولى لإطلاق المؤقت المنتهي. ولأن المؤقت قد تم تحريره للتو في الخطوة 4، فإن الوصول إليه يسبب استخدامًا بعد التحرير ويُسقط النواة.
poc_gdb_script.py)لأن منفذ GDB الخاص بـ QEMU لا يدعم set non-stop on (إيقاف vCPU واحد يوقف جميع وحدات vCPU)، لا يمكن تحقيق التزامن القياسي متعدد الخيوط عبر نقاط التوقف العادية.
يحل هذا المستودع المشكلة عبر ترقيع التعليمات في الذاكرة:
المرحلة 1 (حاجز CPU):
exit_notify (CPU 2)kernel_wait4 (CPU 0)__arm64_sys_timer_delete (CPU 1)handle_posix_cpu_timers (CPU 2)$pc الخاص به باستخدام تعليمة ARM64 ذاتية التفرع 0x14000000 (b . حلقة لا نهائية) ويستأنف التنفيذ.المرحلة 2 (التنسيق التسلسلي):
set scheduler-locking on) ويقدم كل vCPU للأمام بالتسلسل:
handle_posix_cpu_timers إلى ما بعد unlock_task_sighand().kernel_wait4 إلى ما بعد .نزّل أو استنسخ شجرة مصدر Android Common Kernel عند الالتزام 1bf1aa362e6b9573a310fcd14f35bc875b42ba83:
# Option A: Download tarball directly
curl -LO https://android.googlesource.com/kernel/common/+archive/1bf1aa362e6b9573a310fcd14f35bc875b42ba83.tar.gz
mkdir -p kernel-cve && tar -xzf 1bf1aa362e6b9573a310fcd14f35bc875b42ba83.tar.gz -C kernel-cve
cd kernel-cve
# Option B: Clone repository
git clone https://android.googlesource.com/kernel/common
cd common
git checkout 1bf1aa362e6b9573a310fcd14f35bc875b42ba83
run_posix_cpu_timers()افتح kernel/time/posix-cpu-timers.c، وحدد الدالة run_posix_cpu_timers() (حوالي السطر 1435–1448)، وعلّق أسطر الترقيع:
void run_posix_cpu_timers(void)
{
struct task_struct *tsk = current;
lockdep_assert_irqs_disabled();
/*
* Ensure that release_task(tsk) can't happen while
* handle_posix_cpu_timers() is running. Otherwise, a concurrent
* posix_cpu_timer_del() may fail to lock_task_sighand(tsk) and
* miss timer->it.cpu.firing != 0.
*/
// if (tsk->exit_state)
// return;
CONFIG_POSIX_CPU_TIMERS_TASK_WORKملاحظة: عندما يكون
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y، تُنفَّذ مؤقتات CPU من سياقtask_workبدلًا من مقاطعة المؤقت، متجاوزةً حالة التسابق هذه. لذلك، يجب تعطيله لإعادة إنتاج الثغرة.
لأن CONFIG_POSIX_CPU_TIMERS_TASK_WORK يفتقر إلى سلسلة مطالبة في Kconfig الأساسي، فإنه يُعيّن افتراضيًا إلى y ولا يمكن تبديله مباشرة في menuconfig. يمكنك إظهاره كما يلي:
kernel/time/Kconfig (حوالي السطر 56)، أضف سلسلة مطالبة وغيّر الافتراضي:
config POSIX_CPU_TIMERS_TASK_WORK
bool "POSIX CPU timers task work"
default n
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make defconfig
scripts/config --disable POSIX_CPU_TIMERS_TASK_WORK
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make olddefconfig
.config:
grep POSIX_CPU_TIMERS_TASK_WORK .config
# Expected output: # CONFIG_POSIX_CPU_TIMERS_TASK_WORK is not set
ترجم صورة نواة ARM64:
time ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc) Image
ترجم poc.c ترجمة متقاطعة:
aarch64-linux-gnu-gcc -ggdb3 ./poc.c -o poc
شغّل جهازك الافتراضي QEMU بأربع وحدات vCPU (-smp 4) وفعّل منفذ GDB (علامة -s، المنفذ 1234):
qemu-system-aarch64 \
-M virt \
-cpu cortex-a57 \
-smp 4 \
-m 2G \
-kernel arch/arm64/boot/Image \
-append "console=ttyAMA0 root=/dev/vda oops=panic panic_on_warn=1" \
... \
-s
من طرفية المضيف، أرفق GDB بـ QEMU وحمّل سكربت التنسيق:
gdb-multiarch vmlinux
pwndbg> target remote :1234
pwndbg> source poc_gdb_script.py
pwndbg> continue
داخل صدفة ضيف QEMU، شغّل الملف التنفيذي المترجم:
./poc
[!TIP] التوقيت واستكشاف الأخطاء:
إذا انطلق المؤقت قبل الأوان قبل أن يصل الخيط الهدف إلى حالة الزومبي، سيسجل GDB:[!] ERROR: handle_posix_cpu_timers fired before exit_state == EXIT_ZOMBIE
- الخيار 1: ببساطة أعد تشغيل
./pocوأعد تحميل سكربت GDB عدة مرات.- الخيار 2: زد
TIMER_FIRE_MSفيpoc.c(مثلًا، من#define TIMER_FIRE_MS 10إلى20)، وأعد ترجمةpoc.c، وشغّل مرة أخرى. يمنح هذا الخيط وقتًا إضافيًا للوصول إلىexit_notify()والانتقال إلىEXIT_ZOMBIEقبل انتهاء المؤقت.
https://github.com/user-attachments/assets/11481b5c-25f8-46c3-be3a-7b79a06a4948
tsk->sighand = NULLtimer_delete لاستدعاء release_posix_timer() (تحرير sigq).