534 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Converted from tools/testing/selftests/bpf/verifier/spin_lock.c */3 4#include <linux/bpf.h>5#include <bpf/bpf_helpers.h>6#include "bpf_misc.h"7 8struct val {9 int cnt;10 struct bpf_spin_lock l;11};12 13struct {14 __uint(type, BPF_MAP_TYPE_ARRAY);15 __uint(max_entries, 1);16 __type(key, int);17 __type(value, struct val);18} map_spin_lock SEC(".maps");19 20SEC("cgroup/skb")21__description("spin_lock: test1 success")22__success __failure_unpriv __msg_unpriv("")23__retval(0)24__naked void spin_lock_test1_success(void)25{26 asm volatile (" \27 r1 = 0; \28 *(u32*)(r10 - 4) = r1; \29 r2 = r10; \30 r2 += -4; \31 r1 = %[map_spin_lock] ll; \32 call %[bpf_map_lookup_elem]; \33 if r0 != 0 goto l0_%=; \34 exit; \35l0_%=: r6 = r0; \36 r1 = r0; \37 r1 += 4; \38 call %[bpf_spin_lock]; \39 r1 = r6; \40 r1 += 4; \41 r0 = *(u32*)(r6 + 0); \42 call %[bpf_spin_unlock]; \43 r0 = 0; \44 exit; \45" :46 : __imm(bpf_map_lookup_elem),47 __imm(bpf_spin_lock),48 __imm(bpf_spin_unlock),49 __imm_addr(map_spin_lock)50 : __clobber_all);51}52 53SEC("cgroup/skb")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)58{59 asm volatile (" \60 r1 = 0; \61 *(u32*)(r10 - 4) = r1; \62 r2 = r10; \63 r2 += -4; \64 r1 = %[map_spin_lock] ll; \65 call %[bpf_map_lookup_elem]; \66 if r0 != 0 goto l0_%=; \67 exit; \68l0_%=: r6 = r0; \69 r1 = r0; \70 r1 += 4; \71 call %[bpf_spin_lock]; \72 r1 = r6; \73 r1 += 4; \74 r0 = *(u32*)(r1 + 0); \75 call %[bpf_spin_unlock]; \76 r0 = 0; \77 exit; \78" :79 : __imm(bpf_map_lookup_elem),80 __imm(bpf_spin_lock),81 __imm(bpf_spin_unlock),82 __imm_addr(map_spin_lock)83 : __clobber_all);84}85 86SEC("cgroup/skb")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)92{93 asm volatile (" \94 r1 = 0; \95 *(u32*)(r10 - 4) = r1; \96 r2 = r10; \97 r2 += -4; \98 r1 = %[map_spin_lock] ll; \99 call %[bpf_map_lookup_elem]; \100 if r0 != 0 goto l0_%=; \101 exit; \102l0_%=: r6 = r0; \103 r1 = r0; \104 r1 += 4; \105 call %[bpf_spin_lock]; \106 r1 = r6; \107 r1 += 4; \108 r0 = *(u32*)(r6 + 1); \109 call %[bpf_spin_unlock]; \110 r0 = 0; \111 exit; \112" :113 : __imm(bpf_map_lookup_elem),114 __imm(bpf_spin_lock),115 __imm(bpf_spin_unlock),116 __imm_addr(map_spin_lock)117 : __clobber_all);118}119 120SEC("cgroup/skb")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)126{127 asm volatile (" \128 r1 = 0; \129 *(u32*)(r10 - 4) = r1; \130 r2 = r10; \131 r2 += -4; \132 r1 = %[map_spin_lock] ll; \133 call %[bpf_map_lookup_elem]; \134 if r0 != 0 goto l0_%=; \135 exit; \136l0_%=: r6 = r0; \137 r1 = r0; \138 r1 += 4; \139 call %[bpf_spin_lock]; \140 r1 = r6; \141 r1 += 4; \142 r0 = *(u16*)(r6 + 3); \143 call %[bpf_spin_unlock]; \144 r0 = 0; \145 exit; \146" :147 : __imm(bpf_map_lookup_elem),148 __imm(bpf_spin_lock),149 __imm(bpf_spin_unlock),150 __imm_addr(map_spin_lock)151 : __clobber_all);152}153 154SEC("cgroup/skb")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)159{160 asm volatile (" \161 r1 = 0; \162 *(u32*)(r10 - 4) = r1; \163 r2 = r10; \164 r2 += -4; \165 r1 = %[map_spin_lock] ll; \166 call %[bpf_map_lookup_elem]; \167 if r0 != 0 goto l0_%=; \168 exit; \169l0_%=: r6 = r0; \170 r1 = r0; \171 r1 += 4; \172 call %[bpf_spin_lock]; \173 call %[bpf_get_prandom_u32]; \174 r1 = r6; \175 r1 += 4; \176 call %[bpf_spin_unlock]; \177 r0 = 0; \178 exit; \179" :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)185 : __clobber_all);186}187 188SEC("cgroup/skb")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)193{194 asm volatile (" \195 r1 = 0; \196 *(u32*)(r10 - 4) = r1; \197 r2 = r10; \198 r2 += -4; \199 r1 = %[map_spin_lock] ll; \200 call %[bpf_map_lookup_elem]; \201 if r0 != 0 goto l0_%=; \202 exit; \203l0_%=: r6 = r0; \204 r1 = r0; \205 r1 += 4; \206 call %[bpf_spin_lock]; \207 r1 = r6; \208 r1 += 4; \209 r0 = *(u32*)(r6 + 0); \210 if r0 != 0 goto l1_%=; \211 call %[bpf_spin_unlock]; \212l1_%=: r0 = 0; \213 exit; \214" :215 : __imm(bpf_map_lookup_elem),216 __imm(bpf_spin_lock),217 __imm(bpf_spin_unlock),218 __imm_addr(map_spin_lock)219 : __clobber_all);220}221 222SEC("cgroup/skb")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)227{228 asm volatile (" \229 r1 = 0; \230 *(u32*)(r10 - 4) = r1; \231 r2 = r10; \232 r2 += -4; \233 r1 = %[map_spin_lock] ll; \234 call %[bpf_map_lookup_elem]; \235 if r0 != 0 goto l0_%=; \236 exit; \237l0_%=: r6 = r0; \238 r1 = r0; \239 r1 += 4; \240 if r1 != 0 goto l1_%=; \241 call %[bpf_spin_lock]; \242l1_%=: r1 = r6; \243 r1 += 4; \244 r0 = *(u32*)(r6 + 0); \245 call %[bpf_spin_unlock]; \246 r0 = 0; \247 exit; \248" :249 : __imm(bpf_map_lookup_elem),250 __imm(bpf_spin_lock),251 __imm(bpf_spin_unlock),252 __imm_addr(map_spin_lock)253 : __clobber_all);254}255 256SEC("cgroup/skb")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)261{262 asm volatile (" \263 r1 = 0; \264 *(u32*)(r10 - 4) = r1; \265 r2 = r10; \266 r2 += -4; \267 r1 = %[map_spin_lock] ll; \268 call %[bpf_map_lookup_elem]; \269 if r0 != 0 goto l0_%=; \270 exit; \271l0_%=: r6 = r0; \272 r1 = r0; \273 r1 += 4; \274 call %[bpf_spin_lock]; \275 r1 = r6; \276 r1 += 4; \277 call %[bpf_spin_lock]; \278 r1 = r6; \279 r1 += 4; \280 r0 = *(u32*)(r6 + 0); \281 call %[bpf_spin_unlock]; \282 r0 = 0; \283 exit; \284" :285 : __imm(bpf_map_lookup_elem),286 __imm(bpf_spin_lock),287 __imm(bpf_spin_unlock),288 __imm_addr(map_spin_lock)289 : __clobber_all);290}291 292SEC("cgroup/skb")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)297{298 asm volatile (" \299 r1 = 0; \300 *(u32*)(r10 - 4) = r1; \301 r2 = r10; \302 r2 += -4; \303 r1 = %[map_spin_lock] ll; \304 call %[bpf_map_lookup_elem]; \305 if r0 != 0 goto l0_%=; \306 exit; \307l0_%=: r6 = r0; \308 r2 = r10; \309 r2 += -4; \310 r1 = %[map_spin_lock] ll; \311 call %[bpf_map_lookup_elem]; \312 if r0 != 0 goto l1_%=; \313 exit; \314l1_%=: r7 = r0; \315 r1 = r6; \316 r1 += 4; \317 call %[bpf_spin_lock]; \318 r1 = r7; \319 r1 += 4; \320 call %[bpf_spin_unlock]; \321 r0 = 0; \322 exit; \323" :324 : __imm(bpf_map_lookup_elem),325 __imm(bpf_spin_lock),326 __imm(bpf_spin_unlock),327 __imm_addr(map_spin_lock)328 : __clobber_all);329}330 331SEC("cgroup/skb")332__description("spin_lock: test10 lock in subprog without unlock")333__success334__failure_unpriv __msg_unpriv("")335__naked void lock_in_subprog_without_unlock(void)336{337 asm volatile (" \338 r1 = 0; \339 *(u32*)(r10 - 4) = r1; \340 r2 = r10; \341 r2 += -4; \342 r1 = %[map_spin_lock] ll; \343 call %[bpf_map_lookup_elem]; \344 if r0 != 0 goto l0_%=; \345 exit; \346l0_%=: r6 = r0; \347 r1 = r0; \348 r1 += 4; \349 call lock_in_subprog_without_unlock__1; \350 r1 = r6; \351 r1 += 4; \352 call %[bpf_spin_unlock]; \353 r0 = 1; \354 exit; \355" :356 : __imm(bpf_map_lookup_elem),357 __imm(bpf_spin_unlock),358 __imm_addr(map_spin_lock)359 : __clobber_all);360}361 362static __naked __noinline __attribute__((used))363void lock_in_subprog_without_unlock__1(void)364{365 asm volatile (" \366 call %[bpf_spin_lock]; \367 r0 = 0; \368 exit; \369" :370 : __imm(bpf_spin_lock)371 : __clobber_all);372}373 374SEC("tc")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)378{379 asm volatile (" \380 r6 = r1; \381 r1 = 0; \382 *(u32*)(r10 - 4) = r1; \383 r2 = r10; \384 r2 += -4; \385 r1 = %[map_spin_lock] ll; \386 call %[bpf_map_lookup_elem]; \387 if r0 != 0 goto l0_%=; \388 exit; \389l0_%=: r7 = r0; \390 r1 = r0; \391 r1 += 4; \392 call %[bpf_spin_lock]; \393 r0 = *(u8*)skb[0]; \394 r1 = r7; \395 r1 += 4; \396 call %[bpf_spin_unlock]; \397 r0 = 0; \398 exit; \399" :400 : __imm(bpf_map_lookup_elem),401 __imm(bpf_spin_lock),402 __imm(bpf_spin_unlock),403 __imm_addr(map_spin_lock)404 : __clobber_all);405}406 407SEC("tc")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)412{413 asm volatile (" \414 r6 = r1; \415 r6 = *(u32*)(r6 + %[__sk_buff_mark]); \416 r1 = %[map_spin_lock] ll; \417 r9 = r1; \418 r2 = 0; \419 *(u32*)(r10 - 4) = r2; \420 r2 = r10; \421 r2 += -4; \422 call %[bpf_map_lookup_elem]; \423 if r0 != 0 goto l0_%=; \424 exit; \425l0_%=: r7 = r0; \426 r1 = r9; \427 r2 = r10; \428 r2 += -4; \429 call %[bpf_map_lookup_elem]; \430 if r0 != 0 goto l1_%=; \431 exit; \432l1_%=: r8 = r0; \433 r1 = r7; \434 r1 += 4; \435 call %[bpf_spin_lock]; \436 if r6 == 0 goto l2_%=; \437 goto l3_%=; \438l2_%=: r7 = r8; \439l3_%=: r1 = r7; \440 r1 += 4; \441 call %[bpf_spin_unlock]; \442 r0 = 0; \443 exit; \444" :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))450 : __clobber_all);451}452 453/* Make sure that regsafe() compares ids for spin lock records using454 * check_ids():455 * 1: r9 = map_lookup_elem(...) ; r9.id == 1456 * 2: r8 = map_lookup_elem(...) ; r8.id == 2457 * 3: r7 = ktime_get_ns()458 * 4: r6 = ktime_get_ns()459 * 5: if r6 > r7 goto <9>460 * 6: spin_lock(r8)461 * 7: r9 = r8462 * 8: goto <10>463 * 9: spin_lock(r9)464 * 10: spin_unlock(r9) ; r9.id == 1 || r9.id == 2 and lock is active,465 * ; second visit to (10) should be considered safe466 * ; if check_ids() is used.467 * 11: exit(0)468 */469 470SEC("cgroup/skb")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)476{477 asm volatile (" \478 r1 = 0; \479 *(u32*)(r10 - 4) = r1; \480 /* r9 = map_lookup_elem(...) */ \481 r2 = r10; \482 r2 += -4; \483 r1 = %[map_spin_lock] ll; \484 call %[bpf_map_lookup_elem]; \485 if r0 == 0 goto l0_%=; \486 r9 = r0; \487 /* r8 = map_lookup_elem(...) */ \488 r2 = r10; \489 r2 += -4; \490 r1 = %[map_spin_lock] ll; \491 call %[bpf_map_lookup_elem]; \492 if r0 == 0 goto l1_%=; \493 r8 = r0; \494 /* r7 = ktime_get_ns() */ \495 call %[bpf_ktime_get_ns]; \496 r7 = r0; \497 /* r6 = ktime_get_ns() */ \498 call %[bpf_ktime_get_ns]; \499 r6 = r0; \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' \503 * spin_lock(r8) \504 * r9 = r8 \505 * goto unlock \506 */ \507 if r6 > r7 goto l2_%=; \508 r1 = r8; \509 r1 += 4; \510 call %[bpf_spin_lock]; \511 r9 = r8; \512 goto l3_%=; \513l2_%=: /* spin_lock(r9) */ \514 r1 = r9; \515 r1 += 4; \516 call %[bpf_spin_lock]; \517l3_%=: /* spin_unlock(r9) */ \518 r1 = r9; \519 r1 += 4; \520 call %[bpf_spin_unlock]; \521l0_%=: /* exit(0) */ \522 r0 = 0; \523l1_%=: exit; \524" :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)530 : __clobber_all);531}532 533char _license[] SEC("license") = "GPL";534