Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Make sure zero-len skbs aren't redirectable

LWT_XMIT to test L3 case, TC to test L2 case.

v2:
- s/veth_ifindex/ipip_ifindex/ in two places (Martin)
- add comment about which condition triggers the rejection (Martin)

Signed-off-by: Stanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/r/20221121180340.1983627-2-sdf@google.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

authored by

Stanislav Fomichev and committed by
Martin KaFai Lau
68f8e3d4 114039b3

+183
+146
tools/testing/selftests/bpf/prog_tests/empty_skb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <test_progs.h> 3 + #include <network_helpers.h> 4 + #include <net/if.h> 5 + #include "empty_skb.skel.h" 6 + 7 + #define SYS(cmd) ({ \ 8 + if (!ASSERT_OK(system(cmd), (cmd))) \ 9 + goto out; \ 10 + }) 11 + 12 + void test_empty_skb(void) 13 + { 14 + LIBBPF_OPTS(bpf_test_run_opts, tattr); 15 + struct empty_skb *bpf_obj = NULL; 16 + struct nstoken *tok = NULL; 17 + struct bpf_program *prog; 18 + char eth_hlen_pp[15]; 19 + char eth_hlen[14]; 20 + int veth_ifindex; 21 + int ipip_ifindex; 22 + int err; 23 + int i; 24 + 25 + struct { 26 + const char *msg; 27 + const void *data_in; 28 + __u32 data_size_in; 29 + int *ifindex; 30 + int err; 31 + int ret; 32 + bool success_on_tc; 33 + } tests[] = { 34 + /* Empty packets are always rejected. */ 35 + 36 + { 37 + /* BPF_PROG_RUN ETH_HLEN size check */ 38 + .msg = "veth empty ingress packet", 39 + .data_in = NULL, 40 + .data_size_in = 0, 41 + .ifindex = &veth_ifindex, 42 + .err = -EINVAL, 43 + }, 44 + { 45 + /* BPF_PROG_RUN ETH_HLEN size check */ 46 + .msg = "ipip empty ingress packet", 47 + .data_in = NULL, 48 + .data_size_in = 0, 49 + .ifindex = &ipip_ifindex, 50 + .err = -EINVAL, 51 + }, 52 + 53 + /* ETH_HLEN-sized packets: 54 + * - can not be redirected at LWT_XMIT 55 + * - can be redirected at TC to non-tunneling dest 56 + */ 57 + 58 + { 59 + /* __bpf_redirect_common */ 60 + .msg = "veth ETH_HLEN packet ingress", 61 + .data_in = eth_hlen, 62 + .data_size_in = sizeof(eth_hlen), 63 + .ifindex = &veth_ifindex, 64 + .ret = -ERANGE, 65 + .success_on_tc = true, 66 + }, 67 + { 68 + /* __bpf_redirect_no_mac 69 + * 70 + * lwt: skb->len=0 <= skb_network_offset=0 71 + * tc: skb->len=14 <= skb_network_offset=14 72 + */ 73 + .msg = "ipip ETH_HLEN packet ingress", 74 + .data_in = eth_hlen, 75 + .data_size_in = sizeof(eth_hlen), 76 + .ifindex = &ipip_ifindex, 77 + .ret = -ERANGE, 78 + }, 79 + 80 + /* ETH_HLEN+1-sized packet should be redirected. */ 81 + 82 + { 83 + .msg = "veth ETH_HLEN+1 packet ingress", 84 + .data_in = eth_hlen_pp, 85 + .data_size_in = sizeof(eth_hlen_pp), 86 + .ifindex = &veth_ifindex, 87 + }, 88 + { 89 + .msg = "ipip ETH_HLEN+1 packet ingress", 90 + .data_in = eth_hlen_pp, 91 + .data_size_in = sizeof(eth_hlen_pp), 92 + .ifindex = &ipip_ifindex, 93 + }, 94 + }; 95 + 96 + SYS("ip netns add empty_skb"); 97 + tok = open_netns("empty_skb"); 98 + SYS("ip link add veth0 type veth peer veth1"); 99 + SYS("ip link set dev veth0 up"); 100 + SYS("ip link set dev veth1 up"); 101 + SYS("ip addr add 10.0.0.1/8 dev veth0"); 102 + SYS("ip addr add 10.0.0.2/8 dev veth1"); 103 + veth_ifindex = if_nametoindex("veth0"); 104 + 105 + SYS("ip link add ipip0 type ipip local 10.0.0.1 remote 10.0.0.2"); 106 + SYS("ip link set ipip0 up"); 107 + SYS("ip addr add 192.168.1.1/16 dev ipip0"); 108 + ipip_ifindex = if_nametoindex("ipip0"); 109 + 110 + bpf_obj = empty_skb__open_and_load(); 111 + if (!ASSERT_OK_PTR(bpf_obj, "open skeleton")) 112 + goto out; 113 + 114 + for (i = 0; i < ARRAY_SIZE(tests); i++) { 115 + bpf_object__for_each_program(prog, bpf_obj->obj) { 116 + char buf[128]; 117 + bool at_tc = !strncmp(bpf_program__section_name(prog), "tc", 2); 118 + 119 + tattr.data_in = tests[i].data_in; 120 + tattr.data_size_in = tests[i].data_size_in; 121 + 122 + tattr.data_size_out = 0; 123 + bpf_obj->bss->ifindex = *tests[i].ifindex; 124 + bpf_obj->bss->ret = 0; 125 + err = bpf_prog_test_run_opts(bpf_program__fd(prog), &tattr); 126 + sprintf(buf, "err: %s [%s]", tests[i].msg, bpf_program__name(prog)); 127 + 128 + if (at_tc && tests[i].success_on_tc) 129 + ASSERT_GE(err, 0, buf); 130 + else 131 + ASSERT_EQ(err, tests[i].err, buf); 132 + sprintf(buf, "ret: %s [%s]", tests[i].msg, bpf_program__name(prog)); 133 + if (at_tc && tests[i].success_on_tc) 134 + ASSERT_GE(bpf_obj->bss->ret, 0, buf); 135 + else 136 + ASSERT_EQ(bpf_obj->bss->ret, tests[i].ret, buf); 137 + } 138 + } 139 + 140 + out: 141 + if (bpf_obj) 142 + empty_skb__destroy(bpf_obj); 143 + if (tok) 144 + close_netns(tok); 145 + system("ip netns del empty_skb"); 146 + }
+37
tools/testing/selftests/bpf/progs/empty_skb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 + #include <linux/bpf.h> 3 + #include <bpf/bpf_helpers.h> 4 + #include <bpf/bpf_endian.h> 5 + 6 + char _license[] SEC("license") = "GPL"; 7 + 8 + int ifindex; 9 + int ret; 10 + 11 + SEC("lwt_xmit") 12 + int redirect_ingress(struct __sk_buff *skb) 13 + { 14 + ret = bpf_clone_redirect(skb, ifindex, BPF_F_INGRESS); 15 + return 0; 16 + } 17 + 18 + SEC("lwt_xmit") 19 + int redirect_egress(struct __sk_buff *skb) 20 + { 21 + ret = bpf_clone_redirect(skb, ifindex, 0); 22 + return 0; 23 + } 24 + 25 + SEC("tc") 26 + int tc_redirect_ingress(struct __sk_buff *skb) 27 + { 28 + ret = bpf_clone_redirect(skb, ifindex, BPF_F_INGRESS); 29 + return 0; 30 + } 31 + 32 + SEC("tc") 33 + int tc_redirect_egress(struct __sk_buff *skb) 34 + { 35 + ret = bpf_clone_redirect(skb, ifindex, 0); 36 + return 0; 37 + }