1 | #include "vmlinux.h" |
2 | #include <bpf/bpf_helpers.h> |
3 | #include <bpf/bpf_core_read.h> |
4 | |
5 | const char LICENSE[] SEC("license" ) = "GPL" ; |
6 | |
7 | struct { |
8 | __uint(type, BPF_MAP_TYPE_ARRAY); |
9 | __uint(max_entries, 1); |
10 | __type(key, __u32); |
11 | __type(value, __u64); |
12 | } array SEC(".maps" ); |
13 | |
14 | __noinline int sub1(int x) |
15 | { |
16 | int key = 0; |
17 | |
18 | bpf_map_lookup_elem(&array, &key); |
19 | return x + 1; |
20 | } |
21 | |
22 | static __noinline int sub5(int v); |
23 | |
24 | __noinline int sub2(int y) |
25 | { |
26 | return sub5(y + 2); |
27 | } |
28 | |
29 | static __noinline int sub3(int z) |
30 | { |
31 | return z + 3 + sub1(4); |
32 | } |
33 | |
34 | static __noinline int sub4(int w) |
35 | { |
36 | int key = 0; |
37 | |
38 | bpf_map_lookup_elem(&array, &key); |
39 | return w + sub3(5) + sub1(6); |
40 | } |
41 | |
42 | /* sub5() is an identitify function, just to test weirder functions layout and |
43 | * call patterns |
44 | */ |
45 | static __noinline int sub5(int v) |
46 | { |
47 | return sub1(v) - 1; /* compensates sub1()'s + 1 */ |
48 | } |
49 | |
50 | /* unfortunately verifier rejects `struct task_struct *t` as an unknown pointer |
51 | * type, so we need to accept pointer as integer and then cast it inside the |
52 | * function |
53 | */ |
54 | __noinline int get_task_tgid(uintptr_t t) |
55 | { |
56 | /* this ensures that CO-RE relocs work in multi-subprogs .text */ |
57 | return BPF_CORE_READ((struct task_struct *)(void *)t, tgid); |
58 | } |
59 | |
60 | int res1 = 0; |
61 | int res2 = 0; |
62 | int res3 = 0; |
63 | int res4 = 0; |
64 | |
65 | SEC("raw_tp/sys_enter" ) |
66 | int prog1(void *ctx) |
67 | { |
68 | /* perform some CO-RE relocations to ensure they work with multi-prog |
69 | * sections correctly |
70 | */ |
71 | struct task_struct *t = (void *)bpf_get_current_task(); |
72 | |
73 | if (!BPF_CORE_READ(t, pid) || !get_task_tgid((uintptr_t)t)) |
74 | return 1; |
75 | |
76 | res1 = sub1(1) + sub3(2); /* (1 + 1) + (2 + 3 + (4 + 1)) = 12 */ |
77 | return 0; |
78 | } |
79 | |
80 | SEC("raw_tp/sys_exit" ) |
81 | int prog2(void *ctx) |
82 | { |
83 | struct task_struct *t = (void *)bpf_get_current_task(); |
84 | |
85 | if (!BPF_CORE_READ(t, pid) || !get_task_tgid((uintptr_t)t)) |
86 | return 1; |
87 | |
88 | res2 = sub2(3) + sub3(4); /* (3 + 2) + (4 + 3 + (4 + 1)) = 17 */ |
89 | return 0; |
90 | } |
91 | |
92 | static int empty_callback(__u32 index, void *data) |
93 | { |
94 | return 0; |
95 | } |
96 | |
97 | /* prog3 has the same section name as prog1 */ |
98 | SEC("raw_tp/sys_enter" ) |
99 | int prog3(void *ctx) |
100 | { |
101 | struct task_struct *t = (void *)bpf_get_current_task(); |
102 | |
103 | if (!BPF_CORE_READ(t, pid) || !get_task_tgid((uintptr_t)t)) |
104 | return 1; |
105 | |
106 | /* test that ld_imm64 with BPF_PSEUDO_FUNC doesn't get blinded */ |
107 | bpf_loop(1, empty_callback, NULL, 0); |
108 | |
109 | res3 = sub3(5) + 6; /* (5 + 3 + (4 + 1)) + 6 = 19 */ |
110 | return 0; |
111 | } |
112 | |
113 | /* prog4 has the same section name as prog2 */ |
114 | SEC("raw_tp/sys_exit" ) |
115 | int prog4(void *ctx) |
116 | { |
117 | struct task_struct *t = (void *)bpf_get_current_task(); |
118 | |
119 | if (!BPF_CORE_READ(t, pid) || !get_task_tgid((uintptr_t)t)) |
120 | return 1; |
121 | |
122 | res4 = sub4(7) + sub1(8); /* (7 + (5 + 3 + (4 + 1)) + (6 + 1)) + (8 + 1) = 36 */ |
123 | return 0; |
124 | } |
125 | |