Skip to content

Commit 6e2cc60

Browse files
kkdwivediAlexei Starovoitov
authored andcommitted
selftests/bpf: Test sleepable global subprogs in atomic contexts
Add tests for rejecting sleepable and accepting non-sleepable global function calls in atomic contexts. For spin locks, we still reject all global function calls. Once resilient spin locks land, we will carefully lift in cases where we deem it safe. Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 90d8c89 commit 6e2cc60

File tree

6 files changed

+270
-2
lines changed

6 files changed

+270
-2
lines changed

tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ static const char * const inproper_region_tests[] = {
8181
"nested_rcu_region",
8282
"rcu_read_lock_global_subprog_lock",
8383
"rcu_read_lock_global_subprog_unlock",
84+
"rcu_read_lock_sleepable_helper_global_subprog",
85+
"rcu_read_lock_sleepable_kfunc_global_subprog",
86+
"rcu_read_lock_sleepable_global_subprog_indirect",
8487
};
8588

8689
static void test_inproper_region(void)

tools/testing/selftests/bpf/prog_tests/spin_lock.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ static struct {
5050
{ "lock_id_mismatch_innermapval_mapval", "bpf_spin_unlock of different lock" },
5151
{ "lock_global_subprog_call1", "global function calls are not allowed while holding a lock" },
5252
{ "lock_global_subprog_call2", "global function calls are not allowed while holding a lock" },
53+
{ "lock_global_sleepable_helper_subprog", "global function calls are not allowed while holding a lock" },
54+
{ "lock_global_sleepable_kfunc_subprog", "global function calls are not allowed while holding a lock" },
55+
{ "lock_global_sleepable_subprog_indirect", "global function calls are not allowed while holding a lock" },
5356
};
5457

5558
static int match_regex(const char *pattern, const char *string)

tools/testing/selftests/bpf/progs/irq.c

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ int __noinline global_local_irq_balance(void)
222222
}
223223

224224
SEC("?tc")
225-
__failure __msg("global function calls are not allowed with IRQs disabled")
225+
__success
226226
int irq_global_subprog(struct __sk_buff *ctx)
227227
{
228228
unsigned long flags;
@@ -441,4 +441,73 @@ int irq_ooo_refs_array(struct __sk_buff *ctx)
441441
return 0;
442442
}
443443

444+
int __noinline
445+
global_subprog(int i)
446+
{
447+
if (i)
448+
bpf_printk("%p", &i);
449+
return i;
450+
}
451+
452+
int __noinline
453+
global_sleepable_helper_subprog(int i)
454+
{
455+
if (i)
456+
bpf_copy_from_user(&i, sizeof(i), NULL);
457+
return i;
458+
}
459+
460+
int __noinline
461+
global_sleepable_kfunc_subprog(int i)
462+
{
463+
if (i)
464+
bpf_copy_from_user_str(&i, sizeof(i), NULL, 0);
465+
global_subprog(i);
466+
return i;
467+
}
468+
469+
int __noinline
470+
global_subprog_calling_sleepable_global(int i)
471+
{
472+
if (!i)
473+
global_sleepable_kfunc_subprog(i);
474+
return i;
475+
}
476+
477+
SEC("?syscall")
478+
__success
479+
int irq_non_sleepable_global_subprog(void *ctx)
480+
{
481+
unsigned long flags;
482+
483+
bpf_local_irq_save(&flags);
484+
global_subprog(0);
485+
bpf_local_irq_restore(&flags);
486+
return 0;
487+
}
488+
489+
SEC("?syscall")
490+
__failure __msg("global functions that may sleep are not allowed in non-sleepable context")
491+
int irq_sleepable_helper_global_subprog(void *ctx)
492+
{
493+
unsigned long flags;
494+
495+
bpf_local_irq_save(&flags);
496+
global_sleepable_helper_subprog(0);
497+
bpf_local_irq_restore(&flags);
498+
return 0;
499+
}
500+
501+
SEC("?syscall")
502+
__failure __msg("global functions that may sleep are not allowed in non-sleepable context")
503+
int irq_sleepable_global_subprog_indirect(void *ctx)
504+
{
505+
unsigned long flags;
506+
507+
bpf_local_irq_save(&flags);
508+
global_subprog_calling_sleepable_global(0);
509+
bpf_local_irq_restore(&flags);
510+
return 0;
511+
}
512+
444513
char _license[] SEC("license") = "GPL";

tools/testing/selftests/bpf/progs/preempt_lock.c

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ int __noinline preempt_global_subprog(void)
134134
}
135135

