Kernel UAF reachable from user namespace
CVE-2026-29144 Dirty Frag - Linux kernel IP fragment reassembly UAF gives unprivileged users root across major distros. Mechanism, exploitation path, telemetry gaps.
Tracked as CVE-2026-29144. CVSS v3 base 7.8. Local privilege escalation. The bug lives in the Linux kernel IP fragmentation reassembly path inside net/ipv4/ip_fragment.c and the matching IPv6 handler in net/ipv6/reassembly.c. Affected versions span mainline 5.10 through 6.8.7. Patched at commit boundary 6.8.8 and backported to 5.10.219, 5.15.158, 6.1.88, 6.6.29. Distros confirmed vulnerable in shipped kernels - Ubuntu 22.04 GA, Ubuntu 24.04 GA, Debian 12, RHEL 9.3, Rocky 9.3, Amazon Linux 2023, SUSE 15 SP5, current Arch as of the disclosure date. The defect is reachable from an unprivileged user namespace. That is the part that matters.
The bug class is a slab use-after-free in the fragment queue (ipq / frag_queue) cleanup path. CWE-416. Reassembly works by holding partial datagrams in a per-netns hash table keyed by source, destination, protocol, and IP ID. Each ipq owns an sk_buff chain of received fragments. When the last fragment arrives, ip_frag_reasm() walks the chain, merges payload into a head skb, removes the queue from the hash, and frees the per-fragment skbs. Two timers exist on the queue - a per-queue expiry timer and an LRU eviction triggered when the netns reassembly memory cap is exceeded.
The race is between successful reassembly and asynchronous LRU eviction under memory pressure. inet_frag_queue_evict() walks the LRU list, takes the queue lock, removes the queue from the hash, and proceeds to free its skb chain. ip_frag_reasm() on a parallel CPU takes a reference to the head skb before the queue is unlinked, but the existing reference accounting collapses the queue free before the reassembly path consumes its last skb pointer. The result is a freed sk_buff whose data and head pointers are dereferenced after release back to the skbuff_head_cache slab. The fragment payload bytes - attacker-controlled - survive in the freed object until the slab line is reused.
The exploitation primitive is a controlled-content slab UAF in skbuff_head_cache, which is a general-purpose SLUB cache on every distribution kernel shipping today. Cross-cache attacks are not required. The attacker reclaims the freed skb with a heap spray of objects allocated from the same cache - additional skbs created via sendmsg() on a raw or UDP socket, with payload bytes that overlap the sk_buff header layout. The fields of interest are head, data, tail, end, and the destructor function pointer. Overwriting head and end produces an arbitrary-length out-of-bounds read or write when the kernel later calls skb_put() or kfree_skb() against the dangling pointer.
The path from controlled-content UAF to root is conventional. Pivot to a cred overwrite via a pipe_buffer cross-type reclaim - the technique used in DirtyCred lineage exploits since 2022. The pipe_buffer structure shares slab residency in kmalloc-192 on most builds. A function pointer inside pipe_buf_operations is invoked when the pipe is read. Land an attacker-chosen pointer there and KPTI plus SMEP are bypassed via ROP into kernel .text - the conventional gadget set in do_task_dead() and force_sig_info(). SMAP is not relevant - the payload lives in kernel slab memory. KASLR is leaked beforehand via /proc/kallsyms if readable, or via timing oracles against prctl() when not. The final write zeroes current->cred->uid, gid, euid, egid, fsuid, fsgid, and clears the cap mask. The shell that spawned the exploit returns to userspace with uid=0 and a full capability set.
Reachability is the part security teams need to register. The fragmentation code path was historically reachable only by a process holding CAP_NET_RAW, which limited the bug to root-equivalent contexts. That assumption no longer holds. Since the broad rollout of unprivileged user namespaces - Ubuntu enabled by default since 16.04, RHEL since 8.5 with user.max_user_namespaces, the rest of the field since 2022 - a local unprivileged user can unshare(CLONE_NEWUSER | CLONE_NEWNET) and obtain a private network namespace where they hold CAP_NET_RAW over lo and any veth they create. Raw sockets and crafted fragmented packets are then in scope. No privileged binary needed. No suid path involved. The trust boundary that previously gated the bug evaporated when user namespaces went mainstream.
Real-world exploitation maps to MITRE T1068 - exploitation for privilege escalation - chained behind any initial access technique that lands code execution as an unprivileged user. T1190 web app exploitation into a containerized workload is the highest-yield delivery on cloud infrastructure. Container escape implications follow. Default Docker, containerd, and CRI-O configurations disable user namespace remapping, but the host kernel is shared. A pod running as a non-root user inside a Kubernetes cluster that does not pin a restrictive seccomp profile - the cluster default RuntimeDefault does not block the syscalls used here - can stage the primitive and reach host root. PodSecurityStandard restricted does not close the gap. Only an explicit seccomp policy denying unshare with CLONE_NEWUSER, or kernel parameter kernel.unprivileged_userns_clone=0, removes the namespace pivot.
No confirmed in-the-wild use at time of writing. Public PoC was published seven days post-disclosure by the original reporter at a level demonstrating the primitive without delivering a turnkey weapon. Detection vendors have begun ingesting the indicators. Threat intel reporting flags interest from operators historically associated with Linux-targeting toolchains - ShadowPad-adjacent clusters and the SOHO router actor group tracked as VPNFilter successor activity. None are confirmed deployers. The bar to weaponise is low for any operator already maintaining a Linux LPE catalogue.
Telemetry surface is thin. The exploit produces almost nothing distinctive at userland. There is no exec of an unusual binary, no setuid call, no module load, no syscall that on its own is anomalous. unshare() with CLONE_NEWUSER | CLONE_NEWNET is generated by countless legitimate workloads - Chrome’s sandbox, Firejail, rootless containers, bubblewrap. The crafted fragment traffic stays on lo inside the user’s private netns and never crosses a NIC. tcpdump on the host sees nothing. Falco’s default ruleset does not fire. auditd with the standard CIS profile does not fire. Sysmon for Linux event ID 1 logs process creation but the exploit can run inside an existing process. Event ID 11 - file create - is silent. The most reliable signal is the post-exploitation behaviour, not the exploitation itself. A process whose cred transitions from non-zero uid to uid=0 without traversing a setuid binary or execve() of a privileged target is the anomaly. eBPF programs hooking commit_creds() and correlating against the calling task’s prior credential state catch it. Tetragon, Falco’s modern eBPF driver, and CrowdStrike’s Linux sensor in recent agent versions have detections for this credential transition pattern. Most SOC SIEM correlation rules do not.
Network detection is effectively zero. The fragments never leave the host. EDR vendors relying on syscall trace patterns observe socket(AF_INET, SOCK_RAW, ...) inside a netns followed by sendmsg() bursts - neither is rare. The fingerprint that distinguishes exploitation from benign use is the ratio of fragmented sends against loopback inside a freshly-created namespace by a process that has no prior history of raw socket use. That correlation is constructible. It is not on by default.
Patch boundary is the kernel commits listed above. The fix tightens reference accounting on the fragment queue and serialises eviction against in-flight reassembly via an additional refcount taken before the LRU walk releases the queue. Distro kernels rolled the patch through their standard advisory channels in the week following disclosure. Live kernel patching via kpatch, kgraft, or Ksplice covers the bug without reboot on supported subscriptions. Post-patch residual exposure is the eviction path itself - the same code surface has produced two prior CVEs since 2021 and remains a candidate for further variants. Defence-in-depth that holds independent of the kernel patch: set kernel.unprivileged_userns_clone=0 where workloads tolerate it, deploy seccomp profiles that deny unshare(CLONE_NEWUSER) for containers that do not require it, and hook commit_creds in eBPF to alert on credential elevation outside the expected paths. The kernel patch closes this bug. The class is not closed.
Keep Reading
User 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-kernelCVE-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.
linux-kernelDirty 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.
Stay in the loop
New writing delivered when it's ready. No schedule, no spam.