CVE-2026-64560
High · 7.8CVSS
7.8
EPSS
0.5%
Published
Jul 29, 2026
CISA due date
—
Cloudanix analysis
A person who can run a program on an affected Linux system may be able to crash the system or gain control of it, so the operating system kernel should be updated.
- Exploitation
- Local Privilege
- Attacker needs
- Local User
- Complexity
- Moderate
- Impact
- Privilege Gain
- Component
- OS kernel
- Class
- Use After Free
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
This is a Linux kernel use-after-free in POSIX CPU timer handling during a race between timer operations and exec() in a non-leader thread. A local user can trigger a condition where a POSIX CPU timer object is freed while its timerqueue node may still be reachable from task signal state; later timer expiration, rearm, add, or delete paths can dereference the freed object. The likely outcomes are kernel memory corruption, kernel panic/denial of service, or, with sufficient heap control, local privilege escalation to kernel-level privileges. The flaw requires local code execution with low privileges and no user interaction.
Why it matters to the business
Successful exploitation can let a local user or compromised workload take control of the underlying Linux host or crash it. This is especially important for multi-user systems, shared compute, CI/CD runners, container hosts, and systems that execute untrusted code because containers share the host kernel. The issue is not listed in CISA KEV, is not reported as ransomware-used, has very low EPSS, and has no indicated public exploit maturity, which lowers immediate mass-exploitation likelihood; however, Linux kernel local privilege-escalation bugs often become valuable post-compromise tools once technical details are available.
How an attack unfolds
An attacker first needs the ability to run code locally on a vulnerable Linux system, such as through a shell account, compromised application process, container escape precondition, or untrusted workload execution. The attacker runs a multithreaded program that creates and arms POSIX CPU timers targeted at a process/thread group, then repeatedly races timer deletion or timer setting paths against exec() from a non-leader thread. In the vulnerable race, the kernel may observe an old task leader whose sighand has already been cleared during de_thread()/switch_leader() handling and return without properly removing an armed timer. The timer object can then be freed while its timerqueue node remains reachable. When CPU timer processing later walks or manipulates that timerqueue, the kernel can access freed memory. A crude exploit may cause a kernel warning, oops, or panic; a more advanced exploit would attempt to shape kernel heap reuse so the stale timerqueue pointer corrupts controlled kernel objects and yields privilege escalation.
How to fix it
Apply a Linux kernel update from the operating system or appliance vendor that includes the upstream fix for the POSIX CPU timers non-leader exec() race. Because this is in kernel code, remediation normally requires installing the fixed kernel package and rebooting into it; live patching may be possible only if provided and explicitly covering this flaw. No exact fixed versions were provided in the input, so use vendor advisories for the relevant distribution, cloud image, appliance, or embedded platform to identify the corrected kernel build. Prioritize shared Linux systems, container hosts, build workers, developer jump boxes, HPC clusters, VDI/session hosts, and any system where untrusted or semi-trusted users can execute code. As temporary risk reduction, restrict local shell access, reduce untrusted workload execution, apply container isolation hardening, limit user namespaces where operationally feasible, use seccomp/AppArmor/SELinux policies to reduce unnecessary timer-related syscall exposure for high-risk sandboxed workloads, and ensure unprivileged users cannot load eBPF programs, kernel modules, or otherwise increase kernel attack surface. These mitigations reduce exploitability but do not replace patching.
How to confirm the fix worked
Confirm the running kernel, not just the installed package, is updated: compare uname -r and package metadata against the vendor advisory, then verify the system was rebooted or live-patched successfully. Review distribution changelogs for references to POSIX CPU timers, non-leader exec(), lock_task_sighand(), __exit_signal(), de_thread(), or use-after-free fixes. On container platforms, validate the node/host kernel version because patching container images alone does not remediate a host-kernel vulnerability. Exposure exists wherever local users, applications, containers, build jobs, or sandboxed workloads can execute code on a vulnerable kernel. Avoid using public proof-of-concept exploit code for validation on production systems; if testing is required, use vendor-provided regression tests or a controlled non-production host with crash collection enabled.
Typical attack path
- Obtain local low-privileged code execution on a Linux host or inside a workload that shares the host kernel.
- Run a program that creates and arms POSIX CPU timers or uses CPU-time nanosleep paths in a multithreaded process.
- Trigger repeated races between timer_delete()/timer_settime()-like operations and exec() from a non-leader thread so the process leader changes during timer cleanup.
- Cause the kernel to free a POSIX timer object while the timer remains logically queued in task signal/timerqueue state.
- Wait for timer expiration or another timerqueue operation to access the freed timer object.
- Leverage the resulting use-after-free for kernel crash/denial of service or attempt controlled kernel memory corruption for local privilege escalation.
- If privilege escalation succeeds, establish persistence, access host secrets, tamper with workloads, or pivot to other systems.
How to detect it
Exploitation is difficult to prove from ordinary logs because the vulnerable operations occur inside kernel race conditions and may leave no clean application-level trace. Start with kernel logs and crash artifacts: dmesg, journald kernel facility, /var/log/kern.log, /var/log/messages, netconsole, pstore/ramoops, vmcore, kdump, and KASAN/KFENCE reports if enabled. Look for use-after-free, general protection faults, kernel oopses, warnings, or panics with stack traces involving POSIX CPU timer functions, timerqueue functions, de_thread(), switch_leader(), or __exit_signal(). Correlate these events with local audit telemetry showing unusual high-volume use of timer_create, timer_delete, timer_settime, clock_nanosleep, and execve from the same process tree or user account. On EDR/eBPF platforms, hunt for short-lived multithreaded processes repeatedly invoking POSIX timer syscalls and exec transitions, especially from writable directories such as /tmp, /var/tmp, /dev/shm, container overlay paths, CI workspaces, or user home directories. Also investigate any suspicious root privilege transition, new setuid file, modified sudoers entry, unauthorized SSH key, or unexpected kernel module load occurring shortly after kernel warnings or crashes. Threat actor attribution is not provided for this vulnerability, so prioritize behavior-based detection over actor-specific indicators.
- BUG: KASAN: use-after-free
- KASAN: use-after-free
- KFENCE: use-after-free
- general protection fault
- kernel BUG
- kernel panic
- Oops:
- WARNING: CPU:
- run_posix_cpu_timers
- posix_cpu_timer_del
- posix_cpu_timer_set
- posix_cpu_timer_rearm
- posix_cpu_timers_exit
- posix_cpu_timers_exit_group
- lock_task_sighand
- timer_queued
- timerqueue_del
- timerqueue_add
- __exit_signal
- de_thread
- switch_leader
- sys_timer_delete
- timer_delete
- timer_settime
- clock_nanosleep
What your security team should do
- Inventory Linux kernels across servers, endpoints, appliances, cloud images, container nodes, and build infrastructure; identify systems running vendor builds that do not yet include the fix.
- Patch and reboot internet-facing service hosts, container hosts, shared compute, CI/CD runners, and multi-user systems first, even though exploitation requires local access.
- Treat containers as affected when the underlying host kernel is vulnerable; coordinate remediation at the node/host layer rather than only updating container images.
- Temporarily restrict untrusted local code execution and tighten sandboxing for workloads that do not need POSIX timer functionality or broad syscall access.
- Enable or review kernel crash, auditd, eBPF/EDR, and SIEM telemetry for signs of suspicious timer syscall racing, kernel oopses, or unexplained privilege escalation.
- Hunt for post-exploitation artifacts such as newly created privileged users, modified sudoers files, unexpected setuid binaries, abnormal kernel module activity, and suspicious root-owned processes following kernel warnings or crashes.
- Monitor vendor advisories and exploit intelligence because Linux kernel local privilege-escalation vulnerabilities can move from no known exploit to public proof-of-concept quickly.
- If a kernel crash or KASAN use-after-free signature is observed on a vulnerable system, preserve logs and memory/crash dumps before rebooting where operationally feasible.
The record
In the Linux kernel, the following vulnerability has been resolved: posix-cpu-timers: Prevent UAF caused by non-leader exec() race Wongi and Jungwoo decoded and reported a non-leader exec() related race which can result in an UAF: sys_timer_delete() exec() posix_cpu_timer_del() // Observes old leader p = pid_task(pid, pid_type); de_thread() switch_leader(); release_task(old_leader) __exit_signal(old_leader) sighand = lock(old_leader, sighand); posix_cpu_timers*_exit(); sighand = lock_task_sighand(p) unhash_task(old_leader); sh = lock(p, sighand) old_leader->sighand = NULL; unlock(sighand); (p->sighand == NULL) unlock(sh) return NULL; // Returns without action if(!sighand) return 0; free_posix_timer(); This is "harmless" unless the deleted timer was armed and enqueued in p->signal because on exec() a TGID targeted timer is inherited. As sys_timer_delete() freed the underlying posix timer object run_posix_cpu_timers() or any timerqueue related add/delete operations on other timers will access the freed object's timerqueue node, which results in an UAF. There is a similar problem vs. posix_cpu_timer_set(). For regular posix timers it just transiently returns -ESRCH to user space, but for the use case in do_cpu_nanosleep() it's the same UAF just that the k_itimer is allocated on the stack. Also posix_cpu_timer_rearm() fails to rearm the timer, which means it stops to expire. While debating solutions Frederic pointed out another problem: posix_cpu_timer_del(tmr) __exit_signal(p) posix_cpu_timers*_exit(p); unhash_task(p); p->sighand = NULL; sh = lock_task_sighand(p) sighand = p->sighand; if (!sighand) return NULL; lock(sighand); if (!sh) WARN_ON_ONCE(timer_queued(tmr)); On weakly ordered architectures it is not guaranteed that posix_cpu_timer_del() will observe the stores in posix_cpu_timers*_exit() when p->sighand is observed as NULL, which means the WARN() can be a false positive. Solve these issues by: 1) Changing the store in __exit_signal() to smp_store_release(). 2) Adding a smp_acquire__after_ctrl_dep() into the !sighand path of lock_task_sighand(). 3) Creating a helper function for looking up the task and locking sighand which does not return when sighand == NULL. Instead it retries the task lookup and only if that fails it gives up. 4) Using that helper in the three affected functions. #1/#2 ensures that the reader side which observes sighand == NULL also observes all preceeding stores, i.e. the stores in posix_cpu_timers*_exit() and the ones in unhash_task(). #3 ensures that the above described non-leader exec() situation is handled gracefully. When the task lookup returns the old leader, but sighand == NULL then it retries. In the non-leader exec() case the subsequent task lookup will observe the new leader due to #1/#2. In normal exit() scenarios the subsequent lookup fails. When the task lookup fails, the function also checks whether the timer is still enqueued and issues a warning if that's the case. Unfortunately there is nothing which can be done about it, but as the task is already not longer visible the timer should not be accessed anymore. This check also requires memory ordering, which is not provided when the first lookup fails. To achieve that the check is preceeded by a smp_rmb() which pairs with the smp_wmb() in write_seqlock() in __exit_signal(). That ensures that the stores in posix_cpu_timers*_exit() are visible. The history of the non-leader exec() issue goes back to the early days of posix CPU timers, which stored a pointer to the group leader task in the timer. That obviously fails when a non-leader exec() switches the leader. commit e0a70217107e ("posix-cpu-timers: workaround to suppress the problems with mt exec") added a temporary workaround for that in 2010 which surv ---truncated---
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|