Commit c1b93c07 authored by Eduard Zingerman's avatar Eduard Zingerman Committed by Andrii Nakryiko
Browse files

selftests/bpf: Bad_struct_ops test



When loading struct_ops programs kernel requires BTF id of the
struct_ops type and member index for attachment point inside that
type. This makes impossible to use same BPF program in several
struct_ops maps that have different struct_ops type.
Check if libbpf rejects such BPF objects files.

Signed-off-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20240306104529.6453-7-eddyz87@gmail.com
parent c8617e8b
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -611,6 +611,29 @@ struct bpf_struct_ops bpf_bpf_testmod_ops = {
	.owner = THIS_MODULE,
};

static int bpf_dummy_reg2(void *kdata)
{
	struct bpf_testmod_ops2 *ops = kdata;

	ops->test_1();
	return 0;
}

static struct bpf_testmod_ops2 __bpf_testmod_ops2 = {
	.test_1 = bpf_testmod_test_1,
};

struct bpf_struct_ops bpf_testmod_ops2 = {
	.verifier_ops = &bpf_testmod_verifier_ops,
	.init = bpf_testmod_ops_init,
	.init_member = bpf_testmod_ops_init_member,
	.reg = bpf_dummy_reg2,
	.unreg = bpf_dummy_unreg,
	.cfi_stubs = &__bpf_testmod_ops2,
	.name = "bpf_testmod_ops2",
	.owner = THIS_MODULE,
};

extern int bpf_fentry_test1(int a);

static int bpf_testmod_init(void)
@@ -622,6 +645,7 @@ static int bpf_testmod_init(void)
	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_testmod_kfunc_set);
	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_testmod_kfunc_set);
	ret = ret ?: register_bpf_struct_ops(&bpf_bpf_testmod_ops, bpf_testmod_ops);
	ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops2, bpf_testmod_ops2);
	if (ret < 0)
		return ret;
	if (bpf_fentry_test1(0) < 0)
+4 −0
Original line number Diff line number Diff line
@@ -89,4 +89,8 @@ struct bpf_testmod_ops {
	int (*tramp_40)(int value);
};

struct bpf_testmod_ops2 {
	int (*test_1)(void);
};

#endif /* _BPF_TESTMOD_H */
+35 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

#include <test_progs.h>
#include "bad_struct_ops.skel.h"

static void invalid_prog_reuse(void)
{
	struct bad_struct_ops *skel;
	char *log = NULL;
	int err;

	skel = bad_struct_ops__open();
	if (!ASSERT_OK_PTR(skel, "bad_struct_ops__open"))
		return;

	if (start_libbpf_log_capture())
		goto cleanup;

	err = bad_struct_ops__load(skel);
	log = stop_libbpf_log_capture();
	ASSERT_ERR(err, "bad_struct_ops__load should fail");
	ASSERT_HAS_SUBSTR(log,
		"struct_ops init_kern testmod_2 func ptr test_1: invalid reuse of prog test_1",
		"expected init_kern message");

cleanup:
	free(log);
	bad_struct_ops__destroy(skel);
}

void test_bad_struct_ops(void)
{
	if (test__start_subtest("invalid_prog_reuse"))
		invalid_prog_reuse();
}
+25 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "../bpf_testmod/bpf_testmod.h"

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

SEC("struct_ops/test_1")
int BPF_PROG(test_1) { return 0; }

SEC("struct_ops/test_2")
int BPF_PROG(test_2) { return 0; }

SEC(".struct_ops.link")
struct bpf_testmod_ops testmod_1 = {
	.test_1 = (void *)test_1,
	.test_2 = (void *)test_2
};

SEC(".struct_ops.link")
struct bpf_testmod_ops2 testmod_2 = {
	.test_1 = (void *)test_1
};