xref: /linux/tools/testing/selftests/bpf/progs/preempt_lock.c (revision 14c5eb685cdefbd32e73d2723071ecbd8effbce9)
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")
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")
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")
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")
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 
49 static __noinline void preempt_disable(void)
50 {
51 	bpf_preempt_disable();
52 }
53 
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")
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")
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")
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 
86 static __noinline void preempt_balance_subprog(void)
87 {
88 	preempt_disable();
89 	preempt_enable();
90 }
91 
92 SEC("?tc")
93 __success int preempt_balance(struct __sk_buff *ctx)
94 {
95 	bpf_guard_preempt();
96 	return 0;
97 }
98 
99 SEC("?tc")
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#")
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("?uprobe.s")
119 __failure __msg("sleepable helper bpf_get_stack#")
120 int preempt_sleepable_get_stack(struct pt_regs *ctx)
121 {
122 	struct bpf_stack_build_id stack;
123 
124 	bpf_preempt_disable();
125 	bpf_get_stack(ctx, &stack, sizeof(stack),
126 		      BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
127 	bpf_preempt_enable();
128 	return 0;
129 }
130 
131 SEC("?uprobe.s")
132 __failure __msg("sleepable helper bpf_get_task_stack#")
133 int preempt_sleepable_get_task_stack(void *ctx)
134 {
135 	struct bpf_stack_build_id stack;
136 	struct task_struct *task;
137 
138 	task = bpf_get_current_task_btf();
139 	bpf_preempt_disable();
140 	bpf_get_task_stack(task, &stack, sizeof(stack),
141 			   BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
142 	bpf_preempt_enable();
143 	return 0;
144 }
145 
146 SEC("?uprobe.s")
147 __success
148 int sleepable_get_stack(struct pt_regs *ctx)
149 {
150 	struct bpf_stack_build_id stack;
151 
152 	bpf_get_stack(ctx, &stack, sizeof(stack),
153 		      BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
154 	return 0;
155 }
156 
157 SEC("?uprobe.s")
158 __success
159 int sleepable_get_task_stack(void *ctx)
160 {
161 	struct bpf_stack_build_id stack;
162 	struct task_struct *task;
163 
164 	task = bpf_get_current_task_btf();
165 	bpf_get_task_stack(task, &stack, sizeof(stack),
166 			   BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
167 	return 0;
168 }
169 
170 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
171 __failure __msg("kernel func bpf_copy_from_user_str is sleepable within non-preemptible region")
172 int preempt_sleepable_kfunc(void *ctx)
173 {
174 	u32 data;
175 
176 	bpf_preempt_disable();
177 	bpf_copy_from_user_str(&data, sizeof(data), NULL, 0);
178 	bpf_preempt_enable();
179 	return 0;
180 }
181 
182 int __noinline preempt_global_subprog(void)
183 {
184 	preempt_balance_subprog();
185 	return 0;
186 }
187 
188 SEC("?tc")
189 __success
190 int preempt_global_subprog_test(struct __sk_buff *ctx)
191 {
192 	preempt_disable();
193 	preempt_global_subprog();
194 	preempt_enable();
195 	return 0;
196 }
197 
198 int __noinline
199 global_subprog(int i)
200 {
201 	if (i)
202 		bpf_printk("%p", &i);
203 	return i;
204 }
205 
206 int __noinline
207 global_sleepable_helper_subprog(int i)
208 {
209 	if (i)
210 		bpf_copy_from_user(&i, sizeof(i), NULL);
211 	return i;
212 }
213 
214 int __noinline
215 global_sleepable_kfunc_subprog(int i)
216 {
217 	if (i)
218 		bpf_copy_from_user_str(&i, sizeof(i), NULL, 0);
219 	global_subprog(i);
220 	return i;
221 }
222 
223 int __noinline
224 global_subprog_calling_sleepable_global(int i)
225 {
226 	if (!i)
227 		global_sleepable_kfunc_subprog(i);
228 	return i;
229 }
230 
231 SEC("?syscall")
232 __failure __msg("sleepable global function")
233 int preempt_global_sleepable_helper_subprog(struct __sk_buff *ctx)
234 {
235 	preempt_disable();
236 	if (ctx->mark)
237 		global_sleepable_helper_subprog(ctx->mark);
238 	preempt_enable();
239 	return 0;
240 }
241 
242 SEC("?syscall")
243 __failure __msg("sleepable global function")
244 int preempt_global_sleepable_kfunc_subprog(struct __sk_buff *ctx)
245 {
246 	preempt_disable();
247 	if (ctx->mark)
248 		global_sleepable_kfunc_subprog(ctx->mark);
249 	preempt_enable();
250 	return 0;
251 }
252 
253 SEC("?syscall")
254 __failure __msg("sleepable global function")
255 int preempt_global_sleepable_subprog_indirect(struct __sk_buff *ctx)
256 {
257 	preempt_disable();
258 	if (ctx->mark)
259 		global_subprog_calling_sleepable_global(ctx->mark);
260 	preempt_enable();
261 	return 0;
262 }
263 
264 char _license[] SEC("license") = "GPL";
265