1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include "bpf_misc.h"
6 #include "bpf_experimental.h"
7
8 /* From include/linux/filter.h */
9 #define MAX_BPF_STACK 512
10
11 #if defined(__TARGET_ARCH_x86)
12
13 struct elem {
14 struct bpf_timer t;
15 char pad[256];
16 };
17
18 struct {
19 __uint(type, BPF_MAP_TYPE_ARRAY);
20 __uint(max_entries, 1);
21 __type(key, int);
22 __type(value, struct elem);
23 } array SEC(".maps");
24
25 SEC("kprobe")
26 __description("Private stack, single prog")
27 __success
28 __arch_x86_64
29 __jited(" movabsq $0x{{.*}}, %r9")
30 __jited(" addq %gs:0x{{.*}}, %r9")
31 __jited(" movl $0x2a, %edi")
32 __jited(" movq %rdi, -0x100(%r9)")
private_stack_single_prog(void)33 __naked void private_stack_single_prog(void)
34 {
35 asm volatile (" \
36 r1 = 42; \
37 *(u64 *)(r10 - 256) = r1; \
38 r0 = 0; \
39 exit; \
40 " ::: __clobber_all);
41 }
42
43 SEC("raw_tp")
44 __description("No private stack")
45 __success
46 __arch_x86_64
47 __jited(" subq $0x8, %rsp")
no_private_stack_nested(void)48 __naked void no_private_stack_nested(void)
49 {
50 asm volatile (" \
51 r1 = 42; \
52 *(u64 *)(r10 - 8) = r1; \
53 r0 = 0; \
54 exit; \
55 " ::: __clobber_all);
56 }
57
58 __used
cumulative_stack_depth_subprog(void)59 __naked static void cumulative_stack_depth_subprog(void)
60 {
61 asm volatile (" \
62 r1 = 41; \
63 *(u64 *)(r10 - 32) = r1; \
64 call %[bpf_get_smp_processor_id]; \
65 exit; \
66 " :
67 : __imm(bpf_get_smp_processor_id)
68 : __clobber_all);
69 }
70
71 SEC("kprobe")
72 __description("Private stack, subtree > MAX_BPF_STACK")
73 __success
74 __arch_x86_64
75 /* private stack fp for the main prog */
76 __jited(" movabsq $0x{{.*}}, %r9")
77 __jited(" addq %gs:0x{{.*}}, %r9")
78 __jited(" movl $0x2a, %edi")
79 __jited(" movq %rdi, -0x200(%r9)")
80 __jited(" pushq %r9")
81 __jited(" callq 0x{{.*}}")
82 __jited(" popq %r9")
83 __jited(" xorl %eax, %eax")
private_stack_nested_1(void)84 __naked void private_stack_nested_1(void)
85 {
86 asm volatile (" \
87 r1 = 42; \
88 *(u64 *)(r10 - %[max_bpf_stack]) = r1; \
89 call cumulative_stack_depth_subprog; \
90 r0 = 0; \
91 exit; \
92 " :
93 : __imm_const(max_bpf_stack, MAX_BPF_STACK)
94 : __clobber_all);
95 }
96
97 __naked __noinline __used
loop_callback(void)98 static unsigned long loop_callback(void)
99 {
100 asm volatile (" \
101 call %[bpf_get_prandom_u32]; \
102 r1 = 42; \
103 *(u64 *)(r10 - 512) = r1; \
104 call cumulative_stack_depth_subprog; \
105 r0 = 0; \
106 exit; \
107 " :
108 : __imm(bpf_get_prandom_u32)
109 : __clobber_common);
110 }
111
112 SEC("raw_tp")
113 __description("Private stack, callback")
114 __success
115 __arch_x86_64
116 /* for func loop_callback */
117 __jited("func #1")
118 __jited(" endbr64")
119 __jited(" nopl (%rax,%rax)")
120 __jited(" nopl (%rax)")
121 __jited(" pushq %rbp")
122 __jited(" movq %rsp, %rbp")
123 __jited(" endbr64")
124 __jited(" movabsq $0x{{.*}}, %r9")
125 __jited(" addq %gs:0x{{.*}}, %r9")
126 __jited(" pushq %r9")
127 __jited(" callq")
128 __jited(" popq %r9")
129 __jited(" movl $0x2a, %edi")
130 __jited(" movq %rdi, -0x200(%r9)")
131 __jited(" pushq %r9")
132 __jited(" callq")
133 __jited(" popq %r9")
private_stack_callback(void)134 __naked void private_stack_callback(void)
135 {
136 asm volatile (" \
137 r1 = 1; \
138 r2 = %[loop_callback]; \
139 r3 = 0; \
140 r4 = 0; \
141 call %[bpf_loop]; \
142 r0 = 0; \
143 exit; \
144 " :
145 : __imm_ptr(loop_callback),
146 __imm(bpf_loop)
147 : __clobber_common);
148 }
149
150 SEC("fentry/bpf_fentry_test9")
151 __description("Private stack, exception in main prog")
152 __success __retval(0)
153 __arch_x86_64
154 __jited(" pushq %r9")
155 __jited(" callq")
156 __jited(" popq %r9")
private_stack_exception_main_prog(void)157 int private_stack_exception_main_prog(void)
158 {
159 asm volatile (" \
160 r1 = 42; \
161 *(u64 *)(r10 - 512) = r1; \
162 " ::: __clobber_common);
163
164 bpf_throw(0);
165 return 0;
166 }
167
subprog_exception(void)168 __used static int subprog_exception(void)
169 {
170 bpf_throw(0);
171 return 0;
172 }
173
174 SEC("fentry/bpf_fentry_test9")
175 __description("Private stack, exception in subprog")
176 __success __retval(0)
177 __arch_x86_64
178 __jited(" movq %rdi, -0x200(%r9)")
179 __jited(" pushq %r9")
180 __jited(" callq")
181 __jited(" popq %r9")
private_stack_exception_sub_prog(void)182 int private_stack_exception_sub_prog(void)
183 {
184 asm volatile (" \
185 r1 = 42; \
186 *(u64 *)(r10 - 512) = r1; \
187 call subprog_exception; \
188 " ::: __clobber_common);
189
190 return 0;
191 }
192
193 int glob;
subprog2(int * val)194 __noinline static void subprog2(int *val)
195 {
196 glob += val[0] * 2;
197 }
198
subprog1(int * val)199 __noinline static void subprog1(int *val)
200 {
201 int tmp[64] = {};
202
203 tmp[0] = *val;
204 subprog2(tmp);
205 }
206
timer_cb1(void * map,int * key,struct bpf_timer * timer)207 __noinline static int timer_cb1(void *map, int *key, struct bpf_timer *timer)
208 {
209 subprog1(key);
210 return 0;
211 }
212
timer_cb2(void * map,int * key,struct bpf_timer * timer)213 __noinline static int timer_cb2(void *map, int *key, struct bpf_timer *timer)
214 {
215 return 0;
216 }
217
218 SEC("fentry/bpf_fentry_test9")
219 __description("Private stack, async callback, not nested")
220 __success __retval(0)
221 __arch_x86_64
222 __jited(" movabsq $0x{{.*}}, %r9")
private_stack_async_callback_1(void)223 int private_stack_async_callback_1(void)
224 {
225 struct bpf_timer *arr_timer;
226 int array_key = 0;
227
228 arr_timer = bpf_map_lookup_elem(&array, &array_key);
229 if (!arr_timer)
230 return 0;
231
232 bpf_timer_init(arr_timer, &array, 1);
233 bpf_timer_set_callback(arr_timer, timer_cb2);
234 bpf_timer_start(arr_timer, 0, 0);
235 subprog1(&array_key);
236 return 0;
237 }
238
239 SEC("fentry/bpf_fentry_test9")
240 __description("Private stack, async callback, potential nesting")
241 __success __retval(0)
242 __arch_x86_64
243 __jited(" subq $0x100, %rsp")
private_stack_async_callback_2(void)244 int private_stack_async_callback_2(void)
245 {
246 struct bpf_timer *arr_timer;
247 int array_key = 0;
248
249 arr_timer = bpf_map_lookup_elem(&array, &array_key);
250 if (!arr_timer)
251 return 0;
252
253 bpf_timer_init(arr_timer, &array, 1);
254 bpf_timer_set_callback(arr_timer, timer_cb1);
255 bpf_timer_start(arr_timer, 0, 0);
256 subprog1(&array_key);
257 return 0;
258 }
259
260 #else
261
262 SEC("kprobe")
263 __description("private stack is not supported, use a dummy test")
264 __success
dummy_test(void)265 int dummy_test(void)
266 {
267 return 0;
268 }
269
270 #endif
271
272 char _license[] SEC("license") = "GPL";
273