
CVE-2025-38352 को ट्रिगर करने में सहायक PoC और GDB स्क्रिप्ट
CVE-2025-38352 के लिए एक पुनरुत्पादनीय Proof-of-Concept (PoC) और स्वचालित GDB ऑर्केस्ट्रेशन स्क्रिप्ट, जो Linux kernel के POSIX CPU timer सबसिस्टम (kernel/time/posix-cpu-timers.c) में एक Time-of-Check to Time-of-Use (TOCTOU) रेस कंडीशन है जो Use-After-Free (UAF) की ओर ले जाती है।
अस्वीकरण: यह प्रोजेक्ट केवल शैक्षिक, रक्षात्मक और सुरक्षा अनुसंधान उद्देश्यों के लिए है। सभी परीक्षण और पुनरुत्पादन एक पृथक ARM64 QEMU वर्चुअल मशीन में किए गए थे।
प्रोसेस A चाइल्ड प्रोसेस B बनाता है।
प्रोसेस B एक CPU timer बनाता है और बाहर निकलना शुरू करता है, ज़ॉम्बी स्थिति में प्रवेश करता है। जैसे ही B बाहर निकल रहा होता है, उसके CPU कोर पर एक timer interrupt आता है। kernel timer को प्रोसेस करने के लिए interrupt context में प्रवेश करता है, लेकिन डेडलॉक से बचने के लिए अस्थायी रूप से अपना लॉक (unlock_task_sighand) छोड़ देता है।
ठीक उसी समय दूसरे कोर पर, प्रोसेस A बाहर निकल रहे B को reap करता है, उसके signal handler (sighand = NULL) को साफ़ करता है और उसके PID को unhashing करता है।
B में एक अन्य थ्रेड timer delete (posix_cpu_timer_del) को कॉल करता है। यह अपने PID के माध्यम से टास्क को खोजने और उसके signal handler की जाँच करने का प्रयास करता है, लेकिन उन्हें पहले से ही साफ़ किया हुआ / NULL पाता है। यह गलत समझते हुए कि टास्क पूरी तरह से मृत है और कोई timer संभवतः फायर नहीं हो सकता, यह मान लेता है कि यह सुरक्षित है और timer को मेमोरी से मुक्त कर देता है।
इस बीच, पहले कोर पर timer interrupt handler समाप्त हुए timer को फायर करने के लिए फिर से शुरू होता है। चूँकि timer अभी Step 4 में मुक्त किया गया था, उस तक पहुँचने से Use-After-Free होता है और kernel क्रैश हो जाता है।
poc_gdb_script.py)चूँकि QEMU का GDB stub set non-stop on का समर्थन नहीं करता (एक vCPU को रोकने से सभी vCPUs रुक जाते हैं), सामान्य मल्टी-थ्रेडेड सिंक्रोनाइज़ेशन सादे breakpoints के माध्यम से प्राप्त नहीं किया जा सकता।
यह रिपॉज़िटरी In-Memory Instruction Patching के माध्यम से समस्या का समाधान करती है:
Stage 1 (CPU Barrier):
exit_notify (CPU 2)kernel_wait4 (CPU 0)__arm64_sys_timer_delete (CPU 1)handle_posix_cpu_timers (CPU 2)$pc को ARM64 self-branch opcode 0x14000000 (b . infinite loop) से patch करता है और निष्पादन फिर से शुरू करता है।Stage 2 (Sequential Orchestration):
set scheduler-locking on) और प्रत्येक vCPU को क्रमिक रूप से आगे बढ़ाता है:
handle_posix_cpu_timers को unlock_task_sighand() से आगे बढ़ाएँ।commit 1bf1aa362e6b9573a310fcd14f35bc875b42ba83 पर Android Common Kernel स्रोत ट्री डाउनलोड या क्लोन करें:
# 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() में पैच को revert करेंkernel/time/posix-cpu-timers.c खोलें, फ़ंक्शन run_posix_cpu_timers() (लगभग पंक्ति 1435–1448) का पता लगाएँ, और पैच पंक्तियों को comment out करें:
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 timers timer IRQ के बजायtask_workcontext से निष्पादित होते हैं, जिससे यह रेस कंडीशन बायपास हो जाती है। इसलिए, भेद्यता को पुनरुत्पादित करने के लिए इसे अक्षम किया जाना चाहिए।
चूँकि upstream Kconfig में CONFIG_POSIX_CPU_TIMERS_TASK_WORK में prompt string नहीं है, यह डिफ़ॉल्ट रूप से y होता है और menuconfig में सीधे toggle नहीं किया जा सकता। आप इसे निम्नानुसार उजागर कर सकते हैं:
kernel/time/Kconfig में (लगभग पंक्ति 56), एक prompt string जोड़ें और default बदलें:
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 kernel image संकलित करें:
time ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc) Image
poc.c को cross-compile करें:
aarch64-linux-gnu-gcc -ggdb3 ./poc.c -o poc
अपनी QEMU वर्चुअल मशीन को 4 vCPUs (-smp 4) के साथ लॉन्च करें और GDB stub सक्षम करें (-s flag, port 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
अपने host terminal से, GDB को QEMU से अटैच करें और orchestration स्क्रिप्ट लोड करें:
gdb-multiarch vmlinux
pwndbg> target remote :1234
pwndbg> source poc_gdb_script.py
pwndbg> continue
QEMU guest shell के अंदर, संकलित बाइनरी चलाएँ:
./poc
[!TIP] Timing और Troubleshooting:
यदि लक्ष्य थ्रेड के ज़ॉम्बी स्थिति में पहुँचने से पहले timer समय से पहले फायर हो जाता है, तो GDB लॉग करेगा:[!] ERROR: handle_posix_cpu_timers fired before exit_state == EXIT_ZOMBIE
- विकल्प 1: बस
./pocको फिर से चलाएँ और GDB स्क्रिप्ट को कुछ बार source करें।- विकल्प 2:
poc.cमेंTIMER_FIRE_MSबढ़ाएँ (उदाहरण के लिए,#define TIMER_FIRE_MS 10से20तक),poc.cको पुनः संकलित करें, और फिर से चलाएँ। यह थ्रेड को timer समाप्त होने से पहलेexit_notify()तक पहुँचने औरEXIT_ZOMBIEमें संक्रमण करने के लिए अतिरिक्त समय देता है।
https://github.com/user-attachments/assets/11481b5c-25f8-46c3-be3a-7b79a06a4948
kernel_wait4 को tsk->sighand = NULL से आगे बढ़ाएँ।timer_delete को release_posix_timer() (जो sigq को मुक्त करता है) कॉल करने के लिए आगे बढ़ाएँ।