GhostLock (CVE-2026-43499): “no mitigation” is true for the bug — not for the exploit chain

TL;DR

  • GhostLock is a 15-year-old use-after-free in the Linux kernel’s rtmutex.c (the futex priority-inheritance path). Any unprivileged local process can turn it into a root shell. On a shared host that is the whole ballgame: one hacked WordPress plugin becomes root on the box and every tenant on it.
  • CloudLinux’s advisory says there is no mitigation — only the patched kernel or a KernelCare livepatch. That is correct. The UAF stays until you patch. Do that first.
  • But “no mitigation for the bug” is not the same statement as “nothing raises the cost of the public exploit.” The published proof-of-concept is a chain, and chains have weak links.
  • Two of those links are already covered by hardening CFM ships by default: randomize_kstack_offset=on (which is literally the mitigation the researchers name themselves) and the cfm-lsm policy that guards core_pattern and its sibling knobs.
  • None of this closes the hole. It degrades the reliability of the public PoC and gives you a hard block plus telemetry on its final step. Patch anyway.

I went into this expecting CFM to have nothing useful to say — the advisory is unusually blunt about there being no runtime knob. I was wrong, and the reason is worth writing down.


The bug, in one paragraph

GhostLock (CVE-2026-43499, disclosed 7 July 2026 by the VEGA team at Nebula Security in “IonStack part II: GhostLock”) is a use-after-free in the kernel’s real-time mutex code, on the futex priority-inheritance cleanup path. The rollback routine assumes the thread doing the cleanup owns the request it is tearing down; a requeue-with-PI sequence breaks that assumption, and the kernel clears the wrong task’s bookkeeping, leaving a pointer dangling into freed kernel stack. The only prerequisite is CONFIG_FUTEX_PI, which is on by default everywhere and cannot be turned off on a running box without breaking the PI mutexes normal software relies on. The defect landed in Linux 2.6.39 in May 2011, so essentially every kernel of the last decade and a half carries it — which is why every supported CloudLinux version is affected. The researchers report a stable root shell about 97% of the time, in roughly five seconds.

There is no module to blacklist, no sysctl to flip, no per-tenant sandbox that helps — the trigger is the futex() syscall, available to any process, caged or not. The fix is the patched kernel (or the KernelCare livepatch that ships CVE-2026-43499 and its follow-up CVE-2026-53166 together). Nothing here changes that.

So where does CFM come in?


Mitigating the bug vs. degrading the exploit

These are two different questions, and advisories only answer the first one.

“No mitigation” means: nothing stops the rtmutex.c UAF from being triggered and from handing an attacker a dangling pointer. True.

But the jump from dangling pointer to root shell is not free. It is a specific, published chain with specific dependencies, and some of those dependencies are fragile. Harden the platform so that a hot public chain has multiple broken links, and you have bought yourself real time and real visibility — even while the underlying bug is still there. That is the entire point of defense-in-depth, and it is exactly the situation a shared host wants to be in on day zero of an advisory like this.

Here is the public chain, with the two stages CFM actually touches marked:

  1. prefetch timing side-channel → leak the KASLR base and physmap base.
  2. GhostLock UAF → leave a dangling rt_mutex_waiter in the victim task’s pi_blocked_on.
  3. Stack-reclaim via PR_SET_MM_MAP → reclaim the waiter’s own kernel stack and forge a fake rt_mutex_waiter over the freed frame. ← CFM lever 1 bites here
  4. rb-tree erase gives one constrained write → overwrite inet6_protos[IPPROTO_UDP] to point into the CPU entry area.
  5. CEA + ROP → a loopback IPv6/UDP packet pivots through the overwritten handler.
  6. DirtyMode → one write flips core_pattern‘s mode bits; an unprivileged process then writes a |/proc/… payload into the now world-writable core_pattern, and the kernel runs it as root via the usermode-helper. ← CFM lever 2 bites here

Note step 6: the final privilege escalation does not go through commit_creds() or setuid. It pivots through core_pattern → usermodehelper. That detail decides which of CFM’s defenses matter and which stay silent, and it’s why the credential-transition detectors are a red herring here.


Lever 1 — randomize_kstack_offset=on (kernsec, KSPP Tier-1)

This is not a clever CFM trick. It is the mitigation the researchers name in their own write-up, and CFM happens to already apply it.

The stack-reclaim in step 3 works because the freed waiter frame and the later user_auxv frame (from the PR_SET_MM_MAP copy) land at the same stack depth, deterministically. That determinism is the whole game — it’s why the controlled bytes reliably overlap the freed object. Turn on per-syscall kernel-stack offset randomization and they stop lining up:

With RANDOMIZE_KSTACK_OFFSET on they no longer overlap deterministically, and the step becomes a roughly 1/32 (5-bit) stack-offset guess.

So the “97% in five seconds” collapses to a ~1-in-32 gamble per attempt, and a missed guess tends to panic the box rather than silently hand out root — i.e. it converts a quiet compromise into a loud, visible crash.

