1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Facebook */
3 
4 #include <errno.h>
5 #include <string.h>
6 #include <linux/bpf.h>
7 #include <bpf/bpf_helpers.h>
8 #include "bpf_misc.h"
9 
10 char _license[] SEC("license") = "GPL";
11 
12 #define ITER_HELPERS						\
13 	  __imm(bpf_iter_num_new),				\
14 	  __imm(bpf_iter_num_next),				\
15 	  __imm(bpf_iter_num_destroy)
16 
17 SEC("?raw_tp")
18 __success
force_clang_to_emit_btf_for_externs(void * ctx)19 int force_clang_to_emit_btf_for_externs(void *ctx)
20 {
21 	/* we need this as a workaround to enforce compiler emitting BTF
22 	 * information for bpf_iter_num_{new,next,destroy}() kfuncs,
23 	 * as, apparently, it doesn't emit it for symbols only referenced from
24 	 * assembly (or cleanup attribute, for that matter, as well)
25 	 */
26 	bpf_repeat(0);
27 
28 	return 0;
29 }
30 
31 SEC("?raw_tp")
32 __success __log_level(2)
33 __msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")
create_and_destroy(void * ctx)34 int create_and_destroy(void *ctx)
35 {
36 	struct bpf_iter_num iter;
37 
38 	asm volatile (
39 		/* create iterator */
40 		"r1 = %[iter];"
41 		"r2 = 0;"
42 		"r3 = 1000;"
43 		"call %[bpf_iter_num_new];"
44 		/* destroy iterator */
45 		"r1 = %[iter];"
46 		"call %[bpf_iter_num_destroy];"
47 		:
48 		: __imm_ptr(iter), ITER_HELPERS
49 		: __clobber_common
50 	);
51 
52 	return 0;
53 }
54 
55 SEC("?raw_tp")
56 __failure __msg("Unreleased reference id=1")
create_and_forget_to_destroy_fail(void * ctx)57 int create_and_forget_to_destroy_fail(void *ctx)
58 {
59 	struct bpf_iter_num iter;
60 
61 	asm volatile (
62 		/* create iterator */
63 		"r1 = %[iter];"
64 		"r2 = 0;"
65 		"r3 = 1000;"
66 		"call %[bpf_iter_num_new];"
67 		:
68 		: __imm_ptr(iter), ITER_HELPERS
69 		: __clobber_common
70 	);
71 
72 	return 0;
73 }
74 
75 SEC("?raw_tp")
76 __failure __msg("expected an initialized iter_num as arg #1")
destroy_without_creating_fail(void * ctx)77 int destroy_without_creating_fail(void *ctx)
78 {
79 	/* init with zeros to stop verifier complaining about uninit stack */
80 	struct bpf_iter_num iter;
81 
82 	asm volatile (
83 		"r1 = %[iter];"
84 		"call %[bpf_iter_num_destroy];"
85 		:
86 		: __imm_ptr(iter), ITER_HELPERS
87 		: __clobber_common
88 	);
89 
90 	return 0;
91 }
92 
93 SEC("?raw_tp")
94 __failure __msg("expected an initialized iter_num as arg #1")
compromise_iter_w_direct_write_fail(void * ctx)95 int compromise_iter_w_direct_write_fail(void *ctx)
96 {
97 	struct bpf_iter_num iter;
98 
99 	asm volatile (
100 		/* create iterator */
101 		"r1 = %[iter];"
102 		"r2 = 0;"
103 		"r3 = 1000;"
104 		"call %[bpf_iter_num_new];"
105 
106 		/* directly write over first half of iter state */
107 		"*(u64 *)(%[iter] + 0) = r0;"
108 
109 		/* (attempt to) destroy iterator */
110 		"r1 = %[iter];"
111 		"call %[bpf_iter_num_destroy];"
112 		:
113 		: __imm_ptr(iter), ITER_HELPERS
114 		: __clobber_common
115 	);
116 
117 	return 0;
118 }
119 
120 SEC("?raw_tp")
121 __failure __msg("Unreleased reference id=1")
compromise_iter_w_direct_write_and_skip_destroy_fail(void * ctx)122 int compromise_iter_w_direct_write_and_skip_destroy_fail(void *ctx)
123 {
124 	struct bpf_iter_num iter;
125 
126 	asm volatile (
127 		/* create iterator */
128 		"r1 = %[iter];"
129 		"r2 = 0;"
130 		"r3 = 1000;"
131 		"call %[bpf_iter_num_new];"
132 
133 		/* directly write over first half of iter state */
134 		"*(u64 *)(%[iter] + 0) = r0;"
135 
136 		/* don't destroy iter, leaking ref, which should fail */
137 		:
138 		: __imm_ptr(iter), ITER_HELPERS
139 		: __clobber_common
140 	);
141 
142 	return 0;
143 }
144 
145 SEC("?raw_tp")
146 __failure __msg("expected an initialized iter_num as arg #1")
compromise_iter_w_helper_write_fail(void * ctx)147 int compromise_iter_w_helper_write_fail(void *ctx)
148 {
149 	struct bpf_iter_num iter;
150 
151 	asm volatile (
152 		/* create iterator */
153 		"r1 = %[iter];"
154 		"r2 = 0;"
155 		"r3 = 1000;"
156 		"call %[bpf_iter_num_new];"
157 
158 		/* overwrite 8th byte with bpf_probe_read_kernel() */
159 		"r1 = %[iter];"
160 		"r1 += 7;"
161 		"r2 = 1;"
162 		"r3 = 0;" /* NULL */
163 		"call %[bpf_probe_read_kernel];"
164 
165 		/* (attempt to) destroy iterator */
166 		"r1 = %[iter];"
167 		"call %[bpf_iter_num_destroy];"
168 		:
169 		: __imm_ptr(iter), ITER_HELPERS, __imm(bpf_probe_read_kernel)
170 		: __clobber_common
171 	);
172 
173 	return 0;
174 }
175 
subprog_with_iter(void)176 static __noinline void subprog_with_iter(void)
177 {
178 	struct bpf_iter_num iter;
179 
180 	bpf_iter_num_new(&iter, 0, 1);
181 
182 	return;
183 }
184 
185 SEC("?raw_tp")
186 __failure
187 /* ensure there was a call to subprog, which might happen without __noinline */
188 __msg("returning from callee:")
189 __msg("Unreleased reference id=1")
leak_iter_from_subprog_fail(void * ctx)190 int leak_iter_from_subprog_fail(void *ctx)
191 {
192 	subprog_with_iter();
193 
194 	return 0;
195 }
196 
197 SEC("?raw_tp")
198 __success __log_level(2)
199 __msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")
valid_stack_reuse(void * ctx)200 int valid_stack_reuse(void *ctx)
201 {
202 	struct bpf_iter_num iter;
203 
204 	asm volatile (
205 		/* create iterator */
206 		"r1 = %[iter];"
207 		"r2 = 0;"
208 		"r3 = 1000;"
209 		"call %[bpf_iter_num_new];"
210 		/* destroy iterator */
211 		"r1 = %[iter];"
212 		"call %[bpf_iter_num_destroy];"
213 
214 		/* now reuse same stack slots */
215 
216 		/* create iterator */
217 		"r1 = %[iter];"
218 		"r2 = 0;"
219 		"r3 = 1000;"
220 		"call %[bpf_iter_num_new];"
221 		/* destroy iterator */
222 		"r1 = %[iter];"
223 		"call %[bpf_iter_num_destroy];"
224 		:
225 		: __imm_ptr(iter), ITER_HELPERS
226 		: __clobber_common
227 	);
228 
229 	return 0;
230 }
231 
232 SEC("?raw_tp")
233 __failure __msg("expected uninitialized iter_num as arg #1")
double_create_fail(void * ctx)234 int double_create_fail(void *ctx)
235 {
236 	struct bpf_iter_num iter;
237 
238 	asm volatile (
239 		/* create iterator */
240 		"r1 = %[iter];"
241 		"r2 = 0;"
242 		"r3 = 1000;"
243 		"call %[bpf_iter_num_new];"
244 		/* (attempt to) create iterator again */
245 		"r1 = %[iter];"
246 		"r2 = 0;"
247 		"r3 = 1000;"
248 		"call %[bpf_iter_num_new];"
249 		/* destroy iterator */
250 		"r1 = %[iter];"
251 		"call %[bpf_iter_num_destroy];"
252 		:
253 		: __imm_ptr(iter), ITER_HELPERS
254 		: __clobber_common
255 	);
256 
257 	return 0;
258 }
259 
260 SEC("?raw_tp")
261 __failure __msg("expected an initialized iter_num as arg #1")
double_destroy_fail(void * ctx)262 int double_destroy_fail(void *ctx)
263 {
264 	struct bpf_iter_num iter;
265 
266 	asm volatile (
267 		/* create iterator */
268 		"r1 = %[iter];"
269 		"r2 = 0;"
270 		"r3 = 1000;"
271 		"call %[bpf_iter_num_new];"
272 		/* destroy iterator */
273 		"r1 = %[iter];"
274 		"call %[bpf_iter_num_destroy];"
275 		/* (attempt to) destroy iterator again */
276 		"r1 = %[iter];"
277 		"call %[bpf_iter_num_destroy];"
278 		:
279 		: __imm_ptr(iter), ITER_HELPERS
280 		: __clobber_common
281 	);
282 
283 	return 0;
284 }
285 
286 SEC("?raw_tp")
287 __failure __msg("expected an initialized iter_num as arg #1")
next_without_new_fail(void * ctx)288 int next_without_new_fail(void *ctx)
289 {
290 	struct bpf_iter_num iter;
291 
292 	asm volatile (
293 		/* don't create iterator and try to iterate*/
294 		"r1 = %[iter];"
295 		"call %[bpf_iter_num_next];"
296 		/* destroy iterator */
297 		"r1 = %[iter];"
298 		"call %[bpf_iter_num_destroy];"
299 		:
300 		: __imm_ptr(iter), ITER_HELPERS
301 		: __clobber_common
302 	);
303 
304 	return 0;
305 }
306 
307 SEC("?raw_tp")
308 __failure __msg("expected an initialized iter_num as arg #1")
next_after_destroy_fail(void * ctx)309 int next_after_destroy_fail(void *ctx)
310 {
311 	struct bpf_iter_num iter;
312 
313 	asm volatile (
314 		/* create iterator */
315 		"r1 = %[iter];"
316 		"r2 = 0;"
317 		"r3 = 1000;"
318 		"call %[bpf_iter_num_new];"
319 		/* destroy iterator */
320 		"r1 = %[iter];"
321 		"call %[bpf_iter_num_destroy];"
322 		/* don't create iterator and try to iterate*/
323 		"r1 = %[iter];"
324 		"call %[bpf_iter_num_next];"
325 		:
326 		: __imm_ptr(iter), ITER_HELPERS
327 		: __clobber_common
328 	);
329 
330 	return 0;
331 }
332 
333 SEC("?raw_tp")
334 __failure __msg("invalid read from stack")
read_from_iter_slot_fail(void)335 int __naked read_from_iter_slot_fail(void)
336 {
337 	asm volatile (
338 		/* r6 points to struct bpf_iter_num on the stack */
339 		"r6 = r10;"
340 		"r6 += -24;"
341 
342 		/* create iterator */
343 		"r1 = r6;"
344 		"r2 = 0;"
345 		"r3 = 1000;"
346 		"call %[bpf_iter_num_new];"
347 
348 		/* attemp to leak bpf_iter_num state */
349 		"r7 = *(u64 *)(r6 + 0);"
350 		"r8 = *(u64 *)(r6 + 8);"
351 
352 		/* destroy iterator */
353 		"r1 = r6;"
354 		"call %[bpf_iter_num_destroy];"
355 
356 		/* leak bpf_iter_num state */
357 		"r0 = r7;"
358 		"if r7 > r8 goto +1;"
359 		"r0 = r8;"
360 		"exit;"
361 		:
362 		: ITER_HELPERS
363 		: __clobber_common, "r6", "r7", "r8"
364 	);
365 }
366 
367 int zero;
368 
369 SEC("?raw_tp")
370 __failure
__flag(BPF_F_TEST_STATE_FREQ)371 __flag(BPF_F_TEST_STATE_FREQ)
372 __msg("Unreleased reference")
373 int stacksafe_should_not_conflate_stack_spill_and_iter(void *ctx)
374 {
375 	struct bpf_iter_num iter;
376 
377 	asm volatile (
378 		/* Create a fork in logic, with general setup as follows:
379 		 *   - fallthrough (first) path is valid;
380 		 *   - branch (second) path is invalid.
381 		 * Then depending on what we do in fallthrough vs branch path,
382 		 * we try to detect bugs in func_states_equal(), regsafe(),
383 		 * refsafe(), stack_safe(), and similar by tricking verifier
384 		 * into believing that branch state is a valid subset of
385 		 * a fallthrough state. Verifier should reject overall
386 		 * validation, unless there is a bug somewhere in verifier
387 		 * logic.
388 		 */
389 		"call %[bpf_get_prandom_u32];"
390 		"r6 = r0;"
391 		"call %[bpf_get_prandom_u32];"
392 		"r7 = r0;"
393 
394 		"if r6 > r7 goto bad;" /* fork */
395 
396 		/* spill r6 into stack slot of bpf_iter_num var */
397 		"*(u64 *)(%[iter] + 0) = r6;"
398 
399 		"goto skip_bad;"
400 
401 	"bad:"
402 		/* create iterator in the same stack slot */
403 		"r1 = %[iter];"
404 		"r2 = 0;"
405 		"r3 = 1000;"
406 		"call %[bpf_iter_num_new];"
407 
408 		/* but then forget about it and overwrite it back to r6 spill */
409 		"*(u64 *)(%[iter] + 0) = r6;"
410 
411 	"skip_bad:"
412 		"goto +0;" /* force checkpoint */
413 
414 		/* corrupt stack slots, if they are really dynptr */
415 		"*(u64 *)(%[iter] + 0) = r6;"
416 		:
417 		: __imm_ptr(iter),
418 		  __imm_addr(zero),
419 		  __imm(bpf_get_prandom_u32),
420 		  __imm(bpf_dynptr_from_mem),
421 		  ITER_HELPERS
422 		: __clobber_common, "r6", "r7"
423 	);
424 
425 	return 0;
426 }
427