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

selftests/bpf: Add test for freplace program with write access

This adds a selftest that tests the behavior when a freplace target program
attempts to make a write access on a packet. The expectation is that the read or write
access is granted based on the program type of the linked program and
not itself (which is of type, for e.g., BPF_PROG_TYPE_EXT).

This test fails without the associated patch on the verifier.

Signed-off-by: Udip Pant <udippant@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200825232003.2877030-3-udippant@fb.com

authored by

Udip Pant and committed by
Alexei Starovoitov
6dc03dc7 7e40781c

+48
+1
tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
··· 123 123 "freplace/get_skb_len", 124 124 "freplace/get_skb_ifindex", 125 125 "freplace/get_constant", 126 + "freplace/test_pkt_write_access_subprog", 126 127 }; 127 128 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", 128 129 "./test_pkt_access.o",
+27
tools/testing/selftests/bpf/progs/fexit_bpf2bpf.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* Copyright (c) 2019 Facebook */ 3 3 #include <linux/stddef.h> 4 + #include <linux/if_ether.h> 4 5 #include <linux/ipv6.h> 5 6 #include <linux/bpf.h> 7 + #include <linux/tcp.h> 6 8 #include <bpf/bpf_helpers.h> 7 9 #include <bpf/bpf_endian.h> 8 10 #include <bpf/bpf_tracing.h> ··· 153 151 test_get_constant = 1; 154 152 return test_get_constant; /* original get_constant() returns val - 122 */ 155 153 } 154 + 155 + __u64 test_pkt_write_access_subprog = 0; 156 + SEC("freplace/test_pkt_write_access_subprog") 157 + int new_test_pkt_write_access_subprog(struct __sk_buff *skb, __u32 off) 158 + { 159 + 160 + void *data = (void *)(long)skb->data; 161 + void *data_end = (void *)(long)skb->data_end; 162 + struct tcphdr *tcp; 163 + 164 + if (off > sizeof(struct ethhdr) + sizeof(struct ipv6hdr)) 165 + return -1; 166 + 167 + tcp = data + off; 168 + if (tcp + 1 > data_end) 169 + return -1; 170 + 171 + /* make modifications to the packet data */ 172 + tcp->check++; 173 + tcp->syn = 0; 174 + 175 + test_pkt_write_access_subprog = 1; 176 + return 0; 177 + } 178 + 156 179 char _license[] SEC("license") = "GPL";
+20
tools/testing/selftests/bpf/progs/test_pkt_access.c
··· 79 79 return skb->ifindex * val * var; 80 80 } 81 81 82 + __attribute__ ((noinline)) 83 + int test_pkt_write_access_subprog(struct __sk_buff *skb, __u32 off) 84 + { 85 + void *data = (void *)(long)skb->data; 86 + void *data_end = (void *)(long)skb->data_end; 87 + struct tcphdr *tcp = NULL; 88 + 89 + if (off > sizeof(struct ethhdr) + sizeof(struct ipv6hdr)) 90 + return -1; 91 + 92 + tcp = data + off; 93 + if (tcp + 1 > data_end) 94 + return -1; 95 + /* make modification to the packet data */ 96 + tcp->check++; 97 + return 0; 98 + } 99 + 82 100 SEC("classifier/test_pkt_access") 83 101 int test_pkt_access(struct __sk_buff *skb) 84 102 { ··· 135 117 if (test_pkt_access_subprog3(3, skb) != skb->len * 3 * skb->ifindex) 136 118 return TC_ACT_SHOT; 137 119 if (tcp) { 120 + if (test_pkt_write_access_subprog(skb, (void *)tcp - data)) 121 + return TC_ACT_SHOT; 138 122 if (((void *)(tcp) + 20) > data_end || proto != 6) 139 123 return TC_ACT_SHOT; 140 124 barrier(); /* to force ordering of checks */