CFM carries this as a KSPP boot-argument rule (KSEC-BOOT-kspp-004), value on, in Tier-1. Its own profile annotation for compatibility impact is literally “Affects: Nothing” — it is safe to apply everywhere at zero compat cost. The one catch is that it’s a boot argument, so it needs a reboot to take effect. But you are already rebooting for the patched kernel, so it goes into the same maintenance window for free. If you do one thing on the CFM side, do this.


Lever 2 — CFML-FS-008 in enforce (cfm-lsm, BPF-LSM)

CFM’s BPF-LSM component ships a policy — CFML-FS-008, “write to a sensitive kernel knob” — that hooks file_permission on writes to:

core_pattern, modprobe_path, hotplug, /proc/sysrq-trigger, /sys/kernel/uevent_helper, and binfmt_misc/register,

when the writing process is outside a small trusted set (cfm / sysctl / systemd / systemd-sysctl). Its own doc-comment describes the intent as catching kernel-exploit completion pivots through these knobs — which is precisely GhostLock’s DirtyMode stage.

The DirtyMode completion needs an unprivileged process to open() the now-writable core_pattern and write() the |/proc/%P/fd/… payload. That write() goes through file_permission, and in enforce mode the policy returns -EPERM and the chain dies on its last step. As a bonus it covers the sibling pivots (modprobe_path, uevent_helper, …), so an attacker who swaps core_pattern for one of those completions still hits the same wall.

Be honest about the edges, because they matter:

  • The raw kernel write that flips core_pattern‘s mode bits happens inside the ROP stage — a direct kernel memory write that no file hook can see. FS-008 catches the subsequent userspace write() that installs the payload. For the public PoC as written that write is mandatory, so blocking it is enough. A bespoke exploit could choose a completion that never touches these knobs (e.g. a direct cred overwrite) — in which case this lever does nothing. It hardens against the published chain, not against the primitive in the abstract.
  • FS-008 defaults to monitor + disabled. For a real block you need enforce, and you want a short burn-in in monitor first so you don’t -EPERM a legitimate writer of these knobs (an RPM post-install, a tuning script). Watch, then promote.

What CFM does not do here

The credibility of everything above depends on being straight about the gaps:

  • It does not close the UAF. The patched kernel or KernelCare livepatch is the fix. Levers 1 and 2 are cost and visibility, not a cure.
  • CFML-CRED-002 / CRED-003 stay silent. No setuid, no commit_creds — root comes from usermodehelper. The credential-transition detectors never fire on this chain.
  • Disabling user namespaces doesn’t apply. Unlike most LPEs, this chain uses no user namespaces, so the usual user.max_user_namespaces=0 primitive-killer is irrelevant here.
  • There is no LSM hook on futex(). The only runtime block on the trigger is per-workload seccomp filtering of FUTEX_LOCK_PI / FUTEX_WAIT_REQUEUE_PI / FUTEX_CMP_REQUEUE_PI — exactly what the advisory suggests, and it breaks PI mutexes, so it’s containers-only and needs testing. cfm-lsm doesn’t do seccomp.
  • KPTI is not a reliable mitigation for the leak. The prefetch leak is easier with KPTI off, but the researchers note that with KPTI on, prefetch + EntryBleed still recovers the image base. Don’t count on it.
  • The core_pattern=|/bin/false neutralizer is gated off on cPanel/hosting hosts by design — so on a typical cPanel box you don’t get that particular free win, and even where it applies it only closes the coredump vector, not modprobe_path / uevent_helper.

Practical recommendation

  1. Patch. Install the patched kernel for your CloudLinux version, or apply the KernelCare livepatch (it ships CVE-2026-43499 and CVE-2026-53166 together — verify with kcarectl --patch-info | grep -E 'CVE-2026-43499|CVE-2026-53166', not --info). This is the fix. Everything else is defense-in-depth around it.
  2. In the same reboot window, confirm randomize_kstack_offset=on is applied (CFM Tier-1 / KSPP, Affects: Nothing). It’s the researchers’ own named mitigation and it’s free once you’re already rebooting. It turns a ~97% silent win into a ~1/32 gamble that mostly panics.
  3. Turn on CFML-FS-008 in monitor now to see whether anything legitimate writes these knobs, then promote it to enforce after a short burn-in to hard-block the core_pattern completion (and its siblings).

The takeaway isn’t “CFM stops GhostLock” — it doesn’t, and any tool that claims to close an unpatched kernel UAF from userspace is selling you something. The takeaway is narrower and, I think, more useful: an advisory’s “no mitigation” describes the vulnerability, not the deployed exploit. A platform that already ships KSPP hardening and knob-write guards forces the single hottest public chain to survive two extra broken links it wasn’t built to survive. That’s not a substitute for patching. It’s the reason you patch from a position of a bit more safety instead of a lot less.


Credit where due: the bug, the exploit chain, and the RANDOMIZE_KSTACK_OFFSET observation are all from the VEGA / Nebula Security write-up. CFM’s contribution is simply that this hardening is on by default and managed, so the day an advisory like this lands you’re already halfway there.