ペンリジェント・ヘッダー

Clockwork Root: Anatomy of the CVE-2025-38352 Linux Kernel Race Condition

It is Christmas 2025, and while security teams are hoping for a silent night, the Linux Kernel mailing lists are anything but quiet. Google’s Threat Analysis Group (TAG) has dropped a lump of coal in the stocking of every Android vendor: CVE-2025-38352.

This is not a garden-variety memory corruption bug. It is a sophisticated, timing-dependent Race Condition residing deep within the POSIX CPU timer subsystem of the Linux Kernel. With a CVSS score of 7.4, it might seem manageable at first glance, but do not be deceived by the score. In the hands of commercial spyware vendors, this vulnerability has already been weaponized to achieve reliable ローカル特権の昇格 (LPE) on fully patched Android devices, bypassing modern mitigations like KASLR and PAN.

For the elite security engineer, CVE-2025-38352 represents the pinnacle of “Race-to-Use-After-Free” exploitation. It exploits the microscopic gap between a process entering a “Zombie” state and the kernel cleaning up its timers. This article abandons high-level summaries to perform a surgical dissection of kernel/time/posix-cpu-timers.c, the exploitation physics, and why AI-driven temporal analysis is the only way to catch what human auditors missed.

The Kernel’s Fatal Flaw: A Broken Spinlock Dance

To understand CVE-2025-38352, we must look at how the Linux Kernel handles concurrency during process termination. The vulnerability stems from an atomicity violation in how the kernel processes expired CPU timers while a thread is simultaneously attempting to delete them.

脆弱なコードパス

The flaw resides in the handle_posix_cpu_timers() function. This function is responsible for iterating over a list of active timers and firing those that have expired. Critically, to perform this iteration, it must hold the sighand->siglock.

However, prior to the patch, the logic contained a fatal sequence:

  1. Lock Acquisition: The kernel acquires sighand->siglock to traverse the timer list.
  2. The Drop: To handle a specific expiration capability (specifically CPUCLOCK_PERTHREAD), the code briefly drops the lock to perform a check or re-queue operation.
  3. The Use: It re-acquires the lock and proceeds to dereference the timer object.

The Race Window

It is inside this microscopic window—where the lock is dropped—that the attacker strikes.

A concurrent thread (Thread B) issues a timer_delete() syscall. Because the lock is free, Thread B successfully acquires it, removes the timer from the list, and frees the memory via kfree_rcu or slab deallocation.

When Thread A (the victim context) re-acquires the lock, it holds a pointer to a posix_cputimer struct that technically no longer exists. It proceeds to write to this memory (e.g., updating the expiration time), triggering a ユーズアフターフリー(UAF) write.

CVE-2025-38352

Weaponizing the Zombie: The Exploit Primitives

Exploiting a kernel race condition is often compared to winning the lottery. However, advanced exploit developers do not play dice; they rig the game. In the context of CVE-2025-38352, attackers rig the game using Zombie Processes.

1. Widening the Window (The “Zombification” Technique)

The standard race window might be only a few nanoseconds wide. To make exploitation reliable (90%+ success rate), attackers utilize the process exit state.

By spawning a child process and having it exit—but deliberately ない reaping it (via waitpid)—the process enters the EXIT_ZOMBIE state. In this state, the task structure remains in memory, but cleanup logic is pending. Attackers discovered that triggering timer operations on a Zombie process forces the kernel into a slower, more complex code path within posix_cpu_timer_del, artificially dilating the race window from nanoseconds to microseconds.

2. SLUB Feng Shui (Heap Spraying)

Once the UAF is triggered, the kernel writes data to a freed memory slot. If that slot is empty, the kernel crashes (DoS). To get Root, the attacker must replace the freed timer object with a payload.

Attackers leverage the SLUB allocator’s predictable behavior (Last-In, First-Out).

  1. Free: Trigger the race to free the timer struct.
  2. Spray: Immediately flood the kernel heap with user-controlled objects of the exact same size (e.g., using sendmsg ancillary data or key_serial objects).
  3. 汚職だ: The kernel, thinking it is updating the timer, writes to the attacker’s object. If the attacker sprayed a structure containing a function pointer (e.g., a tty_struct または file_operations), the kernel overwrites that pointer.
  4. 実行する: When the attacker invokes the sprayed object (e.g., closing the file), the kernel jumps to the overwritten address -> ROP Chain -> Root.

Beyond Syzkaller: Why Traditional Fuzzing Failed

CVE-2025-38352 went undetected by automated fuzzers like Google’s Syzkaller for years. Why?

Traditional coverage-guided fuzzing is probabilistic. It throws random syscalls at the kernel hoping to crash it.

  • It does not understand Timing.
  • It does not understand State Dependencies (e.g., “Thread A must be exiting while Thread B deletes a timer”).

The statistical probability of a blind fuzzer hitting this specific race condition, with the process in the exact ZOMBIE state, is astronomically low.

CVE-2025-38352

The AI Solution: Penligent’s Temporal Analysis

This failure of traditional tools highlights the necessity of AI-Driven Logic Analysis. This is where ペンリジェント changes the paradigm from “Fuzzing” to “Reasoning.”

Penligent utilizes a specialized Timing-Aware AI Agent designed for concurrency bug hunting:

1. Concurrency Pattern Recognition

Instead of random inputs, Penligent’s model analyzes the Kernel Source AST (Abstract Syntax Tree). It identifies “Dangerous Pairs”—syscalls that modify the same shared resource (in this case, posix_cputimer) but follow different locking paths. It flagged timer_delete そして handle_posix_cpu_timers as a high-probability collision target.

2. Race Window Dilation via AI

Penligent does not just execute syscalls; it orchestrates them. Recognizing the need to widen the race window, the AI automatically inferred the EXIT_ZOMBIE technique by analyzing previous “Ref-Count” vulnerability reports. It generated a Proof-of-Concept that programmatically stalled the CPU (using sched_yield or extensive memory barriers) to guarantee the collision.

For the security engineer, this means Penligent moves beyond reporting “potential bugs” to delivering verified, weaponized exploits that demonstrate the true risk profile of the code.

Remediation and Blue Team Detection

The fix, merged into the Linux Kernel in late 2025, involves a logic check rather than just a lock.

The Fix:

In run_posix_cpu_timers(), the kernel now explicitly checks if (tsk->exit_state). If the task is already dead or dying, it aborts the timer processing immediately. This effectively removes the “Zombie” variable from the equation.

Detection Strategies (EDR/Syslog):

Blue Teams should look for the following Indicators of Compromise (IoC) on Linux/Android servers:

  • High-Frequency Timer Churn: A process rapidly creating and deleting thousands of POSIX timers per second.
  • Zombie Floods: An unusual accumulation of Z state processes that are quickly spawned and not reaped.
  • Kernel Taint: dmesg logs showing “General Protection Faults” or “Slab corruption” in kmalloc-192 (or the specific slab size for timers on your arch).

結論

CVE-2025-38352 serves as a festive reminder that legacy code is a minefield. The POSIX timer code was written decades ago, yet it contained a latent flaw that required the complex memory landscape of 2025 to weaponize.

For the hard-core security engineer, the lesson is clear: The future of vulnerability research isn’t about finding simple buffer overflows. It is about understanding the fourth dimension of code—時間. As long as kernels employ complex locking mechanisms, race conditions will remain the “Crown Jewels” of exploitation.

信頼できるリファレンス

記事を共有する
関連記事