From 12bec2bd4b76d81c5d3996bd14ec1b7f4d983747 Mon Sep 17 00:00:00 2001 From: Sun Jian Date: Wed, 8 Apr 2026 11:46:22 +0800 Subject: [PATCH 1/2] bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb bpf_prog_test_run_skb() calls eth_type_trans() first and then uses skb->protocol to initialize sk family and address fields for the test run. For IPv4 and IPv6 packets, it may access ip_hdr(skb) or ipv6_hdr(skb) even when the provided test input only contains an Ethernet header. Reject the input earlier if the Ethernet frame carries IPv4/IPv6 EtherType but the L3 header is too short. Fold the IPv4/IPv6 header length checks into the existing protocol switch and return -EINVAL before accessing the network headers. Fixes: fa5cb548ced6 ("bpf: Setup socket family and addresses in bpf_prog_test_run_skb") Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc Signed-off-by: Sun Jian Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com Signed-off-by: Alexei Starovoitov --- net/bpf/test_run.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 4cd6b3ea1815..2bc04feadfab 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -1137,19 +1137,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, switch (skb->protocol) { case htons(ETH_P_IP): - sk->sk_family = AF_INET; - if (sizeof(struct iphdr) <= skb_headlen(skb)) { - sk->sk_rcv_saddr = ip_hdr(skb)->saddr; - sk->sk_daddr = ip_hdr(skb)->daddr; + if (skb_headlen(skb) < sizeof(struct iphdr)) { + ret = -EINVAL; + goto out; } + sk->sk_family = AF_INET; + sk->sk_rcv_saddr = ip_hdr(skb)->saddr; + sk->sk_daddr = ip_hdr(skb)->daddr; break; #if IS_ENABLED(CONFIG_IPV6) case htons(ETH_P_IPV6): - sk->sk_family = AF_INET6; - if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { - sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; - sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { + ret = -EINVAL; + goto out; } + sk->sk_family = AF_INET6; + sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; + sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; break; #endif default: From f1cc94665df907a85589ddb5fe74d7768ff61533 Mon Sep 17 00:00:00 2001 From: Sun Jian Date: Wed, 8 Apr 2026 11:46:23 +0800 Subject: [PATCH 2/2] selftests/bpf: cover short IPv4/IPv6 inputs with adjust_room Add a selftest covering ETH_HLEN-sized IPv4/IPv6 EtherType inputs for bpf_prog_test_run_skb(). Reuse a single zero-initialized struct ethhdr eth_hlen and set eth_hlen.h_proto from the per-test h_proto field. Also add a dedicated tc_adjust_room program and route the short IPv4/IPv6 cases to it, so the selftest actually exercises the bpf_skb_adjust_room() path from the report. Signed-off-by: Sun Jian Link: https://lore.kernel.org/r/20260408034623.180320-3-sun.jian.kdev@gmail.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/empty_skb.c | 40 +++++++++++++++++-- tools/testing/selftests/bpf/progs/empty_skb.c | 7 ++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/empty_skb.c b/tools/testing/selftests/bpf/prog_tests/empty_skb.c index 438583e1f2d1..c9fcb70cbafb 100644 --- a/tools/testing/selftests/bpf/prog_tests/empty_skb.c +++ b/tools/testing/selftests/bpf/prog_tests/empty_skb.c @@ -10,8 +10,8 @@ void test_empty_skb(void) struct empty_skb *bpf_obj = NULL; struct nstoken *tok = NULL; struct bpf_program *prog; + struct ethhdr eth_hlen; char eth_hlen_pp[15]; - char eth_hlen[14]; int veth_ifindex; int ipip_ifindex; int err; @@ -25,7 +25,9 @@ void test_empty_skb(void) int err; int ret; int lwt_egress_ret; /* expected retval at lwt/egress */ + __be16 h_proto; bool success_on_tc; + bool adjust_room; } tests[] = { /* Empty packets are always rejected. */ @@ -46,6 +48,28 @@ void test_empty_skb(void) .err = -EINVAL, }, + /* ETH_HLEN-sized packets with IPv4/IPv6 EtherType but + * no L3 header are rejected. + */ + { + .msg = "veth short IPv4 ingress packet", + .data_in = ð_hlen, + .data_size_in = sizeof(eth_hlen), + .ifindex = &veth_ifindex, + .err = -EINVAL, + .h_proto = htons(ETH_P_IP), + .adjust_room = true, + }, + { + .msg = "veth short IPv6 ingress packet", + .data_in = ð_hlen, + .data_size_in = sizeof(eth_hlen), + .ifindex = &veth_ifindex, + .err = -EINVAL, + .h_proto = htons(ETH_P_IPV6), + .adjust_room = true, + }, + /* ETH_HLEN-sized packets: * - can not be redirected at LWT_XMIT * - can be redirected at TC to non-tunneling dest @@ -54,7 +78,7 @@ void test_empty_skb(void) { /* __bpf_redirect_common */ .msg = "veth ETH_HLEN packet ingress", - .data_in = eth_hlen, + .data_in = ð_hlen, .data_size_in = sizeof(eth_hlen), .ifindex = &veth_ifindex, .ret = -ERANGE, @@ -68,7 +92,7 @@ void test_empty_skb(void) * tc: skb->len=14 <= skb_network_offset=14 */ .msg = "ipip ETH_HLEN packet ingress", - .data_in = eth_hlen, + .data_in = ð_hlen, .data_size_in = sizeof(eth_hlen), .ifindex = &ipip_ifindex, .ret = -ERANGE, @@ -108,17 +132,27 @@ void test_empty_skb(void) SYS(out, "ip addr add 192.168.1.1/16 dev ipip0"); ipip_ifindex = if_nametoindex("ipip0"); + memset(eth_hlen_pp, 0, sizeof(eth_hlen_pp)); + memset(ð_hlen, 0, sizeof(eth_hlen)); + bpf_obj = empty_skb__open_and_load(); if (!ASSERT_OK_PTR(bpf_obj, "open skeleton")) goto out; for (i = 0; i < ARRAY_SIZE(tests); i++) { + if (tests[i].data_in == ð_hlen) + eth_hlen.h_proto = tests[i].h_proto; + bpf_object__for_each_program(prog, bpf_obj->obj) { bool at_egress = strstr(bpf_program__name(prog), "egress") != NULL; bool at_tc = !strncmp(bpf_program__section_name(prog), "tc", 2); + bool is_adjust_room = !strcmp(bpf_program__name(prog), "tc_adjust_room"); int expected_ret; char buf[128]; + if (tests[i].adjust_room != is_adjust_room) + continue; + expected_ret = at_egress && !at_tc ? tests[i].lwt_egress_ret : tests[i].ret; tattr.data_in = tests[i].data_in; diff --git a/tools/testing/selftests/bpf/progs/empty_skb.c b/tools/testing/selftests/bpf/progs/empty_skb.c index 4b0cd6753251..44326f5cc8bb 100644 --- a/tools/testing/selftests/bpf/progs/empty_skb.c +++ b/tools/testing/selftests/bpf/progs/empty_skb.c @@ -35,3 +35,10 @@ int tc_redirect_egress(struct __sk_buff *skb) ret = bpf_clone_redirect(skb, ifindex, 0); return 0; } + +SEC("tc") +int tc_adjust_room(struct __sk_buff *skb) +{ + ret = bpf_skb_adjust_room(skb, 4, BPF_ADJ_ROOM_NET, 0); + return 0; +}