xref: /linux/tools/testing/selftests/bpf/progs/preempt_lock.c (revision d0d106a2bd21499901299160744e5fe9f4c83ddb)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <vmlinux.h>
3 #include <bpf/bpf_helpers.h>
4 #include <bpf/bpf_tracing.h>
5 #include "bpf_misc.h"
6 #include "bpf_experimental.h"
7 
8 extern int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void *unsafe_ptr__ign, u64 flags) __weak __ksym;
9 
10 SEC("?tc")
11 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
preempt_lock_missing_1(struct __sk_buff * ctx)12 int preempt_lock_missing_1(struct __sk_buff *ctx)
13 {
14 	bpf_preempt_disable();
15 	return 0;
16 }
17 
18 SEC("?tc")
19 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
preempt_lock_missing_2(struct __sk_buff * ctx)20 int preempt_lock_missing_2(struct __sk_buff *ctx)
21 {
22 	bpf_preempt_disable();
23 	bpf_preempt_disable();
24 	return 0;
25 }
26 
27 SEC("?tc")
28 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
preempt_lock_missing_3(struct __sk_buff * ctx)29 int preempt_lock_missing_3(struct __sk_buff *ctx)
30 {
31 	bpf_preempt_disable();
32 	bpf_preempt_disable();
33 	bpf_preempt_disable();
34 	return 0;
35 }
36 
37 SEC("?tc")
38 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
preempt_lock_missing_3_minus_2(struct __sk_buff * ctx)39 int preempt_lock_missing_3_minus_2(struct __sk_buff *ctx)
40 {
41 	bpf_preempt_disable();
42 	bpf_preempt_disable();
43 	bpf_preempt_disable();
44 	bpf_preempt_enable();
45 	bpf_preempt_enable();
46 	return 0;
47 }
48 
preempt_disable(void)49 static __noinline void preempt_disable(void)
50 {
51 	bpf_preempt_disable();
52 }
53 
preempt_enable(void)54 static __noinline void preempt_enable(void)
55 {
56 	bpf_preempt_enable();
57 }
58 
59 SEC("?tc")
60 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
preempt_lock_missing_1_subprog(struct __sk_buff * ctx)61 int preempt_lock_missing_1_subprog(struct __sk_buff *ctx)
62 {
63 	preempt_disable();
64 	return 0;
65 }
66 
67 SEC("?tc")
68 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
preempt_lock_missing_2_subprog(struct __sk_buff * ctx)69 int preempt_lock_missing_2_subprog(struct __sk_buff *ctx)
70 {
71 	preempt_disable();
72 	preempt_disable();
73 	return 0;
74 }
75 
76 SEC("?tc")
77 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
preempt_lock_missing_2_minus_1_subprog(struct __sk_buff * ctx)78 int preempt_lock_missing_2_minus_1_subprog(struct __sk_buff *ctx)
79 {
80 	preempt_disable();
81 	preempt_disable();
82 	preempt_enable();
83 	return 0;
84 }
85 
preempt_balance_subprog(void)86 static __noinline void preempt_balance_subprog(void)
87 {
88 	preempt_disable();
89 	preempt_enable();
90 }
91 
92 SEC("?tc")
preempt_balance(struct __sk_buff * ctx)93 __success int preempt_balance(struct __sk_buff *ctx)
94 {
95 	bpf_guard_preempt();
96 	return 0;
97 }
98 
99 SEC("?tc")
preempt_balance_subprog_test(struct __sk_buff * ctx)100 __success int preempt_balance_subprog_test(struct __sk_buff *ctx)
101 {
102 	preempt_balance_subprog();
103 	return 0;
104 }
105 
106 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
107 __failure __msg("sleepable helper bpf_copy_from_user#")
preempt_sleepable_helper(void * ctx)108 int preempt_sleepable_helper(void *ctx)
109 {
110 	u32 data;
111 
112 	bpf_preempt_disable();
113 	bpf_copy_from_user(&data, sizeof(data), NULL);
114 	bpf_preempt_enable();
115 	return 0;
116 }
117 
118 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
119 __failure __msg("kernel func bpf_copy_from_user_str is sleepable within non-preemptible region")
preempt_sleepable_kfunc(void * ctx)120 int preempt_sleepable_kfunc(void *ctx)
121 {
122 	u32 data;
123 
124 	bpf_preempt_disable();
125 	bpf_copy_from_user_str(&data, sizeof(data), NULL, 0);
126 	bpf_preempt_enable();
127 	return 0;
128 }
129 
preempt_global_subprog(void)130 int __noinline preempt_global_subprog(void)
131 {
132 	preempt_balance_subprog();
133 	return 0;
134 }
135 
136 SEC("?tc")
137 __failure __msg("global function calls are not allowed with preemption disabled")
preempt_global_subprog_test(struct __sk_buff * ctx)138 int preempt_global_subprog_test(struct __sk_buff *ctx)
139 {
140 	preempt_disable();
141 	preempt_global_subprog();
142 	preempt_enable();
143 	return 0;
144 }
145 
146 char _license[] SEC("license") = "GPL";
147