Commit 07236eab authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov

bpf: factor out fetching basic kfunc metadata

Factor out logic to fetch basic kfunc metadata based on struct bpf_insn.
This is not exactly short or trivial code to just copy/paste and this
information is sometimes necessary in other parts of the verifier logic.
Subsequent patches will rely on this to determine if an instruction is
a kfunc call to iterator next method.

No functional changes intended, including that verbose() warning
behavior when kfunc is not allowed for a particular program type.
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20230308184121.1165081-2-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent ed69e066
...@@ -10079,24 +10079,21 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ ...@@ -10079,24 +10079,21 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
return 0; return 0;
} }
static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, static int fetch_kfunc_meta(struct bpf_verifier_env *env,
int *insn_idx_p) struct bpf_insn *insn,
struct bpf_kfunc_call_arg_meta *meta,
const char **kfunc_name)
{ {
const struct btf_type *t, *func, *func_proto, *ptr_type; const struct btf_type *func, *func_proto;
u32 i, nargs, func_id, ptr_type_id, release_ref_obj_id; u32 func_id, *kfunc_flags;
struct bpf_reg_state *regs = cur_regs(env); const char *func_name;
const char *func_name, *ptr_type_name;
bool sleepable, rcu_lock, rcu_unlock;
struct bpf_kfunc_call_arg_meta meta;
int err, insn_idx = *insn_idx_p;
const struct btf_param *args;
const struct btf_type *ret_t;
struct btf *desc_btf; struct btf *desc_btf;
u32 *kfunc_flags;
/* skip for now, but return error when we find this in fixup_kfunc_call */ if (kfunc_name)
*kfunc_name = NULL;
if (!insn->imm) if (!insn->imm)
return 0; return -EINVAL;
desc_btf = find_kfunc_desc_btf(env, insn->off); desc_btf = find_kfunc_desc_btf(env, insn->off);
if (IS_ERR(desc_btf)) if (IS_ERR(desc_btf))
...@@ -10105,22 +10102,51 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, ...@@ -10105,22 +10102,51 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
func_id = insn->imm; func_id = insn->imm;
func = btf_type_by_id(desc_btf, func_id); func = btf_type_by_id(desc_btf, func_id);
func_name = btf_name_by_offset(desc_btf, func->name_off); func_name = btf_name_by_offset(desc_btf, func->name_off);
if (kfunc_name)
*kfunc_name = func_name;
func_proto = btf_type_by_id(desc_btf, func->type); func_proto = btf_type_by_id(desc_btf, func->type);
kfunc_flags = btf_kfunc_id_set_contains(desc_btf, resolve_prog_type(env->prog), func_id); kfunc_flags = btf_kfunc_id_set_contains(desc_btf, resolve_prog_type(env->prog), func_id);
if (!kfunc_flags) { if (!kfunc_flags) {
verbose(env, "calling kernel function %s is not allowed\n",
func_name);
return -EACCES; return -EACCES;
} }
/* Prepare kfunc call metadata */ memset(meta, 0, sizeof(*meta));
memset(&meta, 0, sizeof(meta)); meta->btf = desc_btf;
meta.btf = desc_btf; meta->func_id = func_id;
meta.func_id = func_id; meta->kfunc_flags = *kfunc_flags;
meta.kfunc_flags = *kfunc_flags; meta->func_proto = func_proto;
meta.func_proto = func_proto; meta->func_name = func_name;
meta.func_name = func_name;
return 0;
}
static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
int *insn_idx_p)
{
const struct btf_type *t, *ptr_type;
u32 i, nargs, ptr_type_id, release_ref_obj_id;
struct bpf_reg_state *regs = cur_regs(env);
const char *func_name, *ptr_type_name;
bool sleepable, rcu_lock, rcu_unlock;
struct bpf_kfunc_call_arg_meta meta;
struct bpf_insn_aux_data *insn_aux;
int err, insn_idx = *insn_idx_p;
const struct btf_param *args;
const struct btf_type *ret_t;
struct btf *desc_btf;
/* skip for now, but return error when we find this in fixup_kfunc_call */
if (!insn->imm)
return 0;
err = fetch_kfunc_meta(env, insn, &meta, &func_name);
if (err == -EACCES && func_name)
verbose(env, "calling kernel function %s is not allowed\n", func_name);
if (err)
return err;
desc_btf = meta.btf;
insn_aux = &env->insn_aux_data[insn_idx];
if (is_kfunc_destructive(&meta) && !capable(CAP_SYS_BOOT)) { if (is_kfunc_destructive(&meta) && !capable(CAP_SYS_BOOT)) {
verbose(env, "destructive kfunc calls require CAP_SYS_BOOT capability\n"); verbose(env, "destructive kfunc calls require CAP_SYS_BOOT capability\n");
...@@ -10173,7 +10199,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, ...@@ -10173,7 +10199,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
err = release_reference(env, regs[meta.release_regno].ref_obj_id); err = release_reference(env, regs[meta.release_regno].ref_obj_id);
if (err) { if (err) {
verbose(env, "kfunc %s#%d reference has not been acquired before\n", verbose(env, "kfunc %s#%d reference has not been acquired before\n",
func_name, func_id); func_name, meta.func_id);
return err; return err;
} }
} }
...@@ -10185,14 +10211,14 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, ...@@ -10185,14 +10211,14 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
err = ref_convert_owning_non_owning(env, release_ref_obj_id); err = ref_convert_owning_non_owning(env, release_ref_obj_id);
if (err) { if (err) {
verbose(env, "kfunc %s#%d conversion of owning ref to non-owning failed\n", verbose(env, "kfunc %s#%d conversion of owning ref to non-owning failed\n",
func_name, func_id); func_name, meta.func_id);
return err; return err;
} }
err = release_reference(env, release_ref_obj_id); err = release_reference(env, release_ref_obj_id);
if (err) { if (err) {
verbose(env, "kfunc %s#%d reference has not been acquired before\n", verbose(env, "kfunc %s#%d reference has not been acquired before\n",
func_name, func_id); func_name, meta.func_id);
return err; return err;
} }
} }
...@@ -10202,7 +10228,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, ...@@ -10202,7 +10228,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
set_rbtree_add_callback_state); set_rbtree_add_callback_state);
if (err) { if (err) {
verbose(env, "kfunc %s#%d failed callback verification\n", verbose(env, "kfunc %s#%d failed callback verification\n",
func_name, func_id); func_name, meta.func_id);
return err; return err;
} }
} }
...@@ -10211,7 +10237,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, ...@@ -10211,7 +10237,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
mark_reg_not_init(env, regs, caller_saved[i]); mark_reg_not_init(env, regs, caller_saved[i]);
/* Check return type */ /* Check return type */
t = btf_type_skip_modifiers(desc_btf, func_proto->type, NULL); t = btf_type_skip_modifiers(desc_btf, meta.func_proto->type, NULL);
if (is_kfunc_acquire(&meta) && !btf_type_is_struct_ptr(meta.btf, t)) { if (is_kfunc_acquire(&meta) && !btf_type_is_struct_ptr(meta.btf, t)) {
/* Only exception is bpf_obj_new_impl */ /* Only exception is bpf_obj_new_impl */
...@@ -10260,11 +10286,11 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, ...@@ -10260,11 +10286,11 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
regs[BPF_REG_0].btf = ret_btf; regs[BPF_REG_0].btf = ret_btf;
regs[BPF_REG_0].btf_id = ret_btf_id; regs[BPF_REG_0].btf_id = ret_btf_id;
env->insn_aux_data[insn_idx].obj_new_size = ret_t->size; insn_aux->obj_new_size = ret_t->size;
env->insn_aux_data[insn_idx].kptr_struct_meta = insn_aux->kptr_struct_meta =
btf_find_struct_meta(ret_btf, ret_btf_id); btf_find_struct_meta(ret_btf, ret_btf_id);
} else if (meta.func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) { } else if (meta.func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) {
env->insn_aux_data[insn_idx].kptr_struct_meta = insn_aux->kptr_struct_meta =
btf_find_struct_meta(meta.arg_obj_drop.btf, btf_find_struct_meta(meta.arg_obj_drop.btf,
meta.arg_obj_drop.btf_id); meta.arg_obj_drop.btf_id);
} else if (meta.func_id == special_kfunc_list[KF_bpf_list_pop_front] || } else if (meta.func_id == special_kfunc_list[KF_bpf_list_pop_front] ||
...@@ -10397,8 +10423,8 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, ...@@ -10397,8 +10423,8 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
regs[BPF_REG_0].id = ++env->id_gen; regs[BPF_REG_0].id = ++env->id_gen;
} /* else { add_kfunc_call() ensures it is btf_type_is_void(t) } */ } /* else { add_kfunc_call() ensures it is btf_type_is_void(t) } */
nargs = btf_type_vlen(func_proto); nargs = btf_type_vlen(meta.func_proto);
args = (const struct btf_param *)(func_proto + 1); args = (const struct btf_param *)(meta.func_proto + 1);
for (i = 0; i < nargs; i++) { for (i = 0; i < nargs; i++) {
u32 regno = i + 1; u32 regno = i + 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment