1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/spin_lock.c */
5 #include <bpf/bpf_helpers.h>
10 struct bpf_spin_lock l;
14 __uint(type, BPF_MAP_TYPE_ARRAY);
15 __uint(max_entries, 1);
17 __type(value, struct val);
18 } map_spin_lock SEC(".maps");
21 __description("spin_lock: test1 success")
22 __success __failure_unpriv __msg_unpriv("")
24 __naked void spin_lock_test1_success(void)
28 *(u32*)(r10 - 4) = r1; \
31 r1 = %[map_spin_lock] ll; \
32 call %[bpf_map_lookup_elem]; \
33 if r0 != 0 goto l0_%=; \
38 call %[bpf_spin_lock]; \
41 r0 = *(u32*)(r6 + 0); \
42 call %[bpf_spin_unlock]; \
46 : __imm(bpf_map_lookup_elem),
48 __imm(bpf_spin_unlock),
49 __imm_addr(map_spin_lock)
54 __description("spin_lock: test2 direct ld/st")
55 __failure __msg("cannot be accessed directly")
56 __failure_unpriv __msg_unpriv("")
57 __naked void lock_test2_direct_ld_st(void)
61 *(u32*)(r10 - 4) = r1; \
64 r1 = %[map_spin_lock] ll; \
65 call %[bpf_map_lookup_elem]; \
66 if r0 != 0 goto l0_%=; \
71 call %[bpf_spin_lock]; \
74 r0 = *(u32*)(r1 + 0); \
75 call %[bpf_spin_unlock]; \
79 : __imm(bpf_map_lookup_elem),
81 __imm(bpf_spin_unlock),
82 __imm_addr(map_spin_lock)
87 __description("spin_lock: test3 direct ld/st")
88 __failure __msg("cannot be accessed directly")
89 __failure_unpriv __msg_unpriv("")
90 __flag(BPF_F_ANY_ALIGNMENT)
91 __naked void lock_test3_direct_ld_st(void)
95 *(u32*)(r10 - 4) = r1; \
98 r1 = %[map_spin_lock] ll; \
99 call %[bpf_map_lookup_elem]; \
100 if r0 != 0 goto l0_%=; \
105 call %[bpf_spin_lock]; \
108 r0 = *(u32*)(r6 + 1); \
109 call %[bpf_spin_unlock]; \
113 : __imm(bpf_map_lookup_elem),
114 __imm(bpf_spin_lock),
115 __imm(bpf_spin_unlock),
116 __imm_addr(map_spin_lock)
121 __description("spin_lock: test4 direct ld/st")
122 __failure __msg("cannot be accessed directly")
123 __failure_unpriv __msg_unpriv("")
124 __flag(BPF_F_ANY_ALIGNMENT)
125 __naked void lock_test4_direct_ld_st(void)
129 *(u32*)(r10 - 4) = r1; \
132 r1 = %[map_spin_lock] ll; \
133 call %[bpf_map_lookup_elem]; \
134 if r0 != 0 goto l0_%=; \
139 call %[bpf_spin_lock]; \
142 r0 = *(u16*)(r6 + 3); \
143 call %[bpf_spin_unlock]; \
147 : __imm(bpf_map_lookup_elem),
148 __imm(bpf_spin_lock),
149 __imm(bpf_spin_unlock),
150 __imm_addr(map_spin_lock)
155 __description("spin_lock: test5 call within a locked region")
156 __failure __msg("calls are not allowed")
157 __failure_unpriv __msg_unpriv("")
158 __naked void call_within_a_locked_region(void)
162 *(u32*)(r10 - 4) = r1; \
165 r1 = %[map_spin_lock] ll; \
166 call %[bpf_map_lookup_elem]; \
167 if r0 != 0 goto l0_%=; \
172 call %[bpf_spin_lock]; \
173 call %[bpf_get_prandom_u32]; \
176 call %[bpf_spin_unlock]; \
180 : __imm(bpf_get_prandom_u32),
181 __imm(bpf_map_lookup_elem),
182 __imm(bpf_spin_lock),
183 __imm(bpf_spin_unlock),
184 __imm_addr(map_spin_lock)
189 __description("spin_lock: test6 missing unlock")
190 __failure __msg("unlock is missing")
191 __failure_unpriv __msg_unpriv("")
192 __naked void spin_lock_test6_missing_unlock(void)
196 *(u32*)(r10 - 4) = r1; \
199 r1 = %[map_spin_lock] ll; \
200 call %[bpf_map_lookup_elem]; \
201 if r0 != 0 goto l0_%=; \
206 call %[bpf_spin_lock]; \
209 r0 = *(u32*)(r6 + 0); \
210 if r0 != 0 goto l1_%=; \
211 call %[bpf_spin_unlock]; \
215 : __imm(bpf_map_lookup_elem),
216 __imm(bpf_spin_lock),
217 __imm(bpf_spin_unlock),
218 __imm_addr(map_spin_lock)
223 __description("spin_lock: test7 unlock without lock")
224 __failure __msg("without taking a lock")
225 __failure_unpriv __msg_unpriv("")
226 __naked void lock_test7_unlock_without_lock(void)
230 *(u32*)(r10 - 4) = r1; \
233 r1 = %[map_spin_lock] ll; \
234 call %[bpf_map_lookup_elem]; \
235 if r0 != 0 goto l0_%=; \
240 if r1 != 0 goto l1_%=; \
241 call %[bpf_spin_lock]; \
244 r0 = *(u32*)(r6 + 0); \
245 call %[bpf_spin_unlock]; \
249 : __imm(bpf_map_lookup_elem),
250 __imm(bpf_spin_lock),
251 __imm(bpf_spin_unlock),
252 __imm_addr(map_spin_lock)
257 __description("spin_lock: test8 double lock")
258 __failure __msg("calls are not allowed")
259 __failure_unpriv __msg_unpriv("")
260 __naked void spin_lock_test8_double_lock(void)
264 *(u32*)(r10 - 4) = r1; \
267 r1 = %[map_spin_lock] ll; \
268 call %[bpf_map_lookup_elem]; \
269 if r0 != 0 goto l0_%=; \
274 call %[bpf_spin_lock]; \
277 call %[bpf_spin_lock]; \
280 r0 = *(u32*)(r6 + 0); \
281 call %[bpf_spin_unlock]; \
285 : __imm(bpf_map_lookup_elem),
286 __imm(bpf_spin_lock),
287 __imm(bpf_spin_unlock),
288 __imm_addr(map_spin_lock)
293 __description("spin_lock: test9 different lock")
294 __failure __msg("unlock of different lock")
295 __failure_unpriv __msg_unpriv("")
296 __naked void spin_lock_test9_different_lock(void)
300 *(u32*)(r10 - 4) = r1; \
303 r1 = %[map_spin_lock] ll; \
304 call %[bpf_map_lookup_elem]; \
305 if r0 != 0 goto l0_%=; \
310 r1 = %[map_spin_lock] ll; \
311 call %[bpf_map_lookup_elem]; \
312 if r0 != 0 goto l1_%=; \
317 call %[bpf_spin_lock]; \
320 call %[bpf_spin_unlock]; \
324 : __imm(bpf_map_lookup_elem),
325 __imm(bpf_spin_lock),
326 __imm(bpf_spin_unlock),
327 __imm_addr(map_spin_lock)
332 __description("spin_lock: test10 lock in subprog without unlock")
333 __failure __msg("unlock is missing")
334 __failure_unpriv __msg_unpriv("")
335 __naked void lock_in_subprog_without_unlock(void)
339 *(u32*)(r10 - 4) = r1; \
342 r1 = %[map_spin_lock] ll; \
343 call %[bpf_map_lookup_elem]; \
344 if r0 != 0 goto l0_%=; \
349 call lock_in_subprog_without_unlock__1; \
352 call %[bpf_spin_unlock]; \
356 : __imm(bpf_map_lookup_elem),
357 __imm(bpf_spin_unlock),
358 __imm_addr(map_spin_lock)
362 static __naked __noinline __attribute__((used))
363 void lock_in_subprog_without_unlock__1(void)
366 call %[bpf_spin_lock]; \
370 : __imm(bpf_spin_lock)
375 __description("spin_lock: test11 ld_abs under lock")
376 __failure __msg("inside bpf_spin_lock")
377 __naked void test11_ld_abs_under_lock(void)
382 *(u32*)(r10 - 4) = r1; \
385 r1 = %[map_spin_lock] ll; \
386 call %[bpf_map_lookup_elem]; \
387 if r0 != 0 goto l0_%=; \
392 call %[bpf_spin_lock]; \
396 call %[bpf_spin_unlock]; \
400 : __imm(bpf_map_lookup_elem),
401 __imm(bpf_spin_lock),
402 __imm(bpf_spin_unlock),
403 __imm_addr(map_spin_lock)
408 __description("spin_lock: regsafe compare reg->id for map value")
409 __failure __msg("bpf_spin_unlock of different lock")
410 __flag(BPF_F_TEST_STATE_FREQ)
411 __naked void reg_id_for_map_value(void)
415 r6 = *(u32*)(r6 + %[__sk_buff_mark]); \
416 r1 = %[map_spin_lock] ll; \
419 *(u32*)(r10 - 4) = r2; \
422 call %[bpf_map_lookup_elem]; \
423 if r0 != 0 goto l0_%=; \
429 call %[bpf_map_lookup_elem]; \
430 if r0 != 0 goto l1_%=; \
435 call %[bpf_spin_lock]; \
436 if r6 == 0 goto l2_%=; \
441 call %[bpf_spin_unlock]; \
445 : __imm(bpf_map_lookup_elem),
446 __imm(bpf_spin_lock),
447 __imm(bpf_spin_unlock),
448 __imm_addr(map_spin_lock),
449 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
453 /* Make sure that regsafe() compares ids for spin lock records using
455 * 1: r9 = map_lookup_elem(...) ; r9.id == 1
456 * 2: r8 = map_lookup_elem(...) ; r8.id == 2
457 * 3: r7 = ktime_get_ns()
458 * 4: r6 = ktime_get_ns()
459 * 5: if r6 > r7 goto <9>
464 * 10: spin_unlock(r9) ; r9.id == 1 || r9.id == 2 and lock is active,
465 * ; second visit to (10) should be considered safe
466 * ; if check_ids() is used.
471 __description("spin_lock: regsafe() check_ids() similar id mappings")
472 __success __msg("29: safe")
473 __failure_unpriv __msg_unpriv("")
474 __log_level(2) __retval(0) __flag(BPF_F_TEST_STATE_FREQ)
475 __naked void check_ids_similar_id_mappings(void)
479 *(u32*)(r10 - 4) = r1; \
480 /* r9 = map_lookup_elem(...) */ \
483 r1 = %[map_spin_lock] ll; \
484 call %[bpf_map_lookup_elem]; \
485 if r0 == 0 goto l0_%=; \
487 /* r8 = map_lookup_elem(...) */ \
490 r1 = %[map_spin_lock] ll; \
491 call %[bpf_map_lookup_elem]; \
492 if r0 == 0 goto l1_%=; \
494 /* r7 = ktime_get_ns() */ \
495 call %[bpf_ktime_get_ns]; \
497 /* r6 = ktime_get_ns() */ \
498 call %[bpf_ktime_get_ns]; \
500 /* if r6 > r7 goto +5 ; no new information about the state is derived from\
501 * ; this check, thus produced verifier states differ\
502 * ; only in 'insn_idx' \
507 if r6 > r7 goto l2_%=; \
510 call %[bpf_spin_lock]; \
513 l2_%=: /* spin_lock(r9) */ \
516 call %[bpf_spin_lock]; \
517 l3_%=: /* spin_unlock(r9) */ \
520 call %[bpf_spin_unlock]; \
521 l0_%=: /* exit(0) */ \
525 : __imm(bpf_ktime_get_ns),
526 __imm(bpf_map_lookup_elem),
527 __imm(bpf_spin_lock),
528 __imm(bpf_spin_unlock),
529 __imm_addr(map_spin_lock)
533 char _license[] SEC("license") = "GPL";