mirror of
https://github.com/torvalds/linux.git
synced 2026-09-28 03:52:02 +02:00
selftests/bpf: Test early in-kernel CO-RE relocation
Add a raw program load with CO-RE relocation metadata but no func_info or line_info. Place the relocation in dead code and require the poisoning log, proving that the kernel processes standalone CO-RE metadata instead of silently skipping it. Also give a subprogram a relocatable immediate as its terminal instruction. Require the relocation's poisoning log before check_subprogs() rejects the resulting fall-through. With the old ordering, check_subprogs() rejects the original terminal instruction before CO-RE can emit the substitution log, so the test continues to distinguish the ordering after relocation target validation is tightened. Submit a trailing ldimm64 first slot with CO-RE metadata and require the early structural diagnostic. This exercises the check that protects relocation processing instead of the later regular instruction validation. Load the standalone instruction stream without relocation metadata first to ensure that CO-RE processing causes its poisoning diagnostic. Encode the fixed BTF metadata directly with the selftest BTF helpers. Suggested-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://patch.msgid.link/20260917233222.2542500-6-memxor@gmail.com Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
This commit is contained in:
parent
c26e97721b
commit
968ee7c06b
|
|
@ -14,6 +14,138 @@
|
|||
|
||||
static char log[16 * 1024];
|
||||
|
||||
static int load_core_relo_insns(int btf_fd, struct bpf_insn *insns, int insn_cnt,
|
||||
struct bpf_func_info *funcs, int func_cnt,
|
||||
int enum_id, int access_str_off, int insn_idx,
|
||||
bool relocate)
|
||||
{
|
||||
struct bpf_core_relo relo = {
|
||||
.insn_off = insn_idx * sizeof(struct bpf_insn),
|
||||
.type_id = enum_id,
|
||||
.access_str_off = access_str_off,
|
||||
.kind = BPF_CORE_ENUMVAL_VALUE,
|
||||
};
|
||||
union bpf_attr attr = {
|
||||
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
|
||||
.insn_cnt = insn_cnt,
|
||||
.insns = (__u64)insns,
|
||||
.license = (__u64)"GPL",
|
||||
.log_buf = (__u64)log,
|
||||
.log_size = sizeof(log),
|
||||
.log_level = 2,
|
||||
.prog_btf_fd = btf_fd,
|
||||
.func_info_rec_size = sizeof(struct bpf_func_info),
|
||||
.func_info = (__u64)funcs,
|
||||
.func_info_cnt = func_cnt,
|
||||
};
|
||||
|
||||
if (relocate) {
|
||||
attr.core_relo_cnt = 1;
|
||||
attr.core_relos = (__u64)&relo;
|
||||
attr.core_relo_rec_size = sizeof(relo);
|
||||
}
|
||||
memset(log, 0, sizeof(log));
|
||||
return sys_bpf_prog_load(&attr, sizeof(attr), 1);
|
||||
}
|
||||
|
||||
static void test_early_core_relo(void)
|
||||
{
|
||||
struct test_btf {
|
||||
struct btf_header hdr;
|
||||
__u32 types[18];
|
||||
char strings[64];
|
||||
} raw_btf = {
|
||||
.hdr = {
|
||||
.magic = BTF_MAGIC,
|
||||
.version = BTF_VERSION,
|
||||
.hdr_len = sizeof(struct btf_header),
|
||||
.type_off = 0,
|
||||
.type_len = sizeof(raw_btf.types),
|
||||
.str_off = offsetof(struct test_btf, strings) -
|
||||
offsetof(struct test_btf, types),
|
||||
.str_len = sizeof(raw_btf.strings),
|
||||
},
|
||||
.types = {
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] int */
|
||||
BTF_FUNC_PROTO_ENC(1, 0), /* [2] int (*)(void) */
|
||||
BTF_FUNC_ENC(5, 2), /* [3] main_fn */
|
||||
BTF_FUNC_ENC(13, 2), /* [4] sub_fn */
|
||||
BTF_TYPE_ENC(20, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [5] enum */
|
||||
BTF_ENUM_ENC(45, 0), /* value = 0 */
|
||||
},
|
||||
.strings = "\0int\0main_fn\0sub_fn\0core_relo_poison_missing\0value\0" "0",
|
||||
};
|
||||
struct bpf_func_info funcs[] = {
|
||||
{ .insn_off = 0, .type_id = 3 },
|
||||
{ .insn_off = 3, .type_id = 4 },
|
||||
};
|
||||
struct bpf_insn core_only[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
struct bpf_insn subprog[] = {
|
||||
BPF_CALL_REL(2),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
struct bpf_insn truncated_ldimm64[] = {
|
||||
BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0),
|
||||
};
|
||||
int access_str_off = 51; /* offset of "0" */
|
||||
int enum_id = 5;
|
||||
int btf_fd, prog_fd = -1;
|
||||
|
||||
btf_fd = bpf_btf_load(&raw_btf, sizeof(raw_btf), NULL);
|
||||
if (!ASSERT_GE(btf_fd, 0, "btf_load"))
|
||||
goto cleanup;
|
||||
|
||||
if (test__start_subtest("without_func_info")) {
|
||||
prog_fd = load_core_relo_insns(btf_fd, core_only, ARRAY_SIZE(core_only), NULL, 0,
|
||||
enum_id, access_str_off, 2, false);
|
||||
if (!ASSERT_GE(prog_fd, 0, "control_load"))
|
||||
goto cleanup;
|
||||
close(prog_fd);
|
||||
prog_fd = load_core_relo_insns(btf_fd, core_only, ARRAY_SIZE(core_only), NULL, 0,
|
||||
enum_id, access_str_off, 2, true);
|
||||
if (!ASSERT_GE(prog_fd, 0, "poisoned_load"))
|
||||
goto cleanup;
|
||||
ASSERT_HAS_SUBSTR(log, "substituting insn #2", "poison_log");
|
||||
close(prog_fd);
|
||||
prog_fd = -1;
|
||||
}
|
||||
|
||||
if (test__start_subtest("before_subprog_validation")) {
|
||||
prog_fd = load_core_relo_insns(btf_fd, subprog, ARRAY_SIZE(subprog), funcs, 2,
|
||||
enum_id, access_str_off, 2, true);
|
||||
if (!ASSERT_LT(prog_fd, 0, "poisoned_load"))
|
||||
goto cleanup;
|
||||
ASSERT_HAS_SUBSTR(log, "substituting insn #2", "poison_log");
|
||||
ASSERT_HAS_SUBSTR(log, "last insn is not an exit or jmp", "poisoned_load_log");
|
||||
}
|
||||
|
||||
if (test__start_subtest("truncated_ldimm64")) {
|
||||
prog_fd = load_core_relo_insns(btf_fd, truncated_ldimm64,
|
||||
ARRAY_SIZE(truncated_ldimm64), NULL, 0,
|
||||
enum_id, access_str_off, 0, true);
|
||||
if (!ASSERT_LT(prog_fd, 0, "truncated_load"))
|
||||
goto cleanup;
|
||||
ASSERT_HAS_SUBSTR(log, "invalid bpf_ld_imm64 insn", "truncated_load_log");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (env.verbosity > VERBOSE_NORMAL && log[0]) {
|
||||
printf("-------- program load log start --------\n");
|
||||
printf("%s", log);
|
||||
printf("-------- program load log end ----------\n");
|
||||
}
|
||||
close(prog_fd);
|
||||
close(btf_fd);
|
||||
}
|
||||
|
||||
/* Check that verifier rejects BPF program containing relocation
|
||||
* pointing to non-existent BTF type.
|
||||
*/
|
||||
|
|
@ -120,6 +252,7 @@ static void test_bad_local_id(void)
|
|||
|
||||
void test_core_reloc_raw(void)
|
||||
{
|
||||
test_early_core_relo();
|
||||
if (test__start_subtest("bad_local_id"))
|
||||
test_bad_local_id();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user