[SRU][R/Q/N][PATCH 0/3] net: GRO managed-frag use-after-free leading to local privilege escalation (LP: #2154172)
Cengiz Can
cengiz.can at canonical.com
Mon May 25 12:03:33 UTC 2026
BugLink: https://bugs.launchpad.net/bugs/2154172
[ Impact ]
skb_gro_receive() in net/core/gro.c copies frag descriptors from a
source skb into a GRO accumulator without checking the
SKBFL_MANAGED_FRAG_REFS flag. A managed-frag skb does not hold a
per-frag page reference; the caller is responsible for the page
lifetime. When such frags are transferred into an accumulator that
is not managed, the accumulator's skb_release_data() path eventually
calls put_page() on frags it never get_page()'d, producing a page
refcount underflow.
An unprivileged local user can turn this underflow into a
use-after-free on UNMOVABLE pages and from there into arbitrary
write of a root-owned read-only file via a dirty-pagetable PFN
overlap. The primitive requires io_uring SEND_ZC with fixed
buffers and a veth/GRO loopback path; both are reachable without
privilege on default Ubuntu installs (with
apparmor_restrict_unprivileged_userns disabled or absent).
[ Fix ]
commit 4db79a322db8c97f7b73b8a347395ef4d685eb40
("net: gro: don't merge zcopy skbs")
When either the source or the last skb in the GRO chain has
SKBFL_MANAGED_FRAG_REFS or any zerocopy flag set, refuse to
merge. This preserves the invariant that GRO does not steal
page references it did not take.
Currently queued in netdev/net; not yet merged into Linus's tree.
Clean cherry-pick onto noble, questing and resolute.
[ Test Plan ]
A user-space reproducer is run on a VM booted with the patched
kernel, AppArmor unprivileged-userns restriction disabled
(kernel.apparmor_restrict_unprivileged_userns=0). With the patch
applied the reproducer can no longer trigger the GRO managed-frag
merge it depends on and self-reports failure; sha256(/etc/passwd)
is unchanged pre/post.
Verified on noble 6.8.0-117, questing 6.17.0-29 and resolute
7.0.0-15.
[ Where Problems Could Occur ]
The fix only refuses a merge in a case that was always unsafe. The
visible effect is that GRO occasionally produces one more
segment-sized skb than it otherwise would on flows that mix managed
and non-managed frags (currently io_uring SEND_ZC over veth /
loopback). That is a tiny throughput change in an uncommon path,
not a crash or correctness problem. The opposite mistake (still
merging) re-exposes the underlying CVE.
No userspace API change. No kernel ABI change. No module change.
More information about the kernel-team
mailing list