xref: /linux/tools/testing/selftests/bpf/progs/verifier_private_stack.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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)")
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")
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
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")
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
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")
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")
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 
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")
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;
194 __noinline static void subprog2(int *val)
195 {
196 	glob += val[0] * 2;
197 }
198 
199 __noinline static void subprog1(int *val)
200 {
201 	int tmp[64] = {};
202 
203 	tmp[0] = *val;
204 	subprog2(tmp);
205 }
206 
207 __noinline static int timer_cb1(void *map, int *key, struct bpf_timer *timer)
208 {
209 	subprog1(key);
210 	return 0;
211 }
212 
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")
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")
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
265 int dummy_test(void)
266 {
267 	return 0;
268 }
269 
270 #endif
271 
272 char _license[] SEC("license") = "GPL";
273