Commit e8699c4f authored by Kumar Kartikeya Dwivedi's avatar Kumar Kartikeya Dwivedi Committed by Alexei Starovoitov
Browse files

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: default avatarYonghong Song <yonghong.song@linux.dev>
Acked-by: default avatarDavid Vernet <void@manifault.com>
Signed-off-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20240204222349.938118-3-memxor@gmail.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent a44b1334
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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)
+65 −0
Original line number Diff line number Diff line
@@ -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";
+44 −0
Original line number Diff line number Diff line
@@ -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";