Skip to content

Commit 5eccd2d

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
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 <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 4ba1d0f commit 5eccd2d

File tree

6 files changed

+19
-66
lines changed

6 files changed

+19
-66
lines changed

include/linux/bpf.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2466,8 +2466,6 @@ int btf_distill_func_proto(struct bpf_verifier_log *log,
24662466
struct btf_func_model *m);
24672467

24682468
struct bpf_reg_state;
2469-
int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
2470-
struct bpf_reg_state *regs);
24712469
int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
24722470
struct bpf_reg_state *regs);
24732471
int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog);

kernel/bpf/btf.c

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6768,8 +6768,7 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr
67686768
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
67696769
const struct btf *btf, u32 func_id,
67706770
struct bpf_reg_state *regs,
6771-
bool ptr_to_mem_ok,
6772-
bool processing_call)
6771+
bool ptr_to_mem_ok)
67736772
{
67746773
enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
67756774
struct bpf_verifier_log *log = &env->log;
@@ -6842,7 +6841,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
68426841
i, btf_type_str(t));
68436842
return -EINVAL;
68446843
}
6845-
} else if (ptr_to_mem_ok && processing_call) {
6844+
} else if (ptr_to_mem_ok) {
68466845
const struct btf_type *resolve_ret;
68476846
u32 type_size;
68486847

@@ -6867,55 +6866,12 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
68676866
return 0;
68686867
}
68696868

6870-
/* Compare BTF of a function declaration with given bpf_reg_state.
6871-
* Returns:
6872-
* EFAULT - there is a verifier bug. Abort verification.
6873-
* EINVAL - there is a type mismatch or BTF is not available.
6874-
* 0 - BTF matches with what bpf_reg_state expects.
6875-
* Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
6876-
*/
6877-
int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
6878-
struct bpf_reg_state *regs)
6879-
{
6880-
struct bpf_prog *prog = env->prog;
6881-
struct btf *btf = prog->aux->btf;
6882-
bool is_global;
6883-
u32 btf_id;
6884-
int err;
6885-
6886-
if (!prog->aux->func_info)
6887-
return -EINVAL;
6888-
6889-
btf_id = prog->aux->func_info[subprog].type_id;
6890-
if (!btf_id)
6891-
return -EFAULT;
6892-
6893-
if (prog->aux->func_info_aux[subprog].unreliable)
6894-
return -EINVAL;
6895-
6896-
is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
6897-
err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, false);
6898-
6899-
/* Compiler optimizations can remove arguments from static functions
6900-
* or mismatched type can be passed into a global function.
6901-
* In such cases mark the function as unreliable from BTF point of view.
6902-
*/
6903-
if (err)
6904-
prog->aux->func_info_aux[subprog].unreliable = true;
6905-
return err;
6906-
}
6907-
69086869
/* Compare BTF of a function call with given bpf_reg_state.
69096870
* Returns:
69106871
* EFAULT - there is a verifier bug. Abort verification.
69116872
* EINVAL - there is a type mismatch or BTF is not available.
69126873
* 0 - BTF matches with what bpf_reg_state expects.
69136874
* Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
6914-
*
6915-
* NOTE: the code is duplicated from btf_check_subprog_arg_match()
6916-
* because btf_check_func_arg_match() is still doing both. Once that
6917-
* function is split in 2, we can call from here btf_check_subprog_arg_match()
6918-
* first, and then treat the calling part in a new code path.
69196875
*/
69206876
int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
69216877
struct bpf_reg_state *regs)
@@ -6937,7 +6893,7 @@ int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
69376893
return -EINVAL;
69386894

69396895
is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
6940-
err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, true);
6896+
err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global);
69416897

