
Android kernel exploit for CVE-2025-38352, previously exploited in-the-wild. Targets vulnerable x86_64 Linux kernels v5.10.x.
Chronomaly is a kernel exploit for the Android / Linux kernel using CVE-2025-38352. The exploit was written specifically for Linux kernel v5.10.157, but should work against all vulnerable v5.10.x kernels, as it does not require any specific kernel text offsets to work.
I covered the vulnerability in detail in a three-part blog post series, all the way from PoC to exploit:

This exploit has only been tested against an x86_64 Linux kernel v5.10.157 running in QEMU. I asked a friend to send me their Pixel 6a kernel config to base my kernel config off of, and these are the config options important for this exploit (I started from the kernelCTF config as a base):
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=nCONFIG_PREEMPT=y (Full Preemption, no RT)CONFIG_SLAB_MERGE_DEFAULT=nDEBUG_LIST=nBUG_ON_DATA_CORRUPTION=nLIST_HARDENED=nTo disable CONFIG_POSIX_CPU_TIMERS_TASK_WORK, you can follow the steps laid out in my first blog post here.
Refer to the qemu.sh file for my QEMU run script. I used 4 cores and 3 GB RAM for testing.
Since the exploit depends on CPU timers, there are two parameters you may need to change to adapt it to your environment.
CPU_USAGE_THRESHOLDThis parameter is used when consuming CPU time to fire the timers inside the race_func(). It must be set such that:
CPU_USAGE_THRESHOLD is too high, as the timers are firing before the race_func() thread can exit).To determine whether the timers are firing or not, insert a printf() statement in the SIGUSR1 polling code in free_func(). If you see the message print out, that means the timers fired.
If set correctly, you'll start seeing the "Parent raced too late / too early" messages in the terminal.
PARENT_SETTIME_DELAY_USPARENT_SETTIME_DELAY_US. This parameter is used by the parent process to hit the 2nd race window inside send_sigqueue() at the same time as the child process. Run the exploit, observe, and modify it as follows:
Ideally, you want to see both "raced too late" and "raced too early" being printed out, and the exploit will work within 1 minute. If you only see one occurring more than the other, adjust accordingly.
In my cross-cache implementation, I assumed that the kernel is not too busy, and that there haven't been many struct sigqueue allocations. I added a comment in sigqueue_crosscache_preallocs() that explains what you would need to do improve this.
If the kernel is really busy, or there are already some struct sigqueue slab pages on the per-cpu / per-node partial list, then the current cross-cache implementation in exploit.c will fail, and the uaf_sigqueue / realloc_sigqueue won't be re-allocated as a pipe buffer data page.
I purposely chose not to make the cross-cache work in a busy kernel, so that the exploit doesn't get misused :)
If you have any questions, please contact me via X / Twitter!