Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
5eccd2db 4ba1d0f2

+19 -66
-2
include/linux/bpf.h
··· 2466 2466 struct btf_func_model *m); 2467 2467 2468 2468 struct bpf_reg_state; 2469 - int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog, 2470 - struct bpf_reg_state *regs); 2471 2469 int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog, 2472 2470 struct bpf_reg_state *regs); 2473 2471 int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog);
+3 -47
kernel/bpf/btf.c
··· 6768 6768 static int btf_check_func_arg_match(struct bpf_verifier_env *env, 6769 6769 const struct btf *btf, u32 func_id, 6770 6770 struct bpf_reg_state *regs, 6771 - bool ptr_to_mem_ok, 6772 - bool processing_call) 6771 + bool ptr_to_mem_ok) 6773 6772 { 6774 6773 enum bpf_prog_type prog_type = resolve_prog_type(env->prog); 6775 6774 struct bpf_verifier_log *log = &env->log; ··· 6841 6842 i, btf_type_str(t)); 6842 6843 return -EINVAL; 6843 6844 } 6844 - } else if (ptr_to_mem_ok && processing_call) { 6845 + } else if (ptr_to_mem_ok) { 6845 6846 const struct btf_type *resolve_ret; 6846 6847 u32 type_size; 6847 6848 ··· 6866 6867 return 0; 6867 6868 } 6868 6869 6869 - /* Compare BTF of a function declaration with given bpf_reg_state. 6870 - * Returns: 6871 - * EFAULT - there is a verifier bug. Abort verification. 6872 - * EINVAL - there is a type mismatch or BTF is not available. 6873 - * 0 - BTF matches with what bpf_reg_state expects. 6874 - * Only PTR_TO_CTX and SCALAR_VALUE states are recognized. 6875 - */ 6876 - int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog, 6877 - struct bpf_reg_state *regs) 6878 - { 6879 - struct bpf_prog *prog = env->prog; 6880 - struct btf *btf = prog->aux->btf; 6881 - bool is_global; 6882 - u32 btf_id; 6883 - int err; 6884 - 6885 - if (!prog->aux->func_info) 6886 - return -EINVAL; 6887 - 6888 - btf_id = prog->aux->func_info[subprog].type_id; 6889 - if (!btf_id) 6890 - return -EFAULT; 6891 - 6892 - if (prog->aux->func_info_aux[subprog].unreliable) 6893 - return -EINVAL; 6894 - 6895 - is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL; 6896 - err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, false); 6897 - 6898 - /* Compiler optimizations can remove arguments from static functions 6899 - * or mismatched type can be passed into a global function. 6900 - * In such cases mark the function as unreliable from BTF point of view. 6901 - */ 6902 - if (err) 6903 - prog->aux->func_info_aux[subprog].unreliable = true; 6904 - return err; 6905 - } 6906 - 6907 6870 /* Compare BTF of a function call with given bpf_reg_state. 6908 6871 * Returns: 6909 6872 * EFAULT - there is a verifier bug. Abort verification. 6910 6873 * EINVAL - there is a type mismatch or BTF is not available. 6911 6874 * 0 - BTF matches with what bpf_reg_state expects. 6912 6875 * Only PTR_TO_CTX and SCALAR_VALUE states are recognized. 6913 - * 6914 - * NOTE: the code is duplicated from btf_check_subprog_arg_match() 6915 - * because btf_check_func_arg_match() is still doing both. Once that 6916 - * function is split in 2, we can call from here btf_check_subprog_arg_match() 6917 - * first, and then treat the calling part in a new code path. 6918 6876 */ 6919 6877 int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog, 6920 6878 struct bpf_reg_state *regs) ··· 6893 6937 return -EINVAL; 6894 6938 6895 6939 is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL; 6896 - err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, true); 6940 + err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global); 6897 6941 6898 6942 /* Compiler optimizations can remove arguments from static functions 6899 6943 * or mismatched type can be passed into a global function.
+12 -13
kernel/bpf/verifier.c
··· 19904 19904 static int do_check_common(struct bpf_verifier_env *env, int subprog) 19905 19905 { 19906 19906 bool pop_log = !(env->log.level & BPF_LOG_LEVEL2); 19907 + struct bpf_subprog_info *sub = subprog_info(env, subprog); 19907 19908 struct bpf_verifier_state *state; 19908 19909 struct bpf_reg_state *regs; 19909 19910 int ret, i; ··· 19931 19930 state->first_insn_idx = env->subprog_info[subprog].start; 19932 19931 state->last_insn_idx = -1; 19933 19932 19933 + 19934 19934 regs = state->frame[state->curframe]->regs; 19935 19935 if (subprog || env->prog->type == BPF_PROG_TYPE_EXT) { 19936 - struct bpf_subprog_info *sub = subprog_info(env, subprog); 19937 19936 const char *sub_name = subprog_name(env, subprog); 19938 19937 struct bpf_subprog_arg_info *arg; 19939 19938 struct bpf_reg_state *reg; ··· 19980 19979 } 19981 19980 } 19982 19981 } else { 19982 + /* if main BPF program has associated BTF info, validate that 19983 + * it's matching expected signature, and otherwise mark BTF 19984 + * info for main program as unreliable 19985 + */ 19986 + if (env->prog->aux->func_info_aux) { 19987 + ret = btf_prepare_func_args(env, 0); 19988 + if (ret || sub->arg_cnt != 1 || sub->args[0].arg_type != ARG_PTR_TO_CTX) 19989 + env->prog->aux->func_info_aux[0].unreliable = true; 19990 + } 19991 + 19983 19992 /* 1st arg to a function */ 19984 19993 regs[BPF_REG_1].type = PTR_TO_CTX; 19985 19994 mark_reg_known_zero(env, regs, BPF_REG_1); 19986 - ret = btf_check_subprog_arg_match(env, subprog, regs); 19987 - if (ret == -EFAULT) 19988 - /* unlikely verifier bug. abort. 19989 - * ret == 0 and ret < 0 are sadly acceptable for 19990 - * main() function due to backward compatibility. 19991 - * Like socket filter program may be written as: 19992 - * int bpf_prog(struct pt_regs *ctx) 19993 - * and never dereference that ctx in the program. 19994 - * 'struct pt_regs' is a type mismatch for socket 19995 - * filter that should be using 'struct __sk_buff'. 19996 - */ 19997 - goto out; 19998 19995 } 19999 19996 20000 19997 ret = do_check(env);
+2 -2
tools/testing/selftests/bpf/prog_tests/log_fixup.c
··· 169 169 if (test__start_subtest("bad_core_relo_trunc_none")) 170 170 bad_core_relo(0, TRUNC_NONE /* full buf */); 171 171 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 */); 173 173 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 */); 175 175 if (test__start_subtest("bad_core_relo_subprog")) 176 176 bad_core_relo_subprog(); 177 177 if (test__start_subtest("missing_map"))
+1 -1
tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
··· 78 78 } 79 79 80 80 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") 82 82 int BPF_PROG(cgrp_kfunc_acquire_unsafe_kretprobe, struct cgroup *cgrp) 83 83 { 84 84 struct cgroup *acquired;
+1 -1
tools/testing/selftests/bpf/progs/task_kfunc_failure.c
··· 248 248 } 249 249 250 250 SEC("lsm/task_free") 251 - __failure __msg("reg type unsupported for arg#0 function") 251 + __failure __msg("R1 must be a rcu pointer") 252 252 int BPF_PROG(task_kfunc_from_lsm_task_free, struct task_struct *task) 253 253 { 254 254 struct task_struct *acquired;