69426898
/* Compiler optimizations can remove arguments from static functions
69436899
* or mismatched type can be passed into a global function.

kernel/bpf/verifier.c

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19904,6 +19904,7 @@ static void free_states(struct bpf_verifier_env *env)
1990419904
static int do_check_common(struct bpf_verifier_env *env, int subprog)
1990519905
{
1990619906
bool pop_log = !(env->log.level & BPF_LOG_LEVEL2);
19907+
struct bpf_subprog_info *sub = subprog_info(env, subprog);
1990719908
struct bpf_verifier_state *state;
1990819909
struct bpf_reg_state *regs;
1990919910
int ret, i;
@@ -19930,9 +19931,9 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
1993019931
state->first_insn_idx = env->subprog_info[subprog].start;
1993119932
state->last_insn_idx = -1;
1993219933

19934+
1993319935
regs = state->frame[state->curframe]->regs;
1993419936
if (subprog || env->prog->type == BPF_PROG_TYPE_EXT) {
19935-
struct bpf_subprog_info *sub = subprog_info(env, subprog);
1993619937
const char *sub_name = subprog_name(env, subprog);
1993719938
struct bpf_subprog_arg_info *arg;
1993819939
struct bpf_reg_state *reg;
@@ -19979,21 +19980,19 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
1997919980
}
1998019981
}
1998119982
} else {
19983+
/* if main BPF program has associated BTF info, validate that
19984+
* it's matching expected signature, and otherwise mark BTF
19985+
* info for main program as unreliable
19986+
*/
19987+
if (env->prog->aux->func_info_aux) {
19988+
ret = btf_prepare_func_args(env, 0);
19989+
if (ret || sub->arg_cnt != 1 || sub->args[0].arg_type != ARG_PTR_TO_CTX)
19990+
env->prog->aux->func_info_aux[0].unreliable = true;
19991+
}
19992+
1998219993
/* 1st arg to a function */
1998319994
regs[BPF_REG_1].type = PTR_TO_CTX;
1998419995
mark_reg_known_zero(env, regs, BPF_REG_1);
19985-
ret = btf_check_subprog_arg_match(env, subprog, regs);
19986-
if (ret == -EFAULT)
19987-
/* unlikely verifier bug. abort.
19988-
* ret == 0 and ret < 0 are sadly acceptable for
19989-
* main() function due to backward compatibility.
19990-
* Like socket filter program may be written as:
19991-
* int bpf_prog(struct pt_regs *ctx)
19992-
* and never dereference that ctx in the program.
19993-
* 'struct pt_regs' is a type mismatch for socket
19994-
* filter that should be using 'struct __sk_buff'.
19995-
*/
19996-
goto out;
1999719996
}
1999819997

1999919998
ret = do_check(env);

tools/testing/selftests/bpf/prog_tests/log_fixup.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ void test_log_fixup(void)
169169
if (test__start_subtest("bad_core_relo_trunc_none"))
170170
bad_core_relo(0, TRUNC_NONE /* full buf */);
171171
if (test__start_subtest("bad_core_relo_trunc_partial"))
172-
bad_core_relo(300, TRUNC_PARTIAL /* truncate original log a bit */);
172+
bad_core_relo(280, TRUNC_PARTIAL /* truncate original log a bit */);
173173
if (test__start_subtest("bad_core_relo_trunc_full"))
174-
bad_core_relo(210, TRUNC_FULL /* truncate also libbpf's message patch */);
174+
bad_core_relo(220, TRUNC_FULL /* truncate also libbpf's message patch */);
175175
if (test__start_subtest("bad_core_relo_subprog"))
176176
bad_core_relo_subprog();
177177
if (test__start_subtest("missing_map"))

tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)
7878
}
7979

8080
SEC("kretprobe/cgroup_destroy_locked")
81-
__failure __msg("reg type unsupported for arg#0 function")
81+
__failure __msg("calling kernel function bpf_cgroup_acquire is not allowed")
8282
int BPF_PROG(cgrp_kfunc_acquire_unsafe_kretprobe, struct cgroup *cgrp)
8383
{
8484
struct cgroup *acquired;

tools/testing/selftests/bpf/progs/task_kfunc_failure.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ int BPF_PROG(task_kfunc_from_pid_no_null_check, struct task_struct *task, u64 cl
248248
}
249249

250250
SEC("lsm/task_free")
251-
__failure __msg("reg type unsupported for arg#0 function")
251+
__failure __msg("R1 must be a rcu pointer")
252252
int BPF_PROG(task_kfunc_from_lsm_task_free, struct task_struct *task)
253253
{
254254
struct task_struct *acquired;

0 commit comments

Comments
 (0)