
PoC- und GDB-Skript unterstützt beim Auslösen von CVE-2025-38352
Ein reproduzierbares Proof-of-Concept (PoC) und automatisiertes GDB-Orchestrierungsskript für CVE-2025-38352, eine Time-of-Check to Time-of-Use (TOCTOU)-Race-Condition im POSIX-CPU-Timer-Subsystem des Linux-Kernels (kernel/time/posix-cpu-timers.c), die zu einem Use-After-Free (UAF) führt.
Haftungsausschluss: Dieses Projekt dient ausschließlich Bildungs-, Verteidigungs- und Sicherheitsforschungszwecken. Alle Tests und Reproduktionen wurden in einer isolierten ARM64-QEMU-VM durchgeführt.
Prozess A erzeugt Kindprozess B.
Prozess B erstellt einen CPU-Timer und beginnt mit dem Beenden, wobei er in den Zombie-Zustand übergeht. Genau während B beendet wird, trifft ein Timer-Interrupt auf seinem CPU-Kern ein. Der Kernel wechselt in den Interrupt-Kontext, um den Timer zu verarbeiten, gibt jedoch vorübergehend seinen Lock (unlock_task_sighand) frei, um Deadlocks zu vermeiden.
Zur exakt gleichen Zeit auf einem anderen Kern reapt Prozess A das beendete B, räumt dessen Signal-Handler auf (sighand = NULL) und entfernt dessen PID aus der Hash-Tabelle.
Ein weiterer Thread in B ruft das Löschen des Timers auf (posix_cpu_timer_del). Er versucht, die Task über ihre PID nachzuschlagen und ihren Signal-Handler zu prüfen, findet diese jedoch bereits aufgeräumt / NULL. In der Fehlannahme, dass die Task vollständig tot ist und keine Timer mehr feuern könnten, geht er davon aus, dass es sicher ist, und gibt den Timer aus dem Speicher frei.
Währenddessen nimmt der Timer-Interrupt-Handler auf dem ersten Kern seine Arbeit wieder auf, um den abgelaufenen Timer zu feuern. Da der Timer gerade in Schritt 4 freigegeben wurde, löst der Zugriff darauf einen Use-After-Free aus und bringt den Kernel zum Absturz.
poc_gdb_script.py)Da QEMUs GDB-Stub set non-stop on nicht unterstützt (das Anhalten einer vCPU hält alle vCPUs an), kann eine standardmäßige Multithread-Synchronisation nicht über einfache Breakpoints erreicht werden.
Dieses Repository löst das Problem über In-Memory Instruction Patching:
Phase 1 (CPU-Barriere):
exit_notify (CPU 2)kernel_wait4 (CPU 0)__arm64_sys_timer_delete (CPU 1)handle_posix_cpu_timers (CPU 2)$pc mit dem ARM64-Self-Branch-Opcode 0x14000000 (b . Endlosschleife) und setzt die Ausführung fort.Phase 2 (Sequenzielle Orchestrierung):
set scheduler-locking on) und schreitet mit jeder vCPU sequenziell voran:
handle_posix_cpu_timers über unlock_task_sighand() hinaus vorrücken.Laden Sie den Android Common Kernel-Quellbaum am Commit 1bf1aa362e6b9573a310fcd14f35bc875b42ba83 herunter oder klonen Sie ihn:
# 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() rückgängig machenÖffnen Sie kernel/time/posix-cpu-timers.c, suchen Sie die Funktion run_posix_cpu_timers() (etwa Zeile 1435–1448) und kommentieren Sie die Patch-Zeilen aus:
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 deaktivierenHinweis: Wenn
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=ygesetzt ist, werden CPU-Timer aus demtask_work-Kontext statt aus dem Timer-IRQ heraus ausgeführt, wodurch diese Race-Condition umgangen wird. Daher muss die Option deaktiviert werden, um die Schwachstelle zu reproduzieren.
Da CONFIG_POSIX_CPU_TIMERS_TASK_WORK im Upstream-Kconfig keinen Prompt-String besitzt, ist der Standardwert y und die Option kann nicht direkt in menuconfig umgeschaltet werden. Sie können sie wie folgt sichtbar machen:
kernel/time/Kconfig (etwa Zeile 56) einen Prompt-String hinzu und ändern Sie den Standardwert:
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 deaktiviert ist:
grep POSIX_CPU_TIMERS_TASK_WORK .config
# Expected output: # CONFIG_POSIX_CPU_TIMERS_TASK_WORK is not set
Kompilieren Sie das ARM64-Kernel-Image:
time ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc) Image
Cross-kompilieren Sie poc.c:
aarch64-linux-gnu-gcc -ggdb3 ./poc.c -o poc
Starten Sie Ihre QEMU-VM mit 4 vCPUs (-smp 4) und aktivieren Sie den 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
Hängen Sie von Ihrem Host-Terminal aus GDB an QEMU an und laden Sie das Orchestrierungsskript:
gdb-multiarch vmlinux
pwndbg> target remote :1234
pwndbg> source poc_gdb_script.py
pwndbg> continue
Führen Sie im QEMU-Gast-Shell das kompilierte Binary aus:
./poc
[!TIP] Timing & Fehlerbehebung:
Wenn der Timer vorzeitig feuert, bevor der Ziel-Thread den Zombie-Zustand erreicht hat, protokolliert GDB:[!] ERROR: handle_posix_cpu_timers fired before exit_state == EXIT_ZOMBIE
- Option 1: Führen Sie einfach
./pocerneut aus und sourcen Sie das GDB-Skript ein paar Mal.- Option 2: Erhöhen Sie
TIMER_FIRE_MSinpoc.c(z. B. von#define TIMER_FIRE_MS 10auf20), kompilieren Siepoc.cneu und führen Sie es erneut aus. Dies gibt dem Thread zusätzliche Zeit,exit_notify()zu erreichen und inEXIT_ZOMBIEüberzugehen, bevor der Timer abläuft.
https://github.com/user-attachments/assets/11481b5c-25f8-46c3-be3a-7b79a06a4948
kernel_wait4 über tsk->sighand = NULL hinaus vorrücken.timer_delete vorrücken, um release_posix_timer() aufzurufen (gibt sigq frei).