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