On Mon, Jun 29, 2020 at 06:52:21PM -0700, Andrii Nakryiko wrote: > 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. yea, it's one of the reasons I added extra function for that in first version > > 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. right, that's mistake, I was after path under struct file, and did not realize this needs to be generic thanks, jirka > > > + 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; > > + } > > [...] >