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("?uprobe.s")
119 __failure __msg("sleepable helper bpf_get_stack#")
preempt_sleepable_get_stack(struct pt_regs * ctx)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#")
preempt_sleepable_get_task_stack(void * ctx)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
sleepable_get_stack(struct pt_regs * ctx)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
sleepable_get_task_stack(void * ctx)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")
preempt_sleepable_kfunc(void * ctx)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
preempt_global_subprog(void)182 int __noinline preempt_global_subprog(void)
183 {
184 preempt_balance_subprog();
185 return 0;
186 }
187
188 SEC("?tc")
189 __success
preempt_global_subprog_test(struct __sk_buff * ctx)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
global_subprog(int i)199 global_subprog(int i)
200 {
201 if (i)
202 bpf_printk("%p", &i);
203 return i;
204 }
205
206 int __noinline
global_sleepable_helper_subprog(int i)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
global_sleepable_kfunc_subprog(int i)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
global_subprog_calling_sleepable_global(int i)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")
preempt_global_sleepable_helper_subprog(struct __sk_buff * ctx)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")
preempt_global_sleepable_kfunc_subprog(struct __sk_buff * ctx)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")
preempt_global_sleepable_subprog_indirect(struct __sk_buff * ctx)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