selftests/bpf: Fix erroneous bitmask operation
[platform/kernel/linux-rpi.git] / tools / testing / selftests / bpf / progs / verifier_spin_lock.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* 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
8 struct val {
9         int cnt;
10         struct bpf_spin_lock l;
11 };
12
13 struct {
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
20 SEC("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;                                           \
35 l0_%=:  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
53 SEC("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;                                           \
68 l0_%=:  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
86 SEC("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;                                           \
102 l0_%=:  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
120 SEC("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;                                           \
136 l0_%=:  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
154 SEC("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;                                           \
169 l0_%=:  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
188 SEC("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;                                           \
203 l0_%=:  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];                        \
212 l1_%=:  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
222 SEC("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;                                           \
237 l0_%=:  r6 = r0;                                        \
238         r1 = r0;                                        \
239         r1 += 4;                                        \
240         if r1 != 0 goto l1_%=;                          \
241         call %[bpf_spin_lock];                          \
242 l1_%=:  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
256 SEC("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;                                           \
271 l0_%=:  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
292 SEC("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;                                           \
307 l0_%=:  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;                                           \
314 l1_%=:  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
331 SEC("cgroup/skb")
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)
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;                                           \
346 l0_%=:  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
362 static __naked __noinline __attribute__((used))
363 void 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
374 SEC("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;                                           \
389 l0_%=:  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
407 SEC("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;                                           \
425 l0_%=:  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;                                           \
432 l1_%=:  r8 = r0;                                        \
433         r1 = r7;                                        \
434         r1 += 4;                                        \
435         call %[bpf_spin_lock];                          \
436         if r6 == 0 goto l2_%=;                          \
437         goto l3_%=;                                     \
438 l2_%=:  r7 = r8;                                        \
439 l3_%=:  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 using
454  * check_ids():
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>
460  *  6: spin_lock(r8)
461  *  7: r9 = r8
462  *  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 safe
466  *                                 ; if check_ids() is used.
467  * 11: exit(0)
468  */
469
470 SEC("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_%=;                                     \
513 l2_%=:  /* spin_lock(r9) */                             \
514         r1 = r9;                                        \
515         r1 += 4;                                        \
516         call %[bpf_spin_lock];                          \
517 l3_%=:  /* spin_unlock(r9) */                           \
518         r1 = r9;                                        \
519         r1 += 4;                                        \
520         call %[bpf_spin_unlock];                        \
521 l0_%=:  /* exit(0) */                                   \
522         r0 = 0;                                         \
523 l1_%=:  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
533 char _license[] SEC("license") = "GPL";