Commit 04fd12df authored by Amery Hung's avatar Amery Hung Committed by Andrii Nakryiko
Browse files

selftests/bpf: Test ambiguous associated struct_ops



Add a test to make sure implicit struct_ops association does not
break backward compatibility nor return incorrect struct_ops.
struct_ops programs should still be allowed to be reused in
different struct_ops map. The associated struct_ops map set implicitly
however will be poisoned. Trying to read it through the helper
bpf_prog_get_assoc_struct_ops() should result in a NULL pointer.

While recursion of test_1() cannot happen due to the associated
struct_ops being ambiguois, explicitly check for it to prevent stack
overflow if the test regresses.

Signed-off-by: default avatarAmery Hung <ameryhung@gmail.com>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20251203233748.668365-6-ameryhung@gmail.com
parent 33a165f9
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

#include <test_progs.h>
#include "struct_ops_assoc.skel.h"
#include "struct_ops_assoc_reuse.skel.h"

static void test_st_ops_assoc(void)
{
@@ -65,8 +66,45 @@ static void test_st_ops_assoc(void)
	struct_ops_assoc__destroy(skel);
}

static void test_st_ops_assoc_reuse(void)
{
	struct struct_ops_assoc_reuse *skel = NULL;
	int err;

	skel = struct_ops_assoc_reuse__open_and_load();
	if (!ASSERT_OK_PTR(skel, "struct_ops_assoc_reuse__open"))
		goto out;

	err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog_a,
					    skel->maps.st_ops_map_a, NULL);
	ASSERT_OK(err, "bpf_program__assoc_struct_ops(syscall_prog_a, st_ops_map_a)");

	err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog_b,
					    skel->maps.st_ops_map_b, NULL);
	ASSERT_OK(err, "bpf_program__assoc_struct_ops(syscall_prog_b, st_ops_map_b)");

	err = struct_ops_assoc_reuse__attach(skel);
	if (!ASSERT_OK(err, "struct_ops_assoc__attach"))
		goto out;

	/* run syscall_prog that calls .test_1 and checks return */
	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog_a), NULL);
	ASSERT_OK(err, "bpf_prog_test_run_opts");

	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog_b), NULL);
	ASSERT_OK(err, "bpf_prog_test_run_opts");

	ASSERT_EQ(skel->bss->test_err_a, 0, "skel->bss->test_err_a");
	ASSERT_EQ(skel->bss->test_err_b, 0, "skel->bss->test_err_b");

out:
	struct_ops_assoc_reuse__destroy(skel);
}

void test_struct_ops_assoc(void)
{
	if (test__start_subtest("st_ops_assoc"))
		test_st_ops_assoc();
	if (test__start_subtest("st_ops_assoc_reuse"))
		test_st_ops_assoc_reuse();
}
+75 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

#include <vmlinux.h>
#include <bpf/bpf_tracing.h>
#include "bpf_misc.h"
#include "../test_kmods/bpf_testmod.h"
#include "../test_kmods/bpf_testmod_kfunc.h"

char _license[] SEC("license") = "GPL";

#define MAP_A_MAGIC 1234
int test_err_a;
int recur;

/*
 * test_1_a is reused. The kfunc should not be able to get the associated
 * struct_ops and call test_1 recursively as it is ambiguous.
 */
SEC("struct_ops")
int BPF_PROG(test_1_a, struct st_ops_args *args)
{
	int ret;

	if (!recur) {
		recur++;
		ret = bpf_kfunc_multi_st_ops_test_1_impl(args, NULL);
		if (ret != -1)
			test_err_a++;
		recur--;
	}

	return MAP_A_MAGIC;
}

/* Programs associated with st_ops_map_a */

SEC("syscall")
int syscall_prog_a(void *ctx)
{
	struct st_ops_args args = {};
	int ret;

	ret = bpf_kfunc_multi_st_ops_test_1_impl(&args, NULL);
	if (ret != MAP_A_MAGIC)
		test_err_a++;

	return 0;
}

SEC(".struct_ops.link")
struct bpf_testmod_multi_st_ops st_ops_map_a = {
	.test_1 = (void *)test_1_a,
};

/* Programs associated with st_ops_map_b */

int test_err_b;

SEC("syscall")
int syscall_prog_b(void *ctx)
{
	struct st_ops_args args = {};
	int ret;

	ret = bpf_kfunc_multi_st_ops_test_1_impl(&args, NULL);
	if (ret != MAP_A_MAGIC)
		test_err_b++;

	return 0;
}

SEC(".struct_ops.link")
struct bpf_testmod_multi_st_ops st_ops_map_b = {
	.test_1 = (void *)test_1_a,
};