bpf: Fix PTR_TO_BTF_ID var_off check
When kfunc support was added, check_ctx_reg was called for PTR_TO_CTX
register, but no offset checks were made for PTR_TO_BTF_ID. Only
reg->off was taken into account by btf_struct_ids_match, which protected
against type mismatch due to non-zero reg->off, but when reg->off was
zero, a user could set the variable offset of the register and allow it
to be passed to kfunc, leading to bad pointer being passed into the
kernel.
Fix this by reusing the extracted helper check_func_arg_reg_off from
previous commit, and make one call before checking all supported
register types. Since the list is maintained, any future changes will be
taken into account by updating check_func_arg_reg_off. This function
prevents non-zero var_off to be set for PTR_TO_BTF_ID, but still allows
a fixed non-zero reg->off, which is needed for type matching to work
correctly when using pointer arithmetic.
ARG_DONTCARE is passed as arg_type, since kfunc doesn't support
accepting a ARG_PTR_TO_ALLOC_MEM without relying on size of parameter
type from BTF (in case of pointer), or using a mem, len pair. The
forcing of offset check for ARG_PTR_TO_ALLOC_MEM is done because ringbuf
helpers obtain the size from the header located at the beginning of the
memory region, hence any changes to the original pointer shouldn't be
allowed. In case of kfunc, size is always known, either at verification
time, or using the length parameter, hence this forcing is not required.
Since this check will happen once already for PTR_TO_CTX, remove the
check_ptr_off_reg call inside its block.
Fixes: e6ac2450d6
("bpf: Support bpf program calling kernel function")
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20220304224645.3677453-3-memxor@gmail.com
This commit is contained in:
Родитель
25b35dd281
Коммит
655efe5089
|
@ -5726,7 +5726,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
|
||||||
const char *func_name, *ref_tname;
|
const char *func_name, *ref_tname;
|
||||||
const struct btf_type *t, *ref_t;
|
const struct btf_type *t, *ref_t;
|
||||||
const struct btf_param *args;
|
const struct btf_param *args;
|
||||||
int ref_regno = 0;
|
int ref_regno = 0, ret;
|
||||||
bool rel = false;
|
bool rel = false;
|
||||||
|
|
||||||
t = btf_type_by_id(btf, func_id);
|
t = btf_type_by_id(btf, func_id);
|
||||||
|
@ -5776,6 +5776,11 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
|
||||||
|
|
||||||
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
|
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
|
||||||
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
|
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
|
||||||
|
|
||||||
|
ret = check_func_arg_reg_off(env, reg, regno, ARG_DONTCARE);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (btf_get_prog_ctx_type(log, btf, t,
|
if (btf_get_prog_ctx_type(log, btf, t,
|
||||||
env->prog->type, i)) {
|
env->prog->type, i)) {
|
||||||
/* If function expects ctx type in BTF check that caller
|
/* If function expects ctx type in BTF check that caller
|
||||||
|
@ -5787,8 +5792,6 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
|
||||||
i, btf_type_str(t));
|
i, btf_type_str(t));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (check_ptr_off_reg(env, reg, regno))
|
|
||||||
return -EINVAL;
|
|
||||||
} else if (is_kfunc && (reg->type == PTR_TO_BTF_ID ||
|
} else if (is_kfunc && (reg->type == PTR_TO_BTF_ID ||
|
||||||
(reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type)))) {
|
(reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type)))) {
|
||||||
const struct btf_type *reg_ref_t;
|
const struct btf_type *reg_ref_t;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче