CVE-2025-38352: In-the-Wild Android Kernel Vulnerability Analysis With PoC



CVE-2025-38352 is a race condition use-after-free vulnerability in the POSIX CPU timers component of the Linux kernel. Security researchers reported that the flaw had been actively exploited in the wild, though the attacks appeared to be limited and highly targeted rather than widespread.

The vulnerability allows attackers to exploit improper memory handling during timer operations, potentially leading to kernel memory corruption. Given the kernel-level impact, successful exploitation could enable elevated privileges or system compromise, making it particularly concerning for Android devices that rely on affected kernel versions.

A detailed analysis of this vulnerability was previously published by @streypaws, whose blog provides a clear explanation of how POSIX CPU timers operate and the specific conditions required to trigger this flaw. Their work offers valuable background and technical context for understanding the issue.

However, the original analysis does not include a working proof-of-concept (PoC) that demonstrates the vulnerability in action. To bridge that gap, I spent time independently researching the flaw and developing my own PoC implementation.

This post offers insight into my approach to vulnerability analysis and PoC development, highlighting how hands-on experimentation can significantly deepen technical understanding. It also illustrates the learning value of breaking down complex kernel issues through practical testing.

Table of Contents

Proof of Concept Overview

Patch Commit Reference

Testing Environment (TL;DR)

Kernel Version

CONFIG_POSIX_CPU_TIMERS_TASK_WORK

QEMU Configuration

Vulnerability Summary

PoC Design Strategy

Building a Minimal POSIX CPU Timer PoC

Creating a Zombie Process

Cleaning Up a Zombie Process

Controlled Zombie Reaping

Implementing the PoC

Extending the Race Window

Kernel Patch to Increase Race Reliability

Triggering the Race Condition

Custom Wait-Time Logic

Timer Initialization

Reaping the Timer Thread and Removing the Timer

PoC Validation

KASAN Crash Output

Non-KASAN Crash Output

Notes on CONFIG_POSIX_CPU_TIMERS_TASK_WORK

Exploitation Discussion

Conclusion

Final Proof of Concept


Patch Commit Details

The kernel patch that addresses CVE-2025-38352 is available in the Linux stable tree. The commit resolves the race condition in the POSIX CPU timers implementation that could lead to a use-after-free scenario.

Patch commit reference:
f90fff1e152dedf52b932240ebbd670d83330eca

 

Testing Environment

Kernel Version

The proof of concept was developed and tested against Linux kernel 6.12.33 (LTS), which was the most recent long-term support release still affected by CVE-2025-38352 at the time of testing.

CONFIG_POSIX_CPU_TIMERS_TASK_WORK

The patch commit notes that the vulnerability cannot be triggered when CONFIG_POSIX_CPU_TIMERS_TASK_WORK is enabled. This option is normally enabled by default and not exposed to users, as it is defined internally within the kernel configuration.

Because this flag is enabled on both x86 and ARM64 architectures, the vulnerability is effectively exploitable only on 32-bit Android devices. This restriction aligns with reports describing the issue as being exploited in a limited and targeted manner in the wild.

To study the vulnerability, the configuration was modified to make CONFIG_POSIX_CPU_TIMERS_TASK_WORK user-toggleable via menuconfig. Aside from this single change, the kernelCTF LTS configuration was used as a baseline.

QEMU Setup

Since the issue is a race condition, testing required a multi-CPU environment. A QEMU virtual machine configured with four CPU cores was used to reliably trigger the race window.


Vulnerability Recap

CVE-2025-38352 occurs in the Linux kernel’s handling of POSIX CPU timers. On every per-CPU scheduler tick, the kernel evaluates whether CPU timers are ready to fire. The flaw arises because this logic can still execute even after a task has transitioned into the EXIT_ZOMBIE state.

During timer processing, firing timers are collected into a local list while holding the task’s signal handler lock. Once the lock is released, the kernel iterates over that list and executes the timers. If the task becomes a zombie during this window, a second thread can reclaim the task and delete the timer, freeing its memory while it is still being referenced—resulting in a use-after-free condition.

This race window exists between dropping the signal handler lock and firing the collected timers, allowing the timer object to be freed via timer_delete() while still in use.


Planning the Proof of Concept

To reliably trigger the bug, the PoC needed to combine three components:

  1. A POSIX CPU timer that fires during task exit

  2. A zombie task whose signal handler remains valid long enough for timer collection

  3. A parent process capable of precisely controlling when the zombie task is reaped

The approach involved creating a non-main thread that exits into a zombie state while being ptraced, allowing the parent process to delay reaping until the race window is reached.


Extending the Race Window

To improve reliability during testing, a temporary kernel modification was introduced to delay execution inside the timer-handling path. This artificially widened the race window, making it easier to observe the vulnerability. While not required for exploitation, this change significantly reduced trial-and-error during development.


Triggering the Race Condition

The race is triggered by carefully aligning the timer expiration with the task’s transition into the zombie state. The timer must fire after exit_notify() marks the task as a zombie, but before the task is fully cleaned up.

This required fine-tuning the CPU time consumed by the thread prior to exit. In the test environment, a delay of approximately 250 microseconds proved effective, though the optimal value may vary depending on system performance.


Observing the Crash

KASAN Enabled

With KASAN enabled, the kernel reports a clear slab use-after-free, confirming that the timer object is accessed after being freed.

KASAN Disabled

Without KASAN, the issue manifests as kernel warnings during signal delivery, still indicating memory corruption stemming from invalid timer access.


Notes on CONFIG_POSIX_CPU_TIMERS_TASK_WORK

Although earlier research suggested the vulnerability could be triggered with this option enabled, testing showed otherwise. The task-work mechanism prevents timer processing after exit, effectively closing the race window. This explains why the vulnerability is limited to configurations where this feature is disabled—primarily older or 32-bit Android builds.


Exploitation Considerations

While a reliable exploitation primitive is demonstrated, full exploitation would require overcoming several challenges:

  • Timers are allocated from a dedicated slab cache

  • Cross-cache reuse may be required

  • The race occurs in scheduler interrupt context, limiting timing flexibility

Despite these challenges, the presence of in-the-wild exploitation indicates the vulnerability is exploitable with sufficient engineering effort.


Conclusion

Developing a proof of concept for CVE-2025-38352 highlights the value of hands-on vulnerability research. Beyond confirming exploitability, the process deepens understanding of POSIX CPU timers, kernel task lifecycles, and signal handling internals.

Carefully breaking down complex kernel behavior into testable components remains one of the most effective ways to learn—and to validate real-world security impact.

Testing Environment

Kernel Version

The proof of concept was developed and tested against Linux kernel 6.12.33 (LTS), which was the most recent long-term support release still affected by CVE-2025-38352 at the time of testing.

CONFIG_POSIX_CPU_TIMERS_TASK_WORK

The patch commit notes that the vulnerability cannot be triggered when CONFIG_POSIX_CPU_TIMERS_TASK_WORK is enabled. This option is normally enabled by default and not exposed to users, as it is defined internally within the kernel configuration.

Because this flag is enabled on both x86 and ARM64 architectures, the vulnerability is effectively exploitable only on 32-bit Android devices. This restriction aligns with reports describing the issue as being exploited in a limited and targeted manner in the wild.

To study the vulnerability, the configuration was modified to make CONFIG_POSIX_CPU_TIMERS_TASK_WORK user-toggleable via menuconfig. Aside from this single change, the kernelCTF LTS configuration was used as a baseline.

QEMU Setup

Since the issue is a race condition, testing required a multi-CPU environment. A QEMU virtual machine configured with four CPU cores was used to reliably trigger the race window.


Vulnerability Recap

CVE-2025-38352 occurs in the Linux kernel’s handling of POSIX CPU timers. On every per-CPU scheduler tick, the kernel evaluates whether CPU timers are ready to fire. The flaw arises because this logic can still execute even after a task has transitioned into the EXIT_ZOMBIE state.

During timer processing, firing timers are collected into a local list while holding the task’s signal handler lock. Once the lock is released, the kernel iterates over that list and executes the timers. If the task becomes a zombie during this window, a second thread can reclaim the task and delete the timer, freeing its memory while it is still being referenced—resulting in a use-after-free condition.

This race window exists between dropping the signal handler lock and firing the collected timers, allowing the timer object to be freed via timer_delete() while still in use.


Planning the Proof of Concept

To reliably trigger the bug, the PoC needed to combine three components:

  1. A POSIX CPU timer that fires during task exit

  2. A zombie task whose signal handler remains valid long enough for timer collection

  3. A parent process capable of precisely controlling when the zombie task is reaped

The approach involved creating a non-main thread that exits into a zombie state while being ptraced, allowing the parent process to delay reaping until the race window is reached.


Extending the Race Window

To improve reliability during testing, a temporary kernel modification was introduced to delay execution inside the timer-handling path. This artificially widened the race window, making it easier to observe the vulnerability. While not required for exploitation, this change significantly reduced trial-and-error during development.


Triggering the Race Condition

The race is triggered by carefully aligning the timer expiration with the task’s transition into the zombie state. The timer must fire after exit_notify() marks the task as a zombie, but before the task is fully cleaned up.

This required fine-tuning the CPU time consumed by the thread prior to exit. In the test environment, a delay of approximately 250 microseconds proved effective, though the optimal value may vary depending on system performance.


Observing the Crash

KASAN Enabled

With KASAN enabled, the kernel reports a clear slab use-after-free, confirming that the timer object is accessed after being freed.

KASAN Disabled

Without KASAN, the issue manifests as kernel warnings during signal delivery, still indicating memory corruption stemming from invalid timer access.


Notes on CONFIG_POSIX_CPU_TIMERS_TASK_WORK

Although earlier research suggested the vulnerability could be triggered with this option enabled, testing showed otherwise. The task-work mechanism prevents timer processing after exit, effectively closing the race window. This explains why the vulnerability is limited to configurations where this feature is disabled—primarily older or 32-bit Android builds.


Exploitation Considerations

While a reliable exploitation primitive is demonstrated, full exploitation would require overcoming several challenges:

  • Timers are allocated from a dedicated slab cache

  • Cross-cache reuse may be required

  • The race occurs in scheduler interrupt context, limiting timing flexibility

Despite these challenges, the presence of in-the-wild exploitation indicates the vulnerability is exploitable with sufficient engineering effort.


Conclusion

Developing a proof of concept for CVE-2025-38352 highlights the value of hands-on vulnerability research. Beyond confirming exploitability, the process deepens understanding of POSIX CPU timers, kernel task lifecycles, and signal handling internals.

Carefully breaking down complex kernel behavior into testable components remains one of the most effective ways to learn—and to validate real-world security impact.

Comments