136136
SEC("?tc")
137-
__failure __msg("global function calls are not allowed with preemption disabled")
137+
__success
138138
int preempt_global_subprog_test(struct __sk_buff *ctx)
139139
{
140140
preempt_disable();
@@ -143,4 +143,70 @@ int preempt_global_subprog_test(struct __sk_buff *ctx)
143143
return 0;
144144
}
145145

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+
146212
char _license[] SEC("license") = "GPL";

tools/testing/selftests/bpf/progs/rcu_read_lock.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,61 @@ int rcu_read_lock_global_subprog_unlock(void *ctx)
439439
ret += global_subprog_unlock(ret);
440440
return 0;
441441
}
442+
443+
int __noinline
444+
global_sleepable_helper_subprog(int i)
445+
{
446+
if (i)
447+
bpf_copy_from_user(&i, sizeof(i), NULL);
448+
return i;
449+
}
450+
451+
int __noinline
452+
global_sleepable_kfunc_subprog(int i)
453+
{
454+
if (i)
455+
bpf_copy_from_user_str(&i, sizeof(i), NULL, 0);
456+
global_subprog(i);
457+
return i;
458+
}
459+
460+
int __noinline
461+
global_subprog_calling_sleepable_global(int i)
462+
{
463+
if (!i)
464+
global_sleepable_kfunc_subprog(i);
465+
return i;
466+
}
467+
468+
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
469+
int rcu_read_lock_sleepable_helper_global_subprog(void *ctx)
470+
{
471+
volatile int ret = 0;
472+
473+
bpf_rcu_read_lock();
474+
ret += global_sleepable_helper_subprog(ret);
475+
bpf_rcu_read_unlock();
476+
return 0;
477+
}
478+
479+
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
480+
int rcu_read_lock_sleepable_kfunc_global_subprog(void *ctx)
481+
{
482+
volatile int ret = 0;
483+
484+
bpf_rcu_read_lock();
485+
ret += global_sleepable_kfunc_subprog(ret);
486+
bpf_rcu_read_unlock();
487+
return 0;
488+
}
489+
490+
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
491+
int rcu_read_lock_sleepable_global_subprog_indirect(void *ctx)
492+
{
493+
volatile int ret = 0;
494+
495+
bpf_rcu_read_lock();
496+
ret += global_subprog_calling_sleepable_global(ret);
497+
bpf_rcu_read_unlock();
498+
return 0;
499+
}

tools/testing/selftests/bpf/progs/test_spin_lock_fail.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,73 @@ int lock_global_subprog_call2(struct __sk_buff *ctx)
245245
return ret;
246246
}
247247

248+
int __noinline
249+
global_subprog_int(int i)
250+
{
251+
if (i)
252+
bpf_printk("%p", &i);
253+
return i;
254+
}
255+
256+
int __noinline
257+
global_sleepable_helper_subprog(int i)
258+
{
259+
if (i)
260+
bpf_copy_from_user(&i, sizeof(i), NULL);
261+
return i;
262+
}
263+
264+
int __noinline
265+
global_sleepable_kfunc_subprog(int i)
266+
{
267+
if (i)
268+
bpf_copy_from_user_str(&i, sizeof(i), NULL, 0);
269+
global_subprog_int(i);
270+
return i;
271+
}
272+
273+
int __noinline
274+
global_subprog_calling_sleepable_global(int i)
275+
{
276+
if (!i)
277+
global_sleepable_kfunc_subprog(i);
278+
return i;
279+
}
280+
281+
SEC("?syscall")
282+
int lock_global_sleepable_helper_subprog(struct __sk_buff *ctx)
283+
{
284+
int ret = 0;
285+
286+
bpf_spin_lock(&lockA);
287+
if (ctx->mark == 42)
288+
ret = global_sleepable_helper_subprog(ctx->mark);
289+
bpf_spin_unlock(&lockA);
290+
return ret;
291+
}
292+
293+
SEC("?syscall")
294+
int lock_global_sleepable_kfunc_subprog(struct __sk_buff *ctx)
295+
{
296+
int ret = 0;
297+
298+
bpf_spin_lock(&lockA);
299+
if (ctx->mark == 42)
300+
ret = global_sleepable_kfunc_subprog(ctx->mark);
301+
bpf_spin_unlock(&lockA);
302+
return ret;
303+
}
304+
305+
SEC("?syscall")
306+
int lock_global_sleepable_subprog_indirect(struct __sk_buff *ctx)
307+
{
308+
int ret = 0;
309+
310+
bpf_spin_lock(&lockA);
311+
if (ctx->mark == 42)
312+
ret = global_subprog_calling_sleepable_global(ctx->mark);
313+
bpf_spin_unlock(&lockA);
314+
return ret;
315+
}
316+
248317
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)