xref: /linux/tools/testing/selftests/bpf/progs/preempt_lock.c (revision 1260ed77798502de9c98020040d2995008de10cc)
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("?fentry.s/" SYS_PREFIX "sys_getpgid")
119 __failure __msg("kernel func bpf_copy_from_user_str is sleepable within non-preemptible region")
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 
130 int __noinline preempt_global_subprog(void)
131 {
132 	preempt_balance_subprog();
133 	return 0;
134 }
135 
136 SEC("?tc")
137 __success
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 int __noinline
147 global_subprog(int i)
148 {
149 	if (i)
150 		bpf_printk("%p", &i);
151 	return i;
152 }
153 
154 int __noinline
155 global_sleepable_helper_subprog(int i)
156 {
157 	if (i)
158 		bpf_copy_from_user(&i, sizeof(i), NULL);
159 	return i;
160 }
161 
162 int __noinline
163 global_sleepable_kfunc_subprog(int i)
164 {
165 	if (i)
166 		bpf_copy_from_user_str(&i, sizeof(i), NULL, 0);
167 	global_subprog(i);
168 	return i;
169 }
170 
171 int __noinline
172 global_subprog_calling_sleepable_global(int i)
173 {
174 	if (!i)
175 		global_sleepable_kfunc_subprog(i);
176 	return i;
177 }
178 
179 SEC("?syscall")
180 __failure __msg("global functions that may sleep are not allowed in non-sleepable context")
181 int preempt_global_sleepable_helper_subprog(struct __sk_buff *ctx)
182 {
183 	preempt_disable();
184 	if (ctx->mark)
185 		global_sleepable_helper_subprog(ctx->mark);
186 	preempt_enable();
187 	return 0;
188 }
189 
190 SEC("?syscall")
191 __failure __msg("global functions that may sleep are not allowed in non-sleepable context")
192 int preempt_global_sleepable_kfunc_subprog(struct __sk_buff *ctx)
193 {
194 	preempt_disable();
195 	if (ctx->mark)
196 		global_sleepable_kfunc_subprog(ctx->mark);
197 	preempt_enable();
198 	return 0;
199 }
200 
201 SEC("?syscall")
202 __failure __msg("global functions that may sleep are not allowed in non-sleepable context")
203 int preempt_global_sleepable_subprog_indirect(struct __sk_buff *ctx)
204 {
205 	preempt_disable();
206 	if (ctx->mark)
207 		global_subprog_calling_sleepable_global(ctx->mark);
208 	preempt_enable();
209 	return 0;
210 }
211 
212 char _license[] SEC("license") = "GPL";
213