selftests/bpf: Add test for static subprog call in lock cs

Add selftests for static subprog calls within bpf_spin_lock critical
section, and ensure we still reject global subprog calls. Also test the
case where a subprog call will unlock the caller's held lock, or the
caller will unlock a lock taken by a subprog call, ensuring correct
transfer of lock state across frames on exit.

Acked-by: Yonghong Song <yonghong.song@linux.dev>
Acked-by: David Vernet <void@manifault.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20240204222349.938118-3-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Kumar Kartikeya Dwivedi 2024-02-04 22:23:49 +00:00 committed by Alexei Starovoitov
parent a44b1334aa
commit e8699c4ff8
3 changed files with 111 additions and 0 deletions

View file

@ -48,6 +48,8 @@ static struct {
{ "lock_id_mismatch_innermapval_kptr", "bpf_spin_unlock of different lock" },
{ "lock_id_mismatch_innermapval_global", "bpf_spin_unlock of different lock" },
{ "lock_id_mismatch_innermapval_mapval", "bpf_spin_unlock of different lock" },
{ "lock_global_subprog_call1", "global function calls are not allowed while holding a lock" },
{ "lock_global_subprog_call2", "global function calls are not allowed while holding a lock" },
};
static int match_regex(const char *pattern, const char *string)

View file

@ -101,4 +101,69 @@ int bpf_spin_lock_test(struct __sk_buff *skb)
err:
return err;
}
struct bpf_spin_lock lockA __hidden SEC(".data.A");
__noinline
static int static_subprog(struct __sk_buff *ctx)
{
volatile int ret = 0;
if (ctx->protocol)
return ret;
return ret + ctx->len;
}
__noinline
static int static_subprog_lock(struct __sk_buff *ctx)
{
volatile int ret = 0;
ret = static_subprog(ctx);
bpf_spin_lock(&lockA);
return ret + ctx->len;
}
__noinline
static int static_subprog_unlock(struct __sk_buff *ctx)
{
volatile int ret = 0;
ret = static_subprog(ctx);
bpf_spin_unlock(&lockA);
return ret + ctx->len;
}
SEC("tc")
int lock_static_subprog_call(struct __sk_buff *ctx)
{
int ret = 0;
bpf_spin_lock(&lockA);
if (ctx->mark == 42)
ret = static_subprog(ctx);
bpf_spin_unlock(&lockA);
return ret;
}
SEC("tc")
int lock_static_subprog_lock(struct __sk_buff *ctx)
{
int ret = 0;
ret = static_subprog_lock(ctx);
bpf_spin_unlock(&lockA);
return ret;
}
SEC("tc")
int lock_static_subprog_unlock(struct __sk_buff *ctx)
{
int ret = 0;
bpf_spin_lock(&lockA);
ret = static_subprog_unlock(ctx);
return ret;
}
char _license[] SEC("license") = "GPL";

View file

@ -201,4 +201,48 @@ CHECK(innermapval_mapval, &iv->lock, &v->lock);
#undef CHECK
__noinline
int global_subprog(struct __sk_buff *ctx)
{
volatile int ret = 0;
if (ctx->protocol)
ret += ctx->protocol;
return ret + ctx->mark;
}
__noinline
static int static_subprog_call_global(struct __sk_buff *ctx)
{
volatile int ret = 0;
if (ctx->protocol)
return ret;
return ret + ctx->len + global_subprog(ctx);
}
SEC("?tc")
int lock_global_subprog_call1(struct __sk_buff *ctx)
{
int ret = 0;
bpf_spin_lock(&lockA);
if (ctx->mark == 42)
ret = global_subprog(ctx);
bpf_spin_unlock(&lockA);
return ret;
}
SEC("?tc")
int lock_global_subprog_call2(struct __sk_buff *ctx)
{
int ret = 0;
bpf_spin_lock(&lockA);
if (ctx->mark == 42)
ret = static_subprog_call_global(ctx);
bpf_spin_unlock(&lockA);
return ret;
}
char _license[] SEC("license") = "GPL";