On Thu, Jun 25, 2020 at 4:49 PM Jiri Olsa <jolsa@xxxxxxxxxx> wrote: > > Adding btf_struct_address function that takes 2 BTF objects > and offset as arguments and checks whether object A is nested > in object B on given offset. > > This function will be used when checking the helper function > PTR_TO_BTF_ID arguments. If the argument has an offset value, > the btf_struct_address will check if the final address is > the expected BTF ID. > > This way we can access nested BTF objects under PTR_TO_BTF_ID > pointer type and pass them to helpers, while they still point > to valid kernel BTF objects. > > Using btf_struct_access to implement new btf_struct_address > function, because it already walks down the given BTF object. > > Signed-off-by: Jiri Olsa <jolsa@xxxxxxxxxx> > --- This logic is very hard to follow. Each type I try to review it, I get lost very fast. TBH, this access_data struct is not just not helpful, but actually just complicates everything. I'll get to this tomorrow morning with fresh brains and will try to do another pass. [...] > int btf_resolve_helper_id(struct bpf_verifier_log *log, > const struct bpf_func_proto *fn, int arg) > { > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 7de98906ddf4..da7351184295 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -3808,6 +3808,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, > struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; > enum bpf_reg_type expected_type, type = reg->type; > enum bpf_arg_type arg_type = fn->arg_type[arg]; > + const struct btf_type *btf_type; > int err = 0; > > if (arg_type == ARG_DONTCARE) > @@ -3887,24 +3888,34 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, > expected_type = PTR_TO_BTF_ID; > if (type != expected_type) > goto err_type; > - if (!fn->check_btf_id) { > - if (reg->btf_id != meta->btf_id) { > - verbose(env, "Helper has type %s got %s in R%d\n", > + if (reg->off) { This non-zero offset only logic looks fishy, tbh. What if the struct you are trying to access is at offset zero? E.g., bpf_link is pretty much always a first field of whatever specific link struct it is contained within. The fact that we allow only non-zero offsets for such use case looks like an arbitrary limitation. > + btf_type = btf_type_by_id(btf_vmlinux, reg->btf_id); > + if (btf_struct_address(&env->log, btf_type, reg->off, meta->btf_id)) { > + verbose(env, "Helper has type %s got %s in R%d, off %d\n", > kernel_type_name(meta->btf_id), > + kernel_type_name(reg->btf_id), regno, reg->off); > + return -EACCES; > + } [...]