1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include "bpf_misc.h"
6 #include "bpf_experimental.h"
7 
8 unsigned long global_flags;
9 
10 extern void bpf_local_irq_save(unsigned long *) __weak __ksym;
11 extern void bpf_local_irq_restore(unsigned long *) __weak __ksym;
12 extern int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void *unsafe_ptr__ign, u64 flags) __weak __ksym;
13 
14 struct bpf_res_spin_lock lockA __hidden SEC(".data.A");
15 struct bpf_res_spin_lock lockB __hidden SEC(".data.B");
16 
17 SEC("?tc")
18 __failure __msg("arg#0 doesn't point to an irq flag on stack")
irq_save_bad_arg(struct __sk_buff * ctx)19 int irq_save_bad_arg(struct __sk_buff *ctx)
20 {
21 	bpf_local_irq_save(&global_flags);
22 	return 0;
23 }
24 
25 SEC("?tc")
26 __failure __msg("arg#0 doesn't point to an irq flag on stack")
irq_restore_bad_arg(struct __sk_buff * ctx)27 int irq_restore_bad_arg(struct __sk_buff *ctx)
28 {
29 	bpf_local_irq_restore(&global_flags);
30 	return 0;
31 }
32 
33 SEC("?tc")
34 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region")
irq_restore_missing_2(struct __sk_buff * ctx)35 int irq_restore_missing_2(struct __sk_buff *ctx)
36 {
37 	unsigned long flags1;
38 	unsigned long flags2;
39 
40 	bpf_local_irq_save(&flags1);
41 	bpf_local_irq_save(&flags2);
42 	return 0;
43 }
44 
45 SEC("?tc")
46 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region")
irq_restore_missing_3(struct __sk_buff * ctx)47 int irq_restore_missing_3(struct __sk_buff *ctx)
48 {
49 	unsigned long flags1;
50 	unsigned long flags2;
51 	unsigned long flags3;
52 
53 	bpf_local_irq_save(&flags1);
54 	bpf_local_irq_save(&flags2);
55 	bpf_local_irq_save(&flags3);
56 	return 0;
57 }
58 
59 SEC("?tc")
60 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region")
irq_restore_missing_3_minus_2(struct __sk_buff * ctx)61 int irq_restore_missing_3_minus_2(struct __sk_buff *ctx)
62 {
63 	unsigned long flags1;
64 	unsigned long flags2;
65 	unsigned long flags3;
66 
67 	bpf_local_irq_save(&flags1);
68 	bpf_local_irq_save(&flags2);
69 	bpf_local_irq_save(&flags3);
70 	bpf_local_irq_restore(&flags3);
71 	bpf_local_irq_restore(&flags2);
72 	return 0;
73 }
74 
local_irq_save(unsigned long * flags)75 static __noinline void local_irq_save(unsigned long *flags)
76 {
77 	bpf_local_irq_save(flags);
78 }
79 
local_irq_restore(unsigned long * flags)80 static __noinline void local_irq_restore(unsigned long *flags)
81 {
82 	bpf_local_irq_restore(flags);
83 }
84 
85 SEC("?tc")
86 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region")
irq_restore_missing_1_subprog(struct __sk_buff * ctx)87 int irq_restore_missing_1_subprog(struct __sk_buff *ctx)
88 {
89 	unsigned long flags;
90 
91 	local_irq_save(&flags);
92 	return 0;
93 }
94 
95 SEC("?tc")
96 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region")
irq_restore_missing_2_subprog(struct __sk_buff * ctx)97 int irq_restore_missing_2_subprog(struct __sk_buff *ctx)
98 {
99 	unsigned long flags1;
100 	unsigned long flags2;
101 
102 	local_irq_save(&flags1);
103 	local_irq_save(&flags2);
104 	return 0;
105 }
106 
107 SEC("?tc")
108 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region")
irq_restore_missing_3_subprog(struct __sk_buff * ctx)109 int irq_restore_missing_3_subprog(struct __sk_buff *ctx)
110 {
111 	unsigned long flags1;
112 	unsigned long flags2;
113 	unsigned long flags3;
114 
115 	local_irq_save(&flags1);
116 	local_irq_save(&flags2);
117 	local_irq_save(&flags3);
118 	return 0;
119 }
120 
121 SEC("?tc")
122 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region")
irq_restore_missing_3_minus_2_subprog(struct __sk_buff * ctx)123 int irq_restore_missing_3_minus_2_subprog(struct __sk_buff *ctx)
124 {
125 	unsigned long flags1;
126 	unsigned long flags2;
127 	unsigned long flags3;
128 
129 	local_irq_save(&flags1);
130 	local_irq_save(&flags2);
131 	local_irq_save(&flags3);
132 	local_irq_restore(&flags3);
133 	local_irq_restore(&flags2);
134 	return 0;
135 }
136 
137 SEC("?tc")
138 __success
irq_balance(struct __sk_buff * ctx)139 int irq_balance(struct __sk_buff *ctx)
140 {
141 	unsigned long flags;
142 
143 	local_irq_save(&flags);
144 	local_irq_restore(&flags);
145 	return 0;
146 }
147 
148 SEC("?tc")
149 __success
irq_balance_n(struct __sk_buff * ctx)150 int irq_balance_n(struct __sk_buff *ctx)
151 {
152 	unsigned long flags1;
153 	unsigned long flags2;
154 	unsigned long flags3;
155 
156 	local_irq_save(&flags1);
157 	local_irq_save(&flags2);
158 	local_irq_save(&flags3);
159 	local_irq_restore(&flags3);
160 	local_irq_restore(&flags2);
161 	local_irq_restore(&flags1);
162 	return 0;
163 }
164 
local_irq_balance(void)165 static __noinline void local_irq_balance(void)
166 {
167 	unsigned long flags;
168 
169 	local_irq_save(&flags);
170 	local_irq_restore(&flags);
171 }
172 
local_irq_balance_n(void)173 static __noinline void local_irq_balance_n(void)
174 {
175 	unsigned long flags1;
176 	unsigned long flags2;
177 	unsigned long flags3;
178 
179 	local_irq_save(&flags1);
180 	local_irq_save(&flags2);
181 	local_irq_save(&flags3);
182 	local_irq_restore(&flags3);
183 	local_irq_restore(&flags2);
184 	local_irq_restore(&flags1);
185 }
186 
187 SEC("?tc")
188 __success
irq_balance_subprog(struct __sk_buff * ctx)189 int irq_balance_subprog(struct __sk_buff *ctx)
190 {
191 	local_irq_balance();
192 	return 0;
193 }
194 
195 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
196 __failure __msg("sleepable helper bpf_copy_from_user#")
irq_sleepable_helper(void * ctx)197 int irq_sleepable_helper(void *ctx)
198 {
199 	unsigned long flags;
200 	u32 data;
201 
202 	local_irq_save(&flags);
203 	bpf_copy_from_user(&data, sizeof(data), NULL);
204 	local_irq_restore(&flags);
205 	return 0;
206 }
207 
208 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
209 __failure __msg("kernel func bpf_copy_from_user_str is sleepable within IRQ-disabled region")
irq_sleepable_kfunc(void * ctx)210 int irq_sleepable_kfunc(void *ctx)
211 {
212 	unsigned long flags;
213 	u32 data;
214 
215 	local_irq_save(&flags);
216 	bpf_copy_from_user_str(&data, sizeof(data), NULL, 0);
217 	local_irq_restore(&flags);
218 	return 0;
219 }
220 
global_local_irq_balance(void)221 int __noinline global_local_irq_balance(void)
222 {
223 	local_irq_balance_n();
224 	return 0;
225 }
226 
227 SEC("?tc")
228 __success
irq_global_subprog(struct __sk_buff * ctx)229 int irq_global_subprog(struct __sk_buff *ctx)
230 {
231 	unsigned long flags;
232 
233 	bpf_local_irq_save(&flags);
234 	global_local_irq_balance();
235 	bpf_local_irq_restore(&flags);
236 	return 0;
237 }
238 
239 SEC("?tc")
240 __failure __msg("cannot restore irq state out of order")
irq_restore_ooo(struct __sk_buff * ctx)241 int irq_restore_ooo(struct __sk_buff *ctx)
242 {
243 	unsigned long flags1;
244 	unsigned long flags2;
245 
246 	bpf_local_irq_save(&flags1);
247 	bpf_local_irq_save(&flags2);
248 	bpf_local_irq_restore(&flags1);
249 	bpf_local_irq_restore(&flags2);
250 	return 0;
251 }
252 
253 SEC("?tc")
254 __failure __msg("cannot restore irq state out of order")
irq_restore_ooo_3(struct __sk_buff * ctx)255 int irq_restore_ooo_3(struct __sk_buff *ctx)
256 {
257 	unsigned long flags1;
258 	unsigned long flags2;
259 	unsigned long flags3;
260 
261 	bpf_local_irq_save(&flags1);
262 	bpf_local_irq_save(&flags2);
263 	bpf_local_irq_restore(&flags2);
264 	bpf_local_irq_save(&flags3);
265 	bpf_local_irq_restore(&flags1);
266 	bpf_local_irq_restore(&flags3);
267 	return 0;
268 }
269 
local_irq_save_3(unsigned long * flags1,unsigned long * flags2,unsigned long * flags3)270 static __noinline void local_irq_save_3(unsigned long *flags1, unsigned long *flags2,
271 					unsigned long *flags3)
272 {
273 	local_irq_save(flags1);
274 	local_irq_save(flags2);
275 	local_irq_save(flags3);
276 }
277 
278 SEC("?tc")
279 __success
irq_restore_3_subprog(struct __sk_buff * ctx)280 int irq_restore_3_subprog(struct __sk_buff *ctx)
281 {
282 	unsigned long flags1;
283 	unsigned long flags2;
284 	unsigned long flags3;
285 
286 	local_irq_save_3(&flags1, &flags2, &flags3);
287 	bpf_local_irq_restore(&flags3);
288 	bpf_local_irq_restore(&flags2);
289 	bpf_local_irq_restore(&flags1);
290 	return 0;
291 }
292 
293 SEC("?tc")
294 __failure __msg("cannot restore irq state out of order")
irq_restore_4_subprog(struct __sk_buff * ctx)295 int irq_restore_4_subprog(struct __sk_buff *ctx)
296 {
297 	unsigned long flags1;
298 	unsigned long flags2;
299 	unsigned long flags3;
300 	unsigned long flags4;
301 
302 	local_irq_save_3(&flags1, &flags2, &flags3);
303 	bpf_local_irq_restore(&flags3);
304 	bpf_local_irq_save(&flags4);
305 	bpf_local_irq_restore(&flags4);
306 	bpf_local_irq_restore(&flags1);
307 	return 0;
308 }
309 
310 SEC("?tc")
311 __failure __msg("cannot restore irq state out of order")
irq_restore_ooo_3_subprog(struct __sk_buff * ctx)312 int irq_restore_ooo_3_subprog(struct __sk_buff *ctx)
313 {
314 	unsigned long flags1;
315 	unsigned long flags2;
316 	unsigned long flags3;
317 
318 	local_irq_save_3(&flags1, &flags2, &flags3);
319 	bpf_local_irq_restore(&flags3);
320 	bpf_local_irq_restore(&flags2);
321 	bpf_local_irq_save(&flags3);
322 	bpf_local_irq_restore(&flags1);
323 	return 0;
324 }
325 
326 SEC("?tc")
327 __failure __msg("expected an initialized")
irq_restore_invalid(struct __sk_buff * ctx)328 int irq_restore_invalid(struct __sk_buff *ctx)
329 {
330 	unsigned long flags1;
331 	unsigned long flags = 0xfaceb00c;
332 
333 	bpf_local_irq_save(&flags1);
334 	bpf_local_irq_restore(&flags);
335 	return 0;
336 }
337 
338 SEC("?tc")
339 __failure __msg("expected uninitialized")
irq_save_invalid(struct __sk_buff * ctx)340 int irq_save_invalid(struct __sk_buff *ctx)
341 {
342 	unsigned long flags1;
343 
344 	bpf_local_irq_save(&flags1);
345 	bpf_local_irq_save(&flags1);
346 	return 0;
347 }
348 
349 SEC("?tc")
350 __failure __msg("expected an initialized")
irq_restore_iter(struct __sk_buff * ctx)351 int irq_restore_iter(struct __sk_buff *ctx)
352 {
353 	struct bpf_iter_num it;
354 
355 	bpf_iter_num_new(&it, 0, 42);
356 	bpf_local_irq_restore((unsigned long *)&it);
357 	return 0;
358 }
359 
360 SEC("?tc")
361 __failure __msg("Unreleased reference id=1")
irq_save_iter(struct __sk_buff * ctx)362 int irq_save_iter(struct __sk_buff *ctx)
363 {
364 	struct bpf_iter_num it;
365 
366 	/* Ensure same sized slot has st->ref_obj_id set, so we reject based on
367 	 * slot_type != STACK_IRQ_FLAG...
368 	 */
369 	_Static_assert(sizeof(it) == sizeof(unsigned long), "broken iterator size");
370 
371 	bpf_iter_num_new(&it, 0, 42);
372 	bpf_local_irq_save((unsigned long *)&it);
373 	bpf_local_irq_restore((unsigned long *)&it);
374 	return 0;
375 }
376 
377 SEC("?tc")
378 __failure __msg("expected an initialized")
irq_flag_overwrite(struct __sk_buff * ctx)379 int irq_flag_overwrite(struct __sk_buff *ctx)
380 {
381 	unsigned long flags;
382 
383 	bpf_local_irq_save(&flags);
384 	flags = 0xdeadbeef;
385 	bpf_local_irq_restore(&flags);
386 	return 0;
387 }
388 
389 SEC("?tc")
390 __failure __msg("expected an initialized")
irq_flag_overwrite_partial(struct __sk_buff * ctx)391 int irq_flag_overwrite_partial(struct __sk_buff *ctx)
392 {
393 	unsigned long flags;
394 
395 	bpf_local_irq_save(&flags);
396 	*(((char *)&flags) + 1) = 0xff;
397 	bpf_local_irq_restore(&flags);
398 	return 0;
399 }
400 
401 SEC("?tc")
402 __failure __msg("cannot restore irq state out of order")
irq_ooo_refs_array(struct __sk_buff * ctx)403 int irq_ooo_refs_array(struct __sk_buff *ctx)
404 {
405 	unsigned long flags[4];
406 	struct { int i; } *p;
407 
408 	/* refs=1 */
409 	bpf_local_irq_save(&flags[0]);
410 
411 	/* refs=1,2 */
412 	p = bpf_obj_new(typeof(*p));
413 	if (!p) {
414 		bpf_local_irq_restore(&flags[0]);
415 		return 0;
416 	}
417 
418 	/* refs=1,2,3 */
419 	bpf_local_irq_save(&flags[1]);
420 
421 	/* refs=1,2,3,4 */
422 	bpf_local_irq_save(&flags[2]);
423 
424 	/* Now when we remove ref=2, the verifier must not break the ordering in
425 	 * the refs array between 1,3,4. With an older implementation, the
426 	 * verifier would swap the last element with the removed element, but to
427 	 * maintain the stack property we need to use memmove.
428 	 */
429 	bpf_obj_drop(p);
430 
431 	/* Save and restore to reset active_irq_id to 3, as the ordering is now
432 	 * refs=1,4,3. When restoring the linear scan will find prev_id in order
433 	 * as 3 instead of 4.
434 	 */
435 	bpf_local_irq_save(&flags[3]);
436 	bpf_local_irq_restore(&flags[3]);
437 
438 	/* With the incorrect implementation, we can release flags[1], flags[2],
439 	 * and flags[0], i.e. in the wrong order.
440 	 */
441 	bpf_local_irq_restore(&flags[1]);
442 	bpf_local_irq_restore(&flags[2]);
443 	bpf_local_irq_restore(&flags[0]);
444 	return 0;
445 }
446 
447 int __noinline
global_subprog(int i)448 global_subprog(int i)
449 {
450 	if (i)
451 		bpf_printk("%p", &i);
452 	return i;
453 }
454 
455 int __noinline
global_sleepable_helper_subprog(int i)456 global_sleepable_helper_subprog(int i)
457 {
458 	if (i)
459 		bpf_copy_from_user(&i, sizeof(i), NULL);
460 	return i;
461 }
462 
463 int __noinline
global_sleepable_kfunc_subprog(int i)464 global_sleepable_kfunc_subprog(int i)
465 {
466 	if (i)
467 		bpf_copy_from_user_str(&i, sizeof(i), NULL, 0);
468 	global_subprog(i);
469 	return i;
470 }
471 
472 int __noinline
global_subprog_calling_sleepable_global(int i)473 global_subprog_calling_sleepable_global(int i)
474 {
475 	if (!i)
476 		global_sleepable_kfunc_subprog(i);
477 	return i;
478 }
479 
480 SEC("?syscall")
481 __success
irq_non_sleepable_global_subprog(void * ctx)482 int irq_non_sleepable_global_subprog(void *ctx)
483 {
484 	unsigned long flags;
485 
486 	bpf_local_irq_save(&flags);
487 	global_subprog(0);
488 	bpf_local_irq_restore(&flags);
489 	return 0;
490 }
491 
492 SEC("?syscall")
493 __failure __msg("global functions that may sleep are not allowed in non-sleepable context")
irq_sleepable_helper_global_subprog(void * ctx)494 int irq_sleepable_helper_global_subprog(void *ctx)
495 {
496 	unsigned long flags;
497 
498 	bpf_local_irq_save(&flags);
499 	global_sleepable_helper_subprog(0);
500 	bpf_local_irq_restore(&flags);
501 	return 0;
502 }
503 
504 SEC("?syscall")
505 __failure __msg("global functions that may sleep are not allowed in non-sleepable context")
irq_sleepable_global_subprog_indirect(void * ctx)506 int irq_sleepable_global_subprog_indirect(void *ctx)
507 {
508 	unsigned long flags;
509 
510 	bpf_local_irq_save(&flags);
511 	global_subprog_calling_sleepable_global(0);
512 	bpf_local_irq_restore(&flags);
513 	return 0;
514 }
515 
516 SEC("?tc")
517 __failure __msg("cannot restore irq state out of order")
irq_ooo_lock_cond_inv(struct __sk_buff * ctx)518 int irq_ooo_lock_cond_inv(struct __sk_buff *ctx)
519 {
520 	unsigned long flags1, flags2;
521 
522 	if (bpf_res_spin_lock_irqsave(&lockA, &flags1))
523 		return 0;
524 	if (bpf_res_spin_lock_irqsave(&lockB, &flags2)) {
525 		bpf_res_spin_unlock_irqrestore(&lockA, &flags1);
526 		return 0;
527 	}
528 
529 	bpf_res_spin_unlock_irqrestore(&lockB, &flags1);
530 	bpf_res_spin_unlock_irqrestore(&lockA, &flags2);
531 	return 0;
532 }
533 
534 SEC("?tc")
535 __failure __msg("function calls are not allowed")
irq_wrong_kfunc_class_1(struct __sk_buff * ctx)536 int irq_wrong_kfunc_class_1(struct __sk_buff *ctx)
537 {
538 	unsigned long flags1;
539 
540 	if (bpf_res_spin_lock_irqsave(&lockA, &flags1))
541 		return 0;
542 	/* For now, bpf_local_irq_restore is not allowed in critical section,
543 	 * but this test ensures error will be caught with kfunc_class when it's
544 	 * opened up. Tested by temporarily permitting this kfunc in critical
545 	 * section.
546 	 */
547 	bpf_local_irq_restore(&flags1);
548 	bpf_res_spin_unlock_irqrestore(&lockA, &flags1);
549 	return 0;
550 }
551 
552 SEC("?tc")
553 __failure __msg("function calls are not allowed")
irq_wrong_kfunc_class_2(struct __sk_buff * ctx)554 int irq_wrong_kfunc_class_2(struct __sk_buff *ctx)
555 {
556 	unsigned long flags1, flags2;
557 
558 	bpf_local_irq_save(&flags1);
559 	if (bpf_res_spin_lock_irqsave(&lockA, &flags2))
560 		return 0;
561 	bpf_local_irq_restore(&flags2);
562 	bpf_res_spin_unlock_irqrestore(&lockA, &flags1);
563 	return 0;
564 }
565 
566 char _license[] SEC("license") = "GPL";
567