diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bpf/verifier.c | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 39f7f633b4d6..0547fbeeebbe 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8839,7 +8839,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, enum bpf_arg_type arg_type = fn->arg_type[arg]; int regno = reg_from_argno(argno); enum bpf_reg_type type = reg->type; - u32 *arg_btf_id = NULL; + const u32 *arg_btf_id = NULL; u32 key_size; int err = 0; @@ -12179,13 +12179,18 @@ bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta) static int get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, - const struct btf_param *args, int arg, int nargs) + const struct btf_param *args, int arg, int nargs, + struct bpf_func_proto *proto) { const struct btf_type *t, *ref_t = NULL; + const u32 *ref_id_ptr = NULL; argno_t argno = argno_from_arg(arg + 1); const char *ref_tname = NULL; + u32 ref_id; int arg_type; + proto->arg_btf_id[arg] = NULL; + if (is_kfunc_arg_prog_aux(meta->btf, &args[arg])) return ARG_PTR_TO_PROG_AUX; @@ -12213,7 +12218,11 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, reg_arg_name(env, argno), btf_type_str(t)); return -EINVAL; } - ref_t = btf_type_skip_modifiers(meta->btf, t->type, NULL); + /* Keep a pointer to the BTF field containing the resolved referent ID. */ + ref_id_ptr = &t->type; + ref_t = btf_type_skip_modifiers(meta->btf, *ref_id_ptr, &ref_id); + while (*ref_id_ptr != ref_id) + ref_id_ptr = &btf_type_by_id(meta->btf, *ref_id_ptr)->type; ref_tname = btf_name_by_offset(meta->btf, ref_t->name_off); /* In this function, we verify the kfunc's BTF as per the argument type, @@ -12336,13 +12345,20 @@ 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. Other argument kinds - * have their own provenance requirements and must not inherit MEM_RCU. - */ - if (base_type(arg_type) == ARG_PTR_TO_BTF_ID && is_kfunc_rcu(meta)) - arg_type |= MEM_RCU; + if (base_type(arg_type) == ARG_PTR_TO_BTF_ID) { + if (is_kfunc_arg_map(meta->btf, &args[arg])) + proto->arg_btf_id[arg] = reg2btf_ids[CONST_PTR_TO_MAP]; + else + proto->arg_btf_id[arg] = ref_id_ptr; + + /* + * A KF_RCU kfunc accepts an RCU-protected pointer where it would + * otherwise demand a referenced or trusted one. Other argument kinds + * have their own provenance requirements and must not inherit MEM_RCU. + */ + if (is_kfunc_rcu(meta)) + arg_type |= MEM_RCU; + } return arg_type; } @@ -12368,7 +12384,7 @@ static int gen_kfunc_arg_proto(struct bpf_verifier_env *env, struct bpf_call_arg } for (i = 0; i < nargs; i++) { - arg_type = get_kfunc_arg_type(env, meta, args, i, nargs); + arg_type = get_kfunc_arg_type(env, meta, args, i, nargs, proto); if (arg_type < 0) return arg_type; @@ -13024,8 +13040,10 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me continue; } + if (base_type(arg_type) == ARG_PTR_TO_BTF_ID) + ref_id = *meta->fn->arg_btf_id[i]; + if (is_kfunc_arg_map(btf, &args[i])) { - ref_id = *reg2btf_ids[CONST_PTR_TO_MAP]; ref_t = btf_type_by_id(btf_vmlinux, ref_id); ref_tname = btf_name_by_offset(btf, ref_t->name_off); } |
