1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00
linux/tools/testing/selftests/bpf/prog_tests/log_fixup.c
Andrii Nakryiko 5eccd2db42 bpf: reuse btf_prepare_func_args() check for main program BTF validation
Instead of btf_check_subprog_arg_match(), use btf_prepare_func_args()
logic to validate "trustworthiness" of main BPF program's BTF information,
if it is present.

We ignored results of original BTF check anyway, often times producing
confusing and ominously-sounding "reg type unsupported for arg#0
function" message, which has no apparent effect on program correctness
and verification process.

All the -EFAULT returning sanity checks are already performed in
check_btf_info_early(), so there is zero reason to have this duplication
of logic between btf_check_subprog_call() and btf_check_subprog_arg_match().
Dropping btf_check_subprog_arg_match() simplifies
btf_check_func_arg_match() further removing `bool processing_call` flag.

One subtle bit that was done by btf_check_subprog_arg_match() was
potentially marking main program's BTF as unreliable. We do this
explicitly now with a dedicated simple check, preserving the original
behavior, but now based on well factored btf_prepare_func_args() logic.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20231215011334.2307144-3-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-12-19 18:06:46 -08:00

181 lines
5.2 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
#include <test_progs.h>
#include <bpf/btf.h>
#include "test_log_fixup.skel.h"
enum trunc_type {
TRUNC_NONE,
TRUNC_PARTIAL,
TRUNC_FULL,
};
static void bad_core_relo(size_t log_buf_size, enum trunc_type trunc_type)
{
char log_buf[8 * 1024];
struct test_log_fixup* skel;
int err;
skel = test_log_fixup__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;
bpf_program__set_autoload(skel->progs.bad_relo, true);
memset(log_buf, 0, sizeof(log_buf));
bpf_program__set_log_buf(skel->progs.bad_relo, log_buf, log_buf_size ?: sizeof(log_buf));
bpf_program__set_log_level(skel->progs.bad_relo, 1 | 8); /* BPF_LOG_FIXED to force truncation */
err = test_log_fixup__load(skel);
if (!ASSERT_ERR(err, "load_fail"))
goto cleanup;
ASSERT_HAS_SUBSTR(log_buf,
"0: <invalid CO-RE relocation>\n"
"failed to resolve CO-RE relocation <byte_sz> ",
"log_buf_part1");
switch (trunc_type) {
case TRUNC_NONE:
ASSERT_HAS_SUBSTR(log_buf,
"struct task_struct___bad.fake_field (0:1 @ offset 4)\n",
"log_buf_part2");
ASSERT_HAS_SUBSTR(log_buf,
"max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n",
"log_buf_end");
break;
case TRUNC_PARTIAL:
/* we should get full libbpf message patch */
ASSERT_HAS_SUBSTR(log_buf,
"struct task_struct___bad.fake_field (0:1 @ offset 4)\n",
"log_buf_part2");
/* we shouldn't get full end of BPF verifier log */
ASSERT_NULL(strstr(log_buf, "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n"),
"log_buf_end");
break;
case TRUNC_FULL:
/* we shouldn't get second part of libbpf message patch */
ASSERT_NULL(strstr(log_buf, "struct task_struct___bad.fake_field (0:1 @ offset 4)\n"),
"log_buf_part2");
/* we shouldn't get full end of BPF verifier log */
ASSERT_NULL(strstr(log_buf, "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n"),
"log_buf_end");
break;
}
if (env.verbosity > VERBOSE_NONE)
printf("LOG: \n=================\n%s=================\n", log_buf);
cleanup:
test_log_fixup__destroy(skel);
}
static void bad_core_relo_subprog(void)
{
char log_buf[8 * 1024];
struct test_log_fixup* skel;
int err;
skel = test_log_fixup__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;
bpf_program__set_autoload(skel->progs.bad_relo_subprog, true);
bpf_program__set_log_buf(skel->progs.bad_relo_subprog, log_buf, sizeof(log_buf));
err = test_log_fixup__load(skel);
if (!ASSERT_ERR(err, "load_fail"))
goto cleanup;
ASSERT_HAS_SUBSTR(log_buf,
": <invalid CO-RE relocation>\n"
"failed to resolve CO-RE relocation <byte_off> ",
"log_buf");
ASSERT_HAS_SUBSTR(log_buf,
"struct task_struct___bad.fake_field_subprog (0:2 @ offset 8)\n",
"log_buf");
if (env.verbosity > VERBOSE_NONE)
printf("LOG: \n=================\n%s=================\n", log_buf);
cleanup:
test_log_fixup__destroy(skel);
}
static void missing_map(void)
{
char log_buf[8 * 1024];
struct test_log_fixup* skel;
int err;
skel = test_log_fixup__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;
bpf_map__set_autocreate(skel->maps.missing_map, false);
bpf_program__set_autoload(skel->progs.use_missing_map, true);
bpf_program__set_log_buf(skel->progs.use_missing_map, log_buf, sizeof(log_buf));
err = test_log_fixup__load(skel);
if (!ASSERT_ERR(err, "load_fail"))
goto cleanup;
ASSERT_TRUE(bpf_map__autocreate(skel->maps.existing_map), "existing_map_autocreate");
ASSERT_FALSE(bpf_map__autocreate(skel->maps.missing_map), "missing_map_autocreate");
ASSERT_HAS_SUBSTR(log_buf,
": <invalid BPF map reference>\n"
"BPF map 'missing_map' is referenced but wasn't created\n",
"log_buf");
if (env.verbosity > VERBOSE_NONE)
printf("LOG: \n=================\n%s=================\n", log_buf);
cleanup:
test_log_fixup__destroy(skel);
}
static void missing_kfunc(void)
{
char log_buf[8 * 1024];
struct test_log_fixup* skel;
int err;
skel = test_log_fixup__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;
bpf_program__set_autoload(skel->progs.use_missing_kfunc, true);
bpf_program__set_log_buf(skel->progs.use_missing_kfunc, log_buf, sizeof(log_buf));
err = test_log_fixup__load(skel);
if (!ASSERT_ERR(err, "load_fail"))
goto cleanup;
ASSERT_HAS_SUBSTR(log_buf,
"0: <invalid kfunc call>\n"
"kfunc 'bpf_nonexistent_kfunc' is referenced but wasn't resolved\n",
"log_buf");
if (env.verbosity > VERBOSE_NONE)
printf("LOG: \n=================\n%s=================\n", log_buf);
cleanup:
test_log_fixup__destroy(skel);
}
void test_log_fixup(void)
{
if (test__start_subtest("bad_core_relo_trunc_none"))
bad_core_relo(0, TRUNC_NONE /* full buf */);
if (test__start_subtest("bad_core_relo_trunc_partial"))
bad_core_relo(280, TRUNC_PARTIAL /* truncate original log a bit */);
if (test__start_subtest("bad_core_relo_trunc_full"))
bad_core_relo(220, TRUNC_FULL /* truncate also libbpf's message patch */);
if (test__start_subtest("bad_core_relo_subprog"))
bad_core_relo_subprog();
if (test__start_subtest("missing_map"))
missing_map();
if (test__start_subtest("missing_kfunc"))
missing_kfunc();
}