GhostLock: The 15-Year-Old Linux Kernel Bug That Defeated Lockdep
A deep dive into CVE-2026-43499, a stack use-after-free in the rtmutex subsystem affecting nearly every Linux distribution.
A fifteen-year-old bug in the core of the Linux kernel locking mechanism has been uncovered, exposing a fundamental architectural hazard in systems programming: the silent danger of API reuse under changed assumptions. Tracked as CVE-2026-43499 and dubbed GhostLock, this stack use-after-free (UAF) vulnerability has existed in almost every mainstream Linux distribution since 2011.
Discovered by security firm Nebula Security using an automated tool named VEGA, the flaw allows an unprivileged local attacker to escape containers and gain full root privileges with 97% reliability. The exploit takes roughly five seconds to execute. Because the vulnerability lives in the priority-inheritance futex (FUTEX_PI) implementation, which is enabled by default in virtually all major distributions, the bug represents a significant patching priority for anyone managing Linux-based infrastructure.
The Root Cause: When "Current" Is Not the Waiter
GhostLock was introduced in May 2011 with the release of Linux kernel version 2.6.39, during a rewrite of the real-time mutex (rtmutex) subsystem. It remained untouched until it was patched in April 2026 (commit 3bfdc63936dd) ahead of the Linux 7.1 release.
The vulnerability lies in kernel/locking/rtmutex.c within a cleanup helper called remove_waiter(). This function was originally designed for a straightforward scenario: a thread blocks on a lock, decides to stop waiting, and cleans up its own state. In this single-threaded execution path, the thread currently running on the CPU (current) is always the task that owns the waiter object.
Using current as a shorthand, the original developer wrote remove_waiter() to clear the calling thread's blocked status:
static void __sched remove_waiter(struct rt_mutex_base *lock,
struct rt_mutex_waiter *waiter)
{
...
raw_spin_lock(¤t->pi_lock);
rt_mutex_dequeue(lock, waiter);
current->pi_blocked_on = NULL; // The bug: assumes current is the waiter
raw_spin_unlock(¤t->pi_lock);
...
}
This assumption broke when the kernel developers reused remove_waiter() for the Requeue-PI proxy path. Under rt_mutex_start_proxy_lock(), a third-party thread (the requeuer) attempts to proxy a lock acquisition on behalf of a sleeping waiter task.
If this proxy operation encounters an error, such as a deadlock, it must roll back the operation. It does so by calling remove_waiter():
int __sched rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,
struct rt_mutex_waiter *waiter,
struct task_struct *task)
{
int ret;
raw_spin_lock_irq(&lock->wait_lock);
ret = __rt_mutex_start_proxy_lock(lock, waiter, task);
if (unlikely(ret))
remove_waiter(lock, waiter); // Triggered on ret == -EDEADLK
raw_spin_unlock_irq(&lock->wait_lock);
return ret;
}
On this proxy path, current is the thread executing the requeue system call, not the sleeping waiter task. When remove_waiter() runs during a rollback, it clears current->pi_blocked_on (the requeuer's state) instead of clearing the state of the actual sleeping task (waiter->task).
This mismatch slipped past lockdep, the kernel's runtime locking validator. lockdep verified that a lock was held, but it failed to validate whose lock was held.
Triggering the Stack Use-After-Free
To exploit this mismatch, an attacker must force the proxy lock path to return an -EDEADLK error. This is achieved by constructing a priority-inheritance dependency cycle using three threads and three futexes:
- f_pi_chain: A PI futex locked by the waiter thread.
- f_pi_target: A PI futex locked by an owner thread.
- f_wait: A standard futex where the waiter thread blocks via
FUTEX_WAIT_REQUEUE_PI.
The waiter thread blocks on f_wait with its rt_mutex_waiter structure allocated directly on its kernel stack. The owner thread then blocks on f_pi_chain. When a coordinator thread calls FUTEX_CMP_REQUEUE_PI to move the waiter from f_wait to f_pi_target, the kernel performs a priority-inheritance chain walk. It detects a loop: waiter -> target -> owner -> chain -> waiter.
This loop returns -EDEADLK, triggering the buggy rollback. The coordinator thread's pi_blocked_on is cleared, while the waiter thread's pi_blocked_on pointer remains untouched, still pointing to the rt_mutex_waiter structure on its own stack.
When the waiter thread wakes up and returns to userspace, its kernel stack frame is popped and freed. However, the kernel still holds a active pointer to that popped stack frame.
Heap-based use-after-free exploits are often notoriously unstable because they rely on tight race windows to reallocate freed memory before the kernel accesses it. GhostLock bypasses this limitation. Because the dangling pointer resides on a thread's stack, the attacker can let the waiter thread sit idle in userspace indefinitely. There is no race pressure.
The exploit chain stabilizes the attack by using PR_SET_MM_MAP to forge a fake waiter structure on the reused stack space. It then triggers a subsequent priority-inheritance chain walk to dereference the forged structure, eventually overwriting a function pointer in inet6_protos[IPPROTO_UDP] and executing a payload to escalate privileges.
The Developer and Platform Angle: Mitigations and the CVSS Trap
GhostLock is tracked with a CVSS score of 7.8 (High). Security teams that prioritize patches solely based on "Critical" (9.0+) CVSS ratings are making a dangerous mistake here. The 7.8 rating reflects the requirement that an attacker must have local access to the target machine to run the exploit.
However, GhostLock was disclosed as part of a two-stage exploit chain called IonStack. The first stage, CVE-2026-10702, is a vulnerability in Firefox's IonMonkey JIT compiler (patched in version 151.0.3) that allows remote code execution inside the browser sandbox. By chaining the browser exploit with GhostLock, an attacker can achieve a zero-click, remote-to-root compromise on a target system. This makes GhostLock a critical threat for multi-tenant environments, cloud servers, and developer workstations.
The Patching Trap: CVE-2026-53166
When upgrading your infrastructure, do not simply grab the first kernel build that claims to fix GhostLock. The initial upstream fix for CVE-2026-43499 introduced a regression that caused kernel crashes, tracked separately as CVE-2026-53166.
Ensure your systems are updated to a kernel version that includes both the GhostLock fix and the subsequent stability cleanups. Many major enterprise distributions, including older Ubuntu LTS releases (20.04, 22.04, and 24.04), had patches marked as "in progress" or pending verification in early July 2026. Verify your package versions against your distribution's security advisories rather than assuming a standard update has resolved the issue.
Hardening Mitigations
If immediate patching is not possible due to legacy software constraints, you can disrupt the public exploit chain by enabling specific kernel hardening options:
- RANDOMIZE_KSTACK_OFFSET: This configuration randomizes the kernel stack offset on every system call. While it does not fix the underlying dangling pointer, it makes the precise stack-reconstruction steps required by the public exploit significantly more difficult and less reliable.
- STATIC_USERMODE_HELPER: This option prevents the kernel from executing arbitrary usermode helpers, making it harder for an attacker to transition from a controlled kernel write to an interactive root shell.
Ultimately, these mitigations only raise the bar for exploitation. Because the vulnerability requires no special namespaces or capabilities to trigger, the only complete resolution is deploying a fully patched kernel.
Sources & further reading
- GhostLock, a stack-UAF that has existed in ALL Linux distributions for 15 years — nebusec.ai
- 15-Year-Old GhostLock Flaw Enables Root and Container Escape on Most Linux Distros — thehackernews.com
- IonStack part II: GhostLock, a stack-UAF that has existed in ALL Linux distributions for 15 years - Security & Privacy - LinuxCommunity.io — linuxcommunity.io
- Public Exploit Turns 15-Year Linux Kernel Flaw Into 5-Second Root Attack — techtimes.com
Ji-ho covers the increasingly tangled overlap between cloud architecture and security, drawing on a background as a penetration tester to keep his reporting grounded in real-world attack paths. He never lets a vendor claim go unquestioned and insists that every buzzword come with a proof of concept.
Discussion 0
No comments yet
Be the first to weigh in.