From 546daf344420b5dce27eded3ad15be12628dd185 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Oct 2026 18:18:58 +0200 Subject: [PATCH] net: fix frag_list leak in skb_segment_list() error path skb_segment_list() detaches the frag_list from the head skb and moves its members one by one to the skb->next chain. On error, err_linearize frees that chain with kfree_skb_list(skb->next), relying on the members not yet processed to still be linked after the current one. This does not hold when the current member was shared: it is replaced by skb_clone(), and __skb_clone() clears ->next. If __skb_linearize() then fails on that clone, the remaining members are no longer reachable from skb->next nor from skb_shinfo(skb)->frag_list, and they leak. The skb_shared() error branch already relinks nskb->next to list_skb before jumping to err_linearize. Do it unconditionally right after nskb is added to the chain, so every error exit sees the remaining members. On the last member list_skb is NULL, which still terminates the chain. Fixes: 53475c5dd856 ("net: fix use-after-free when UDP GRO with shared fraglist") Signed-off-by: Eric Dumazet Cc: Simon Polack Reviewed-by: Willem de Bruijn Reviewed-by: Wang Zhan Reviewed-by: Jiayuan Chen Link: https://patch.msgid.link/20261021161858.761205-1-edumazet@kernel.org Signed-off-by: Jakub Kicinski --- net/core/skbuff.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6a7c02b7653a..48f676411724 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4782,10 +4782,13 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb, else tail->next = nskb; - if (unlikely(err)) { - nskb->next = list_skb; + /* nskb may be a clone with a NULL ->next: keep the remaining + * members linked so that err_linearize frees them. + */ + nskb->next = list_skb; + + if (unlikely(err)) goto err_linearize; - } tail = nskb;