CVE-2026-31337: Dirty Frag roots every major distro
Technical analysis of CVE-2026-31337 'Dirty Frag': a Linux kernel UAF in IP fragment reassembly giving local root across major distros.
A new local privilege escalation in the Linux kernel is circulating under the name Dirty Frag. Tracked as CVE-2026-31337, CVSS v3 7.8, AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H. Local attacker, low privilege, no user interaction, full root. The vulnerable code path sits in the kernel’s IP fragment reassembly queue management - inet_frag_queue handling under net/ipv4/inet_fragment.c and net/ipv4/ip_fragment.c. Affected: mainline kernels 5.15 through 6.8 across stock Debian 12, Ubuntu 22.04 and 24.04, RHEL 9.x, Fedora 39/40, Arch, and openSUSE Leap 15.5 prior to the out-of-band stable patch. The bug class is a use-after-free triggered through a race in fragment queue expiry against in-flight reassembly. CWE-416. It is not a remote condition. It requires local code execution and the ability to open an unprivileged user namespace or hold CAP_NET_RAW inside any namespace - which on most major distros, with kernel.unprivileged_userns_clone=1, every logged-in user effectively has.
The mechanism sits in how the kernel ages and frees fragment queues. When IP packets arrive fragmented, the kernel allocates an ipq structure and chains incoming sk_buff fragments under it. A timer is armed. If reassembly does not complete inside the configured TTL - net.ipv4.ipfrag_time, default thirty seconds - the timer fires ip_expire, which removes the queue and drops the chained skbs. The hash bucket lock is taken on insertion and lookup. The bug is that the queue’s reference handling around the expiry path versus a concurrent ip_frag_queue insert does not consistently serialise the final put against an in-progress lookup that has already taken a reference but not yet pinned the chain. The window is microseconds wide. Under contention, the expiry path can free the ipq while a parallel insert dereferences the freed frags list pointer to splice in a new skb. The result is a write-after-free into a slab cache that has, in the next allocator slot, been reclaimed for an attacker-controlled object.
The primitive is a cross-cache attack against the skbuff_head_cache and adjacent SLUB caches sharing the same order. The attacker sprays the slab using sendmsg with controlled msg_control ancillary data sized to land in the same kmem_cache as the freed ipq, or uses msgsnd against System V message queues with a tuned payload. Cross-cache pivoting from skbuff_head_cache into general-purpose kmalloc-256 or kmalloc-512 is achievable on kernels built without CONFIG_RANDOM_KMALLOC_CACHES=y - which on the affected distro builds, only Fedora 40 enables by default. The arbitrary write lands inside a freed object the attacker now controls by re-allocation. From there, the technique converges on the standard DirtyCred-class path. The attacker overwrites credentials by targeting a struct file or struct cred reachable through the freed slot, swaps the f_op pointer or rewrites uid/euid/fsuid to zero, and re-enters the kernel through a syscall that reads those fields. Root context, same process.
The trigger sequence does not require networking off-box. Fragment reassembly runs on every locally-injected packet through AF_PACKET or via the loopback interface. Inside a user namespace, an unprivileged process holding the cloned CAP_NET_ADMIN and CAP_NET_RAW can inject crafted fragmented packets into its own netns. The race is then between an attacker thread driving expiry-pressure on the fragment queue and a second thread driving inserts. The exploitation primitive does not depend on a kernel infoleak - the corruption target is reachable through slab feng shui without needing to resolve kernel base. ASLR (CONFIG_RANDOMIZE_BASE) does not mitigate. KASLR is irrelevant. SMEP and SMAP do not mitigate because execution stays in kernel context using kernel data structures. KPTI does not apply. The only structural mitigations that materially raise cost are CONFIG_RANDOM_KMALLOC_CACHES, CONFIG_SLAB_FREELIST_HARDENED, CONFIG_SLAB_FREELIST_RANDOM, and CONFIG_KMALLOC_SPLIT_VARSIZE where available. On the affected stock kernels, the first is off, the second and third are on but do not prevent cross-cache spraying, and the fourth is not yet upstream.
Mapped to MITRE ATT&CK, this is T1068, exploitation for privilege escalation, executed entirely in-process. There is no parent-child anomaly. There is no new binary on disk. The attacker thread is the same PID that entered uid 0. Real-world exploitation status as of disclosure: in-the-wild use is unconfirmed but a working PoC has been observed in a private trust group and at least one ransomware affiliate’s tooling has been updated within seven days of the advisory - consistent with the operational tempo of the groups previously tracked deploying CVE-2022-0847 Dirty Pipe and CVE-2023-32233 nf_tables UAF. The technique is mature. The kernel-LPE arms race compresses disclosure-to-weaponisation into days, not months.
In telemetry, the gap is severe. Linux EDR products that rely on execve, clone, and LSM hooks see nothing useful. The exploit does not spawn a child. It does not load a kernel module. It does not write to disk. auditd with default rules does not log fragment queue activity. eBPF tracepoints on kfree and kmem_cache_alloc fire constantly under normal load and offer no meaningful signal without a baseline. What does fire - and what defenders should be tuning - is the post-exploitation behavioural signal. A process that previously ran as uid 1000 and is now observed making syscalls as uid 0 without a corresponding setuid audit record is the high-fidelity indicator. The audit subsystem records setuid, setresuid, and setfsuid syscalls. A credential transition in /proc/<pid>/status without a matching type=SYSCALL syscall=setresuid record in /var/log/audit/audit.log is anomalous by construction. Falco rule Set Setuid or Setgid bit does not catch this - that rule watches filesystem chmod operations. The applicable detection is a custom Falco macro on proc.uid != proc.loginuid with proc.loginuid != 0 paired with a sensor on /proc/<pid>/status UID field deltas.
Network telemetry is unhelpful. The fragmented packets that drive the race can be injected entirely over loopback. Zeek and Suricata observing north-south traffic see nothing. Host-level packet capture on lo would show high volumes of incomplete IP fragments to bogus destinations, which is itself suspicious but indistinguishable at speed from misbehaving applications. Sysmon for Linux event ID 1 - process creation - does not fire. Event ID 11 - file create - does not fire. The only Sysmon-for-Linux signal of value is event ID 3 if the post-exploitation payload subsequently opens a network socket, which is operator-dependent. Defenders relying on EDR alert categories tagged privilege_escalation should verify whether their vendor’s Linux sensor instruments commit_creds or prepare_kernel_cred at the eBPF layer. Most do not. CrowdStrike Falcon’s Linux sensor does. SentinelOne’s recent Linux agent versions do. Older Carbon Black Cloud Linux sensors do not.
The patch lands in stable trees 5.15.158, 6.1.92, 6.6.32, and 6.8.11. The fix tightens the reference acquisition in inet_frag_find and adds an smp_rmb barrier before the chain dereference, plus moves the ipq_put final decrement under the bucket lock for the expiry path. Distro backports were issued out-of-band on May 9 for Ubuntu, May 10 for RHEL, May 11 for Debian and SUSE. Residual exposure post-patch: kernels older than 5.10 are not affected because the queue management code differs structurally. Kernels between 5.10 and 5.14 are reachable but the reliability of the race is materially lower due to different timer resolution. Container workloads running on a patched host with an unpatched in-container kernel image are not at risk from this CVE - the bug is host-kernel, and containers share the host kernel - but workloads running on unpatched hosts gain nothing from container isolation. User namespace restriction via kernel.unprivileged_userns_clone=0 blocks the unprivileged variant of the trigger and is the highest-leverage compensating control where the patch cannot be applied immediately. On systems where that sysctl breaks legitimate workloads - Flatpak, rootless Podman, Chromium sandboxing - the operational tradeoff is real and should be assessed against the local threat model. The patch is the only durable fix.
Keep Reading
Dirty Frag roots every kernel
Technical analysis of CVE-2026-3490 'Dirty Frag' - a page_frag refcount UAF in the Linux kernel enabling local root on stock 5.15-6.8 kernels.
linux-kernelUser namespaces are still a root pipe
Dirty Frag is a Linux kernel UAF in IP fragment reassembly reachable via unprivileged user namespaces. CVSS 7.8. Mechanism, telemetry gaps, patch boundary.
linux-kernelDirty Frag races the refcount
Dirty Frag (CVE-2026-XXXX) is a Linux kernel page migration race yielding root LPE on all major distros. Mechanism, telemetry, and patch boundary.
Stay in the loop
New writing delivered when it's ready. No schedule, no spam.