[PATCH net v2] net: gro: avoid parsing headers from shared fragments
flat view
From: Kyle Zeng <hidden>
Date: 2026-10-31 05:07:56
Also in:
lkml
Subsystem:
networking [general], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
When an skb has an empty linear head, skb_gro_reset_offset() can expose the first page fragment directly to GRO header parsers. For an SKBFL_SHARED_FRAG skb, those bytes may still be writable through a file mapping. Headers validated during receive can therefore differ from the headers later copied into the linear head and used during completion. For example, changing an IPv6 destination-options length between the short and full header fetches in ipv6_gro_pull_exthdrs() can make ipv6_gro_complete() pass an out-of-bounds offset to udp6_gro_complete(). A userspace reproducer triggered a KASAN slab-out-of-bounds read there on an unmodified kernel as UID 1000. The same completion path can write the UDP checksum and length through the invalid offset. The packet has trusted TCP GSO metadata and spliced file data, so it reaches completion without an skb zerocopy destructor or a second GRO packet. Disable the direct-fragment fast path for skbs with externally writable fragments. With an empty linear head, frag0_len remains zero, so skb_gro_header_slow() pulls each required header into the linear head before it is inspected. Subsequent pulls preserve the validated prefix. This covers both gro_receive_skb() and napi_gro_frags(), including other protocols using the same helpers. Linear headers and private fragments retain their existing fast paths. Codex assisted with review of the supplied report, reproducer and draft fix, related-path analysis, and this changelog. The patched net/core/gro.o builds with W=1 using the supplied x86-64 configuration, allyesconfig and allmodconfig. The fix was checked by code-path analysis; the reproducer and kernel selftests have not been run on a booted patched kernel. The issue was found by an LLM. Fixes: dff0b0161ad5 ("net: gro: parse ipv6 ext headers without frag0 invalidation") Cc: stable@kernel.org Signed-off-by: Kyle Zeng <redacted> --- I have a reproducer for this issue. v2: - add Fixes tag - explain that the issue was found by LLM v1: https://lore.kernel.org/netdev/20261030042212.73949-1-kylebot@openai.com/ (local) net/core/gro.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/core/gro.c b/net/core/gro.c
index 1b033855a20d..d6cf2d497934 100644
--- a/net/core/gro.c
+++ b/net/core/gro.c@@ -413,7 +413,8 @@ static inline void skb_gro_reset_offset(struct sk_buff *skb, u32 nhoff) headlen = skb_headlen(skb); NAPI_GRO_CB(skb)->frag0 = skb->data; NAPI_GRO_CB(skb)->frag0_len = headlen; - if (headlen) + /* Shared fragments must be pulled into the linear head before parsing. */ + if (headlen || skb_has_shared_frag(skb)) return; pinfo = skb_shinfo(skb);
base-commit: 2a500a04d6f969318c05f46aedb6e73fc1963a00 -- 2.55.0.openai.911.g06873a30d2f3