1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Facebook */
7 #include <bpf/bpf_helpers.h>
10 char _license[] SEC("license") = "GPL";
12 #define ITER_HELPERS \
13 __imm(bpf_iter_num_new), \
14 __imm(bpf_iter_num_next), \
15 __imm(bpf_iter_num_destroy)
19 int force_clang_to_emit_btf_for_externs(void *ctx)
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)
32 __success __log_level(2)
33 __msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")
34 int create_and_destroy(void *ctx)
36 struct bpf_iter_num iter;
43 "call %[bpf_iter_num_new];"
44 /* destroy iterator */
46 "call %[bpf_iter_num_destroy];"
48 : __imm_ptr(iter), ITER_HELPERS
56 __failure __msg("Unreleased reference id=1")
57 int create_and_forget_to_destroy_fail(void *ctx)
59 struct bpf_iter_num iter;
66 "call %[bpf_iter_num_new];"
68 : __imm_ptr(iter), ITER_HELPERS
76 __failure __msg("expected an initialized iter_num as arg #1")
77 int destroy_without_creating_fail(void *ctx)
79 /* init with zeros to stop verifier complaining about uninit stack */
80 struct bpf_iter_num iter;
84 "call %[bpf_iter_num_destroy];"
86 : __imm_ptr(iter), ITER_HELPERS
94 __failure __msg("expected an initialized iter_num as arg #1")
95 int compromise_iter_w_direct_write_fail(void *ctx)
97 struct bpf_iter_num iter;
100 /* create iterator */
104 "call %[bpf_iter_num_new];"
106 /* directly write over first half of iter state */
107 "*(u64 *)(%[iter] + 0) = r0;"
109 /* (attempt to) destroy iterator */
111 "call %[bpf_iter_num_destroy];"
113 : __imm_ptr(iter), ITER_HELPERS
121 __failure __msg("Unreleased reference id=1")
122 int compromise_iter_w_direct_write_and_skip_destroy_fail(void *ctx)
124 struct bpf_iter_num iter;
127 /* create iterator */
131 "call %[bpf_iter_num_new];"
133 /* directly write over first half of iter state */
134 "*(u64 *)(%[iter] + 0) = r0;"
136 /* don't destroy iter, leaking ref, which should fail */
138 : __imm_ptr(iter), ITER_HELPERS
146 __failure __msg("expected an initialized iter_num as arg #1")
147 int compromise_iter_w_helper_write_fail(void *ctx)
149 struct bpf_iter_num iter;
152 /* create iterator */
156 "call %[bpf_iter_num_new];"
158 /* overwrite 8th byte with bpf_probe_read_kernel() */
163 "call %[bpf_probe_read_kernel];"
165 /* (attempt to) destroy iterator */
167 "call %[bpf_iter_num_destroy];"
169 : __imm_ptr(iter), ITER_HELPERS, __imm(bpf_probe_read_kernel)
176 static __noinline void subprog_with_iter(void)
178 struct bpf_iter_num iter;
180 bpf_iter_num_new(&iter, 0, 1);
187 /* ensure there was a call to subprog, which might happen without __noinline */
188 __msg("returning from callee:")
189 __msg("Unreleased reference id=1")
190 int leak_iter_from_subprog_fail(void *ctx)
198 __success __log_level(2)
199 __msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")
200 int valid_stack_reuse(void *ctx)
202 struct bpf_iter_num iter;
205 /* create iterator */
209 "call %[bpf_iter_num_new];"
210 /* destroy iterator */
212 "call %[bpf_iter_num_destroy];"
214 /* now reuse same stack slots */
216 /* create iterator */
220 "call %[bpf_iter_num_new];"
221 /* destroy iterator */
223 "call %[bpf_iter_num_destroy];"
225 : __imm_ptr(iter), ITER_HELPERS
233 __failure __msg("expected uninitialized iter_num as arg #1")
234 int double_create_fail(void *ctx)
236 struct bpf_iter_num iter;
239 /* create iterator */
243 "call %[bpf_iter_num_new];"
244 /* (attempt to) create iterator again */
248 "call %[bpf_iter_num_new];"
249 /* destroy iterator */
251 "call %[bpf_iter_num_destroy];"
253 : __imm_ptr(iter), ITER_HELPERS
261 __failure __msg("expected an initialized iter_num as arg #1")
262 int double_destroy_fail(void *ctx)
264 struct bpf_iter_num iter;
267 /* create iterator */
271 "call %[bpf_iter_num_new];"
272 /* destroy iterator */
274 "call %[bpf_iter_num_destroy];"
275 /* (attempt to) destroy iterator again */
277 "call %[bpf_iter_num_destroy];"
279 : __imm_ptr(iter), ITER_HELPERS
287 __failure __msg("expected an initialized iter_num as arg #1")
288 int next_without_new_fail(void *ctx)
290 struct bpf_iter_num iter;
293 /* don't create iterator and try to iterate*/
295 "call %[bpf_iter_num_next];"
296 /* destroy iterator */
298 "call %[bpf_iter_num_destroy];"
300 : __imm_ptr(iter), ITER_HELPERS
308 __failure __msg("expected an initialized iter_num as arg #1")
309 int next_after_destroy_fail(void *ctx)
311 struct bpf_iter_num iter;
314 /* create iterator */
318 "call %[bpf_iter_num_new];"
319 /* destroy iterator */
321 "call %[bpf_iter_num_destroy];"
322 /* don't create iterator and try to iterate*/
324 "call %[bpf_iter_num_next];"
326 : __imm_ptr(iter), ITER_HELPERS
334 __failure __msg("invalid read from stack")
335 int __naked read_from_iter_slot_fail(void)
338 /* r6 points to struct bpf_iter_num on the stack */
342 /* create iterator */
346 "call %[bpf_iter_num_new];"
348 /* attemp to leak bpf_iter_num state */
349 "r7 = *(u64 *)(r6 + 0);"
350 "r8 = *(u64 *)(r6 + 8);"
352 /* destroy iterator */
354 "call %[bpf_iter_num_destroy];"
356 /* leak bpf_iter_num state */
358 "if r7 > r8 goto +1;"
363 : __clobber_common, "r6", "r7", "r8"
371 __flag(BPF_F_TEST_STATE_FREQ)
372 __msg("Unreleased reference")
373 int stacksafe_should_not_conflate_stack_spill_and_iter(void *ctx)
375 struct bpf_iter_num iter;
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
389 "call %[bpf_get_prandom_u32];"
391 "call %[bpf_get_prandom_u32];"
394 "if r6 > r7 goto bad;" /* fork */
396 /* spill r6 into stack slot of bpf_iter_num var */
397 "*(u64 *)(%[iter] + 0) = r6;"
402 /* create iterator in the same stack slot */
406 "call %[bpf_iter_num_new];"
408 /* but then forget about it and overwrite it back to r6 spill */
409 "*(u64 *)(%[iter] + 0) = r6;"
412 "goto +0;" /* force checkpoint */
414 /* corrupt stack slots, if they are really dynptr */
415 "*(u64 *)(%[iter] + 0) = r6;"
419 __imm(bpf_get_prandom_u32),
420 __imm(bpf_dynptr_from_mem),
422 : __clobber_common, "r6", "r7"