The BTF ID argument of a kfunc has to be referenced or trusted unless the kfunc is KF_RCU, in which case an RCU-protected pointer is accepted too. check_kfunc_args() reads that off meta->kfunc_flags on every verification of the call, which is the last thing keeping the argument policy of ARG_PTR_TO_BTF_ID out of the generated prototype. Set MEM_RCU in get_kfunc_arg_type() for ARG_PTR_TO_BTF_ID arguments of KF_RCU kfuncs, the way it already sets OBJ_RELEASE for release arguments, and test the generated flag instead. Setting it on every pointer argument would be equivalent here but would leak MEM_RCU into arguments whose handling compares the whole arg_type, such as the ARG_PTR_TO_CTX test in check_func_arg_reg_off(). No functional change intended. Signed-off-by: Amery Hung --- kernel/bpf/verifier.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f43462a43ee9..c5b394e847e6 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -12239,6 +12239,14 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, if (is_kfunc_release(meta) && arg == 0) arg_type |= OBJ_RELEASE; + /* + * A KF_RCU kfunc accepts an RCU-protected pointer where it would + * otherwise demand a referenced or trusted one. Only ARG_PTR_TO_BTF_ID + * looks at where its register came from, so leave the other kinds alone. + */ + if (base_type(arg_type) == ARG_PTR_TO_BTF_ID && is_kfunc_rcu(meta)) + arg_type |= MEM_RCU; + return arg_type; } @@ -13174,7 +13182,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me reg2btf_ids[base_type(reg->type)]) { if (!is_trusted_reg(env, reg) || bpf_type_has_unsafe_modifiers(reg->type)) { - if (!is_kfunc_rcu(meta)) { + if (!(arg_type & MEM_RCU)) { const char *expected_type; expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id); -- 2.52.0