1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Facebook */
3 #include <linux/bpf.h>
4 #include "bpf_helpers.h"
5 #include "bpf_trace_helpers.h"
6 
7 struct sk_buff {
8 	unsigned int len;
9 };
10 
11 __u64 test_result = 0;
12 BPF_TRACE_2("fexit/test_pkt_access", test_main,
13 	    struct sk_buff *, skb, int, ret)
14 {
15 	int len;
16 
17 	__builtin_preserve_access_index(({
18 		len = skb->len;
19 	}));
20 	if (len != 74 || ret != 0)
21 		return 0;
22 	test_result = 1;
23 	return 0;
24 }
25 
26 __u64 test_result_subprog1 = 0;
27 BPF_TRACE_2("fexit/test_pkt_access_subprog1", test_subprog1,
28 	    struct sk_buff *, skb, int, ret)
29 {
30 	int len;
31 
32 	__builtin_preserve_access_index(({
33 		len = skb->len;
34 	}));
35 	if (len != 74 || ret != 148)
36 		return 0;
37 	test_result_subprog1 = 1;
38 	return 0;
39 }
40 
41 /* Though test_pkt_access_subprog2() is defined in C as:
42  * static __attribute__ ((noinline))
43  * int test_pkt_access_subprog2(int val, volatile struct __sk_buff *skb)
44  * {
45  *     return skb->len * val;
46  * }
47  * llvm optimizations remove 'int val' argument and generate BPF assembly:
48  *   r0 = *(u32 *)(r1 + 0)
49  *   w0 <<= 1
50  *   exit
51  * In such case the verifier falls back to conservative and
52  * tracing program can access arguments and return value as u64
53  * instead of accurate types.
54  */
55 struct args_subprog2 {
56 	__u64 args[5];
57 	__u64 ret;
58 };
59 __u64 test_result_subprog2 = 0;
60 SEC("fexit/test_pkt_access_subprog2")
test_subprog2(struct args_subprog2 * ctx)61 int test_subprog2(struct args_subprog2 *ctx)
62 {
63 	struct sk_buff *skb = (void *)ctx->args[0];
64 	__u64 ret;
65 	int len;
66 
67 	bpf_probe_read_kernel(&len, sizeof(len),
68 			      __builtin_preserve_access_index(&skb->len));
69 
70 	ret = ctx->ret;
71 	/* bpf_prog_load() loads "test_pkt_access.o" with BPF_F_TEST_RND_HI32
72 	 * which randomizes upper 32 bits after BPF_ALU32 insns.
73 	 * Hence after 'w0 <<= 1' upper bits of $rax are random.
74 	 * That is expected and correct. Trim them.
75 	 */
76 	ret = (__u32) ret;
77 	if (len != 74 || ret != 148)
78 		return 0;
79 	test_result_subprog2 = 1;
80 	return 0;
81 }
82 char _license[] SEC("license") = "GPL";
83