syzbot
memory leak in build_skb
Status:
upstream: reported syz repro on 2026/10/30 03:34
Subsystems:
net
Labels:
prio:high
[Documentation on labels]
Reported-by: syzbot+a3f21220cbbb6e14ee2e@syzkaller.appspotmail.com
First crash: 5d10h, last: 5d10h
✨ AI-generated root cause summary:
In IPsec IP-TFS (XFRM_MODE_IPTFS) processing, when inner packets (including the reused outer skb) are parsed and added to a temporary local 'sublist' during __input_process_payload(), any error encountering invalid header data or truncated payload jumps to 'done:'. At 'done:', packets on 'sublist' are neither delivered nor freed, and the reused outer skb is neither placed in 'defer' nor freed by kfree_skb(), permanently leaking the sk_buff and its attached sec_path extension.
▶
▼
✨ Full AI root cause analysis
Root Cause Analysis
1. Overview of the Bug
The reported bug is a permanent kernel memory leak of an sk_buff (size 240) and its attached sec_path extension skb_ext (size 192). The leak occurs in the IP-TFS (IP Traffic Flow Security, XFRM_MODE_IPTFS) encapsulation logic in net/xfrm/xfrm_iptfs.c.
2. Detailed Technical Walkthrough
-
Packet Ingestion and Tunnel / ESP Processing:
An ESP packet received via a TUN interface is passed up through tun_get_user() -> netif_receive_skb() -> ip_rcv() -> ip_protocol_deliver_rcu() -> xfrm4_esp_rcv(). The VTI ESP protocol handler (vti_rcv_proto() / vti_input()) looks up the tunnel and invokes xfrm_input(skb, nexthdr, spi, encap_type).
-
XFRM Processing & IPTFS Handoff:
In net/xfrm/xfrm_input.c:xfrm_input(), a security path extension is allocated and attached to the skb via secpath_set(skb) at line 571 (the second leaked object, size 192).
After ESP payload decryption (esp_input()), xfrm_input() calls xfrm_inner_mode_input(x, skb). Because the SA mode is configured as XFRM_MODE_IPTFS (mode 5), it executes iptfs_input() (net/xfrm/xfrm_iptfs.c:1724).
iptfs_input() takes ownership of the skb and returns -EINPROGRESS, which causes xfrm_input() to return 0 without freeing or dropping the skb.
-
Packet Reassembly and Payload Processing:
iptfs_input() orders the incoming packet and calls iptfs_input_ordered(x, skb) (net/xfrm/xfrm_iptfs.c:1225).
iptfs_input_ordered() initializes a local list on its stack frame (struct list_head sublist; INIT_LIST_HEAD(&sublist);) and calls __input_process_payload(x, data, &skbseq, &sublist).
-
The Root Cause Defect in __input_process_payload():
Inside __input_process_payload() (net/xfrm/xfrm_iptfs.c:950):
- In the while loop (
while (data < tail)), the received linear skb is reused for the first inner packet (lines 1066–1094):
first_skb = skb;
defer = NULL;
- The packet is prepared and added to the list of packets to be forwarded:
iptfs_complete_inner_skb(x, skb);
list_add_tail(&skb->list, sublist); (line 1178)
- When the loop continues to evaluate the subsequent data block (such as trailing payload bytes, malformed padding, or subsequent inner packet headers), if an error occurs (such as
skb_copy_seq_read() failure, invalid inner IP version iph->version not in {0, 4, 6}, or invalid header/packet length iplen < iphlen):
} else {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
goto done;
}
Execution immediately jumps to done: (line 1201), skipping the packet transmission loop at line 1196 (list_for_each_entry_safe(skb, next, sublist, list)).
- At label
done:, cleanup logic only handles defer or !first_skb:
done:
skb = skbseq->root_skb;
skb_abort_seq_read(skbseq);
if (defer) {
consume_skb(defer);
} else if (!first_skb) {
kfree_skb(skb);
}
return true;
Because first_skb was set to skb and defer is NULL, neither branch is taken!
Furthermore, sublist is never walked or drained. Any packets queued onto sublist (including first_skb and any reassembled packets added earlier by iptfs_reassem_cont()) remain linked in sublist.
__input_process_payload() returns true. In iptfs_input_ordered(), consumed is true, so if (!consumed) at line 1297 is not taken.
iptfs_input_ordered() returns, destroying the stack frame holding sublist. The hex dump in the leak report confirms this: skb->next and skb->prev contain 0xffffc900021f3890, which is the exact address of sublist on the kernel thread stack.
Classification and Impact
- RootCauseFiles:
net/xfrm/xfrm_iptfs.c contains the missing cleanup in __input_process_payload().
- MemoryCorruption:
false. The unreferenced sk_buff and sec_path objects are orphaned on the heap without any surviving dangling pointers reachable by subsequent kernel operations; no invalid write, invalid free, or use-after-free occurs.
- InfoLeak:
none. The defect only leaks memory allocation slots, disclosing no kernel data to user space.
- RawDenialOfService:
true. Each malformed or unaligned IP-TFS packet causes permanent kernel heap exhaustion of sk_buff and skb_ext slab caches, eventually causing an out-of-memory denial of service.
- IsNetCandidate:
true. The bug is located in the XFRM IPsec networking subsystem and IP-TFS protocol processing.
- IsKVMCandidate:
false. The issue is unrelated to KVM or virtualization.
▶
▼
Last patch testing requests (1)
Sample crash report:
* Struck through repros no longer work on HEAD.