xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/bpf/progs/fexit_bpf2bpf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2019 Facebook */
3*4882a593Smuzhiyun #include <linux/stddef.h>
4*4882a593Smuzhiyun #include <linux/if_ether.h>
5*4882a593Smuzhiyun #include <linux/ipv6.h>
6*4882a593Smuzhiyun #include <linux/bpf.h>
7*4882a593Smuzhiyun #include <linux/tcp.h>
8*4882a593Smuzhiyun #include <bpf/bpf_helpers.h>
9*4882a593Smuzhiyun #include <bpf/bpf_endian.h>
10*4882a593Smuzhiyun #include <bpf/bpf_tracing.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun struct sk_buff {
13*4882a593Smuzhiyun 	unsigned int len;
14*4882a593Smuzhiyun };
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun __u64 test_result = 0;
17*4882a593Smuzhiyun SEC("fexit/test_pkt_access")
BPF_PROG(test_main,struct sk_buff * skb,int ret)18*4882a593Smuzhiyun int BPF_PROG(test_main, struct sk_buff *skb, int ret)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun 	int len;
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun 	__builtin_preserve_access_index(({
23*4882a593Smuzhiyun 		len = skb->len;
24*4882a593Smuzhiyun 	}));
25*4882a593Smuzhiyun 	if (len != 74 || ret != 0)
26*4882a593Smuzhiyun 		return 0;
27*4882a593Smuzhiyun 	test_result = 1;
28*4882a593Smuzhiyun 	return 0;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun __u64 test_result_subprog1 = 0;
32*4882a593Smuzhiyun SEC("fexit/test_pkt_access_subprog1")
BPF_PROG(test_subprog1,struct sk_buff * skb,int ret)33*4882a593Smuzhiyun int BPF_PROG(test_subprog1, struct sk_buff *skb, int ret)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	int len;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	__builtin_preserve_access_index(({
38*4882a593Smuzhiyun 		len = skb->len;
39*4882a593Smuzhiyun 	}));
40*4882a593Smuzhiyun 	if (len != 74 || ret != 148)
41*4882a593Smuzhiyun 		return 0;
42*4882a593Smuzhiyun 	test_result_subprog1 = 1;
43*4882a593Smuzhiyun 	return 0;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /* Though test_pkt_access_subprog2() is defined in C as:
47*4882a593Smuzhiyun  * static __attribute__ ((noinline))
48*4882a593Smuzhiyun  * int test_pkt_access_subprog2(int val, volatile struct __sk_buff *skb)
49*4882a593Smuzhiyun  * {
50*4882a593Smuzhiyun  *     return skb->len * val;
51*4882a593Smuzhiyun  * }
52*4882a593Smuzhiyun  * llvm optimizations remove 'int val' argument and generate BPF assembly:
53*4882a593Smuzhiyun  *   r0 = *(u32 *)(r1 + 0)
54*4882a593Smuzhiyun  *   w0 <<= 1
55*4882a593Smuzhiyun  *   exit
56*4882a593Smuzhiyun  * In such case the verifier falls back to conservative and
57*4882a593Smuzhiyun  * tracing program can access arguments and return value as u64
58*4882a593Smuzhiyun  * instead of accurate types.
59*4882a593Smuzhiyun  */
60*4882a593Smuzhiyun struct args_subprog2 {
61*4882a593Smuzhiyun 	__u64 args[5];
62*4882a593Smuzhiyun 	__u64 ret;
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun __u64 test_result_subprog2 = 0;
65*4882a593Smuzhiyun SEC("fexit/test_pkt_access_subprog2")
test_subprog2(struct args_subprog2 * ctx)66*4882a593Smuzhiyun int test_subprog2(struct args_subprog2 *ctx)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	struct sk_buff *skb = (void *)ctx->args[0];
69*4882a593Smuzhiyun 	__u64 ret;
70*4882a593Smuzhiyun 	int len;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	bpf_probe_read_kernel(&len, sizeof(len),
73*4882a593Smuzhiyun 			      __builtin_preserve_access_index(&skb->len));
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	ret = ctx->ret;
76*4882a593Smuzhiyun 	/* bpf_prog_load() loads "test_pkt_access.o" with BPF_F_TEST_RND_HI32
77*4882a593Smuzhiyun 	 * which randomizes upper 32 bits after BPF_ALU32 insns.
78*4882a593Smuzhiyun 	 * Hence after 'w0 <<= 1' upper bits of $rax are random.
79*4882a593Smuzhiyun 	 * That is expected and correct. Trim them.
80*4882a593Smuzhiyun 	 */
81*4882a593Smuzhiyun 	ret = (__u32) ret;
82*4882a593Smuzhiyun 	if (len != 74 || ret != 148)
83*4882a593Smuzhiyun 		return 0;
84*4882a593Smuzhiyun 	test_result_subprog2 = 1;
85*4882a593Smuzhiyun 	return 0;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun __u64 test_result_subprog3 = 0;
89*4882a593Smuzhiyun SEC("fexit/test_pkt_access_subprog3")
BPF_PROG(test_subprog3,int val,struct sk_buff * skb,int ret)90*4882a593Smuzhiyun int BPF_PROG(test_subprog3, int val, struct sk_buff *skb, int ret)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	int len;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	__builtin_preserve_access_index(({
95*4882a593Smuzhiyun 		len = skb->len;
96*4882a593Smuzhiyun 	}));
97*4882a593Smuzhiyun 	if (len != 74 || ret != 74 * val || val != 3)
98*4882a593Smuzhiyun 		return 0;
99*4882a593Smuzhiyun 	test_result_subprog3 = 1;
100*4882a593Smuzhiyun 	return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun __u64 test_get_skb_len = 0;
104*4882a593Smuzhiyun SEC("freplace/get_skb_len")
new_get_skb_len(struct __sk_buff * skb)105*4882a593Smuzhiyun int new_get_skb_len(struct __sk_buff *skb)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	int len = skb->len;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	if (len != 74)
110*4882a593Smuzhiyun 		return 0;
111*4882a593Smuzhiyun 	test_get_skb_len = 1;
112*4882a593Smuzhiyun 	return 74; /* original get_skb_len() returns skb->len */
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun __u64 test_get_skb_ifindex = 0;
116*4882a593Smuzhiyun SEC("freplace/get_skb_ifindex")
new_get_skb_ifindex(int val,struct __sk_buff * skb,int var)117*4882a593Smuzhiyun int new_get_skb_ifindex(int val, struct __sk_buff *skb, int var)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	void *data_end = (void *)(long)skb->data_end;
120*4882a593Smuzhiyun 	void *data = (void *)(long)skb->data;
121*4882a593Smuzhiyun 	struct ipv6hdr ip6, *ip6p;
122*4882a593Smuzhiyun 	int ifindex = skb->ifindex;
123*4882a593Smuzhiyun 	__u32 eth_proto;
124*4882a593Smuzhiyun 	__u32 nh_off;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	/* check that BPF extension can read packet via direct packet access */
127*4882a593Smuzhiyun 	if (data + 14 + sizeof(ip6) > data_end)
128*4882a593Smuzhiyun 		return 0;
129*4882a593Smuzhiyun 	ip6p = data + 14;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (ip6p->nexthdr != 6 || ip6p->payload_len != __bpf_constant_htons(123))
132*4882a593Smuzhiyun 		return 0;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	/* check that legacy packet access helper works too */
135*4882a593Smuzhiyun 	if (bpf_skb_load_bytes(skb, 14, &ip6, sizeof(ip6)) < 0)
136*4882a593Smuzhiyun 		return 0;
137*4882a593Smuzhiyun 	ip6p = &ip6;
138*4882a593Smuzhiyun 	if (ip6p->nexthdr != 6 || ip6p->payload_len != __bpf_constant_htons(123))
139*4882a593Smuzhiyun 		return 0;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (ifindex != 1 || val != 3 || var != 1)
142*4882a593Smuzhiyun 		return 0;
143*4882a593Smuzhiyun 	test_get_skb_ifindex = 1;
144*4882a593Smuzhiyun 	return 3; /* original get_skb_ifindex() returns val * ifindex * var */
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun volatile __u64 test_get_constant = 0;
148*4882a593Smuzhiyun SEC("freplace/get_constant")
new_get_constant(long val)149*4882a593Smuzhiyun int new_get_constant(long val)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	if (val != 123)
152*4882a593Smuzhiyun 		return 0;
153*4882a593Smuzhiyun 	test_get_constant = 1;
154*4882a593Smuzhiyun 	return test_get_constant; /* original get_constant() returns val - 122 */
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun __u64 test_pkt_write_access_subprog = 0;
158*4882a593Smuzhiyun SEC("freplace/test_pkt_write_access_subprog")
new_test_pkt_write_access_subprog(struct __sk_buff * skb,__u32 off)159*4882a593Smuzhiyun int new_test_pkt_write_access_subprog(struct __sk_buff *skb, __u32 off)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	void *data = (void *)(long)skb->data;
163*4882a593Smuzhiyun 	void *data_end = (void *)(long)skb->data_end;
164*4882a593Smuzhiyun 	struct tcphdr *tcp;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (off > sizeof(struct ethhdr) + sizeof(struct ipv6hdr))
167*4882a593Smuzhiyun 		return -1;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	tcp = data + off;
170*4882a593Smuzhiyun 	if (tcp + 1 > data_end)
171*4882a593Smuzhiyun 		return -1;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	/* make modifications to the packet data */
174*4882a593Smuzhiyun 	tcp->check++;
175*4882a593Smuzhiyun 	tcp->syn = 0;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	test_pkt_write_access_subprog = 1;
178*4882a593Smuzhiyun 	return 0;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun char _license[] SEC("license") = "GPL";
182