Skip to content

Security1 publisher3 min readPublished

Disabling unprivileged user namespaces stops three of four new Linux local-root bugs

Fixes are in for four Linux local-root bugs found in code more than a decade old. Turning off unprivileged user namespaces closes three of them. The fourth stays open.

The Watch · Security desk

Illustration accompanying Disabling unprivileged user namespaces stops three of four new Linux local-root bugs

What happened

  • Four Linux local-privilege-escalation vulnerabilities were disclosed together: DirtyAH6 (CVE-2026-80844), TUNderflow (CVE-2026-81000), PPPoEject (CVE-2026-68121) and DiagSpill (CVE-2026-74469).
  • DirtyAH6, TUNderflow and PPPoEject all need unprivileged user namespaces to reach local root, while DiagSpill reaches it without one.
  • Fixes went in after a mid-July report to [email protected], and the writeup plus proof-of-concept code publish on September 18 at 6am UTC under a linux-distros embargo.

Compiled by The WatchSomething wrong?How this is made

Why it matters

  • decision The unprivileged user namespace setting now has a coverage number on this batch: off, it removes three local paths and leaves one. That is a partial control operators can size.
  • exposure A host running IPsec AH in transport mode can be crashed by someone holding no local account at all, so DirtyAH6 does not belong in the queue behind the local-only bugs.
  • cost After 06:00 UTC on September 18, the cost of attacking an unpatched host drops to running published code, and the patch window closes for everyone who has not shipped the kernel update.
  • precedent One harness delivered four kernel LPEs in a single coordinated release, so the next disclosure from the same tooling should be planned for as a batch of CVEs across several subsystems.

DirtyAH6 is the one to read first. `ipv6_rearrange_rthdr()` took the number of addresses from `hdrlen`, then moved an address pointer by `segments - segments_left` without first checking that `segments_left` was no larger than `segments` [9]. A raw IPv6 `HDRINCL` packet with `hdrlen=2` and `segments_left=255` moved the pointer back 4,064 bytes and handed the same 4,064-byte length to `memmove()` [10]. At 16 bytes per IPv6 address, that displacement is 254 addresses [18].

With AH in transport mode, the same bug becomes a remote crash or denial of service, and with memory grooming performed on the target the researcher turned it into remote root in the lab [11]. The researcher wrote that getting to root with remote-only grooming looks extremely difficult but is not a priori impossible [12].

TUNderflow is an integer underflow. `tun_set_headroom()` stored receive headroom straight into `tun->align`, while `tun_get_user()` used the same value to decide how much packet data to keep in the head [13]. A `netkit` device with 4,096 bytes of configured headroom, under a VXLAN device and an Open vSwitch datapath, passed 4,160 bytes to a raw TUN port; `SKB_MAX_HEAD(4160)` underflowed, the negative `good_linear` became a huge `size_t`, `prepad + linear` and `len - linear` wrapped, and `tun_alloc_skb()` left `skb->data` 64 bytes beyond its 4,096-byte allocation [14]. The overshoot is exactly what the chain added on top of the configured headroom [19].

In PPPoEject, `pppoe_sendmsg()` held a pointer into the `skb` head across `dev_hard_header()`, where a device callback can call `pskb_expand_head()` and free that head [15]. Blocking the payload copy on FUSE while adding the first GRE or IP6GRE port to an empty `team` or `bonding` device triggered the reallocation [16].

DiagSpill is the outlier. It needs no user namespace [3], and it is the second of the two bugs with a remote condition [4]. The post describes `sctp_diag` building a Netlink reply with one `sockaddr_storage` per peer transport [17]; the exploitation detail comes with the writeup and proof-of-concept code on September 18 [6].

So the hardening call is bounded. Switching off unprivileged user namespaces takes away the local path for DirtyAH6, TUNderflow and PPPoEject, three of the four [20]. DiagSpill's local path does not use a namespace, and neither does the AH6 remote path [3][11].

All four came out of one harness: graph-based tracking of security-relevant kernel objects, as used in CIFSwitch, combined with the tooling from OVSwrap that lets agents reason geometrically about memory state [8]. The underlying bugs had been in the tree for 10 to 21 years [2]. Report to public code runs about nine weeks [21], and the post credits Stefan Klassert, Xin Long, Paolo Abeni, Willem de Bruijn and Greg KH among the maintainers who handled patching and coordination [7].

What to watch

  • Whether distribution kernels carry all four fixes before the proof-of-concept code publishes at 06:00 UTC on September 18.
  • Whether anyone reproduces DirtyAH6 remote root with grooming performed entirely over the network, which the researcher called extremely difficult.
  • What conditions DiagSpill's remote path actually requires, since it is the one LPE here that no user namespace setting blocks.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories