Netdev List
 help / color / mirror / Atom feed
* [PATCH bpf v8 0/2] bpf: tcp: Fix null-ptr-deref in arbitrary SYN Cookie
@ 2026-06-08 12:58 Jiayuan Chen
  2026-06-08 12:58 ` [PATCH bpf v8 1/2] net: Validate protocol in skb_steal_sock() for BPF-assigned sockets Jiayuan Chen
  2026-06-08 12:58 ` [PATCH bpf v8 2/2] selftests/bpf: Add protocol check test for bpf_sk_assign_tcp_reqsk() Jiayuan Chen
  0 siblings, 2 replies; 6+ messages in thread
From: Jiayuan Chen @ 2026-06-08 12:58 UTC (permalink / raw)
  To: bpf
  Cc: Jiayuan Chen, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Willem de Bruijn, Andrii Nakryiko,
	Eduard Zingerman, Alexei Starovoitov, Daniel Borkmann,
	Martin KaFai Lau, Kumar Kartikeya Dwivedi, Song Liu,
	Yonghong Song, Jiri Olsa, Shuah Khan, Joe Stringer,
	Kuniyuki Iwashima, netdev, linux-kernel, linux-kselftest

bpf_sk_assign_tcp_reqsk() does not validate the L4 protocol of the skb,
only checking skb->protocol (L3). A BPF program that calls this kfunc on
a non-TCP skb (e.g. UDP) will succeed, attaching a TCP reqsk to the skb.

When the skb enters the UDP receive path, skb_steal_sock() returns the
TCP listener socket from the reqsk. The UDP code then casts this TCP
socket to udp_sock and accesses UDP-specific fields at invalid offsets,
causing a null pointer dereference:

  BUG: KASAN: null-ptr-deref in __udp_enqueue_schedule_skb+0x19d/0x1df0
  Read of size 4 at addr 0000000000000008 by task test_progs/537

  CPU: 1 UID: 0 PID: 537 Comm: test_progs Not tainted 7.0.0-rc4+ #46 PREEMPT
  Call Trace:
   <IRQ>
   dump_stack_lvl (lib/dump_stack.c:123)
   print_report (mm/kasan/report.c:487)
   kasan_report (mm/kasan/report.c:597)
   __kasan_check_read (mm/kasan/shadow.c:32)
   __udp_enqueue_schedule_skb (net/ipv4/udp.c:1719)
   udp_queue_rcv_one_skb (net/ipv4/udp.c:2370 net/ipv4/udp.c:2500)
   udp_queue_rcv_skb (net/ipv4/udp.c:2532)
   udp_unicast_rcv_skb (net/ipv4/udp.c:2684)
   __udp4_lib_rcv (net/ipv4/udp.c:2742)
   udp_rcv (net/ipv4/udp.c:2937)
   ip_protocol_deliver_rcu (net/ipv4/ip_input.c:209)
   ip_local_deliver_finish (./include/linux/rcupdate.h:879 net/ipv4/ip_input.c:242)
   ip_local_deliver (net/ipv4/ip_input.c:265)
   __netif_receive_skb_one_core (net/core/dev.c:6164 (discriminator 4))
   __netif_receive_skb (net/core/dev.c:6280)

Solution

Validating the protocol in the helper is not enough: a BPF program can
bypass an ip_hdr(skb)->protocol check via TOCTOU by rewriting the header
around the call, and bpf_sk_assign() has the same problem since it can
assign any socket type to any skb. So validate the protocol where the
assigned socket is consumed instead.

Patch 1: Validate the L4 protocol in skb_steal_sock(). Each caller passes
the protocol it handles (TCP or UDP), and a prefetched socket whose
protocol does not match is rejected, regardless of how it was assigned.
Patch 2: Add a selftest that calls bpf_sk_assign_tcp_reqsk() on a UDP skb
and verifies the stack no longer crashes.

---
v1: https://lore.kernel.org/bpf/20260323105510.51990-1-jiayuan.chen@linux.dev/
v2: https://lore.kernel.org/bpf/20260326062657.88446-1-jiayuan.chen@linux.dev/
v3: https://lore.kernel.org/bpf/20260327133915.286037-1-jiayuan.chen@linux.dev/
v4: https://lore.kernel.org/bpf/20260330080746.319680-1-jiayuan.chen@linux.dev/
v5: https://lore.kernel.org/bpf/20260401110511.73355-1-jiayuan.chen@linux.dev/
v6: https://lore.kernel.org/all/20260403015851.148209-1-jiayuan.chen@linux.dev/

Changes in v6 & v7: 
- resend and keep selftest.

Changes in v5:
- use skb_header_pointer instead of pskb_may_pull.

Changes in v5:
- Add pskb_may_pull before accessing IP/IPv6 headers in kfunc
- Use buf[] instead of buf[32], verify recv data with ASSERT_STREQ
- Remove unnecessary variable initializations in selftest and BPF

Changes in v4:
- Check if assign_ret is EINVAL instead of checking if it is 0

Changes in v3:
- Add IPv6 test coverage, reuse test_cases[] to iterate over both
  address families
- Share TCP/UDP port to simplify BPF program, remove unnecessary
  global variables
- Use connect_to_fd() + send()/recv() instead of manual sockaddr
  construction
- Suggested by Kuniyuki Iwashima

Changes in v2:
- Add Reviewed-by tag from Kuniyuki Iwashima for patch 1
- Use UDP socket recv() instead of kern_sync_rcu() for synchronization
  in selftest

Jiayuan Chen (2):
  net: Validate protocol in skb_steal_sock() for BPF-assigned sockets
  selftests/bpf: Add protocol check test for bpf_sk_assign_tcp_reqsk()

 include/net/inet6_hashtables.h                |   7 +-
 include/net/inet_hashtables.h                 |   7 +-
 include/net/request_sock.h                    |  16 ++-
 net/ipv4/udp.c                                |   2 +-
 net/ipv6/udp.c                                |   2 +-
 .../bpf/prog_tests/tcp_custom_syncookie.c     |  87 ++++++++++++++-
 .../bpf/progs/test_tcp_custom_syncookie.c     | 102 ++++++++++++++++++
 7 files changed, 210 insertions(+), 13 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-06-08 17:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-08 12:58 [PATCH bpf v8 0/2] bpf: tcp: Fix null-ptr-deref in arbitrary SYN Cookie Jiayuan Chen
2026-06-08 12:58 ` [PATCH bpf v8 1/2] net: Validate protocol in skb_steal_sock() for BPF-assigned sockets Jiayuan Chen
2026-06-08 13:31   ` bot+bpf-ci
2026-06-08 17:21   ` Kuniyuki Iwashima
2026-06-08 12:58 ` [PATCH bpf v8 2/2] selftests/bpf: Add protocol check test for bpf_sk_assign_tcp_reqsk() Jiayuan Chen
2026-06-08 13:31   ` bot+bpf-ci

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox