Skip to content

Commit abdf397

Browse files
CIQ Kernel Automationroxanan1996
authored andcommitted
net: fix memory leak in skb_segment_list for GRO packets
jira VULN-174746 cve CVE-2026-22979 commit-author Mohammad Heib <mheib@redhat.com> commit 238e03d When skb_segment_list() is called during packet forwarding, it handles packets that were aggregated by the GRO engine. Historically, the segmentation logic in skb_segment_list assumes that individual segments are split from a parent SKB and may need to carry their own socket memory accounting. Accordingly, the code transfers truesize from the parent to the newly created segments. Prior to commit ed4ccce ("gro: fix ownership transfer"), this truesize subtraction in skb_segment_list() was valid because fragments still carry a reference to the original socket. However, commit ed4ccce ("gro: fix ownership transfer") changed this behavior by ensuring that fraglist entries are explicitly orphaned (skb->sk = NULL) to prevent illegal orphaning later in the stack. This change meant that the entire socket memory charge remained with the head SKB, but the corresponding accounting logic in skb_segment_list() was never updated. As a result, the current code unconditionally adds each fragment's truesize to delta_truesize and subtracts it from the parent SKB. Since the fragments are no longer charged to the socket, this subtraction results in an effective under-count of memory when the head is freed. This causes sk_wmem_alloc to remain non-zero, preventing socket destruction and leading to a persistent memory leak. The leak can be observed via KMEMLEAK when tearing down the networking environment: unreferenced object 0xffff8881e6eb9100 (size 2048): comm "ping", pid 6720, jiffies 4295492526 backtrace: kmem_cache_alloc_noprof+0x5c6/0x800 sk_prot_alloc+0x5b/0x220 sk_alloc+0x35/0xa00 inet6_create.part.0+0x303/0x10d0 __sock_create+0x248/0x640 __sys_socket+0x11b/0x1d0 Since skb_segment_list() is exclusively used for SKB_GSO_FRAGLIST packets constructed by GRO, the truesize adjustment is removed. The call to skb_release_head_state() must be preserved. As documented in commit cf673ed ("net: fix fraglist segmentation reference count leak"), it is still required to correctly drop references to SKB extensions that may be overwritten during __copy_skb_header(). Fixes: ed4ccce ("gro: fix ownership transfer") Signed-off-by: Mohammad Heib <mheib@redhat.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/20260104213101.352887-1-mheib@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> (cherry picked from commit 238e03d) Signed-off-by: CIQ Kernel Automation <ciq_kernel_automation@ciq.com>
1 parent 8d82077 commit abdf397

1 file changed

Lines changed: 5 additions & 3 deletions

File tree

net/core/skbuff.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4007,12 +4007,14 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
40074007
{
40084008
struct sk_buff *list_skb = skb_shinfo(skb)->frag_list;
40094009
unsigned int tnl_hlen = skb_tnl_header_len(skb);
4010-
unsigned int delta_truesize = 0;
40114010
unsigned int delta_len = 0;
40124011
struct sk_buff *tail = NULL;
40134012
struct sk_buff *nskb, *tmp;
40144013
int len_diff, err;
40154014

4015+
/* Only skb_gro_receive_list generated skbs arrive here */
4016+
DEBUG_NET_WARN_ON_ONCE(!(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST));
4017+
40164018
skb_push(skb, -skb_network_offset(skb) + offset);
40174019

40184020
skb_shinfo(skb)->frag_list = NULL;
@@ -4021,8 +4023,9 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
40214023
nskb = list_skb;
40224024
list_skb = list_skb->next;
40234025

4026+
DEBUG_NET_WARN_ON_ONCE(nskb->sk);
4027+
40244028
err = 0;
4025-
delta_truesize += nskb->truesize;
40264029
if (skb_shared(nskb)) {
40274030
tmp = skb_clone(nskb, GFP_ATOMIC);
40284031
if (tmp) {
@@ -4066,7 +4069,6 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
40664069

40674070
} while (list_skb);
40684071

4069-
skb->truesize = skb->truesize - delta_truesize;
40704072
skb->data_len = skb->data_len - delta_len;
40714073
skb->len = skb->len - delta_len;
40724074

0 commit comments

Comments
 (0)