
PoC y script de GDB que ayudan a desencadenar CVE-2025-38352
Un Proof-of-Concept (PoC) reproducible y un script de orquestación automatizada de GDB para CVE-2025-38352, una condición de carrera Time-of-Check to Time-of-Use (TOCTOU) en el subsistema de temporizadores POSIX de CPU del kernel de Linux (kernel/time/posix-cpu-timers.c) que conduce a un Use-After-Free (UAF).
Descargo de responsabilidad: Este proyecto es solo para fines educativos, defensivos y de investigación de seguridad. Todas las pruebas y reproducciones se realizaron en una máquina virtual ARM64 QEMU aislada.
El proceso A crea el proceso hijo B.
El proceso B crea un temporizador de CPU y comienza a salir, entrando en el estado zombie. Justo cuando B está saliendo, llega una interrupción del temporizador en su núcleo de CPU. El kernel entra en contexto de interrupción para procesar el temporizador, pero libera temporalmente su bloqueo (unlock_task_sighand) para evitar interbloqueos.
Exactamente al mismo tiempo, en otro núcleo, el proceso A recolecta a B que está saliendo, limpiando su manejador de señales (sighand = NULL) y eliminando su PID de la tabla hash.
Otro hilo en B llama a la eliminación del temporizador (posix_cpu_timer_del). Intenta buscar la tarea a través de su PID y verificar su manejador de señales, pero los encuentra ya limpiados / NULL. Al interpretar erróneamente que la tarea está completamente muerta y que no podría haber temporizadores disparándose, asume que es seguro y libera el temporizador de la memoria.
Mientras tanto, el manejador de interrupción del temporizador en el primer núcleo se reanuda para disparar el temporizador expirado. Debido a que el temporizador acaba de ser liberado en el Paso 4, acceder a él provoca un Use-After-Free y bloquea el kernel.
poc_gdb_script.py)Debido a que el stub GDB de QEMU no admite set non-stop on (detener una vCPU detiene todas las vCPU), la sincronización multihilo estándar no se puede lograr mediante breakpoints simples.
Este repositorio resuelve el problema mediante Parcheo de Instrucciones en Memoria:
Etapa 1 (Barrera de CPU):
exit_notify (CPU 2)kernel_wait4 (CPU 0)__arm64_sys_timer_delete (CPU 1)handle_posix_cpu_timers (CPU 2)$pc con el opcode de auto-ramificación de ARM64 0x14000000 (bucle infinito b .) y reanuda la ejecución.Etapa 2 (Orquestación Secuencial):
set scheduler-locking on) y avanza cada vCPU secuencialmente:
handle_posix_cpu_timers más allá de unlock_task_sighand().Descargue o clone el árbol de código fuente de Android Common Kernel en el commit 1bf1aa362e6b9573a310fcd14f35bc875b42ba83:
# Opción A: Descargar el tarball directamente
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
# Opción B: Clonar el repositorio
git clone https://android.googlesource.com/kernel/common
cd common
git checkout 1bf1aa362e6b9573a310fcd14f35bc875b42ba83
run_posix_cpu_timers()Abra kernel/time/posix-cpu-timers.c, localice la función run_posix_cpu_timers() (alrededor de las líneas 1435–1448) y comente las líneas del parche:
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_WORKNota: Cuando
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y, los temporizadores de CPU se ejecutan desde el contexto detask_worken lugar de la IRQ del temporizador, evitando esta condición de carrera. Por lo tanto, debe deshabilitarse para reproducir la vulnerabilidad.
Debido a que CONFIG_POSIX_CPU_TIMERS_TASK_WORK carece de una cadena de prompt en el Kconfig upstream, su valor predeterminado es y y no se puede alternar directamente en menuconfig. Puede exponerlo de la siguiente manera:
kernel/time/Kconfig (alrededor de la línea 56), agregue una cadena de prompt y cambie el valor predeterminado:
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
# Salida esperada: # CONFIG_POSIX_CPU_TIMERS_TASK_WORK is not set
Compile la imagen del kernel ARM64:
time ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc) Image
Compile de forma cruzada poc.c:
aarch64-linux-gnu-gcc -ggdb3 ./poc.c -o poc
Inicie su máquina virtual QEMU con 4 vCPU (-smp 4) y habilite el stub GDB (bandera -s, puerto 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
Desde su terminal anfitrión, adjunte GDB a QEMU y cargue el script de orquestación:
gdb-multiarch vmlinux
pwndbg> target remote :1234
pwndbg> source poc_gdb_script.py
pwndbg> continue
Dentro del shell del invitado QEMU, ejecute el binario compilado:
./poc
[!TIP] Sincronización y solución de problemas:
Si el temporizador se dispara prematuramente antes de que el hilo objetivo haya alcanzado el estado zombie, GDB registrará:[!] ERROR: handle_posix_cpu_timers fired before exit_state == EXIT_ZOMBIE
- Opción 1: Simplemente vuelva a ejecutar
./pocy cargue el script GDB unas cuantas veces.- Opción 2: Aumente
TIMER_FIRE_MSenpoc.c(por ejemplo, de#define TIMER_FIRE_MS 10a20), recompilepoc.cy ejecute de nuevo. Esto otorga al hilo tiempo adicional para alcanzarexit_notify()y transicionar aEXIT_ZOMBIEantes de que expire el temporizador.
https://github.com/user-attachments/assets/11481b5c-25f8-46c3-be3a-7b79a06a4948
kernel_wait4tsk->sighand = NULLtimer_delete para llamar a release_posix_timer() (liberando sigq).