]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb
authorSun Jian <sun.jian.kdev@gmail.com>
Wed, 8 Apr 2026 03:46:22 +0000 (11:46 +0800)
committerAlexei Starovoitov <ast@kernel.org>
Sun, 12 Apr 2026 22:42:57 +0000 (15:42 -0700)
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 <sun.jian.kdev@gmail.com>
Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
net/bpf/test_run.c

index 4cd6b3ea1815a93e9416583136676d5b01275229..2bc04feadfabedd4584431905c513af5e4882803 100644 (file)
@@ -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: