On Wed, Jul 22, 2020 at 2:13 PM Jiri Olsa <jolsa@xxxxxxxxxx> wrote: > > Adding btf_struct_ids_match function to check if given address provided > by BTF object + offset is also address of another nested BTF object. > > This allows to pass an argument to helper, which is defined via parent > BTF object + offset, like for bpf_d_path (added in following changes): > > SEC("fentry/filp_close") > int BPF_PROG(prog_close, struct file *file, void *id) > { > ... > ret = bpf_d_path(&file->f_path, ... > > The first bpf_d_path argument is hold by verifier as BTF file object > plus offset of f_path member. > > The btf_struct_ids_match function will walk the struct file object and > check if there's nested struct path object on the given offset. > > Signed-off-by: Jiri Olsa <jolsa@xxxxxxxxxx> > --- > include/linux/bpf.h | 2 ++ > kernel/bpf/btf.c | 29 +++++++++++++++++++++++++++++ > kernel/bpf/verifier.c | 18 ++++++++++++------ > 3 files changed, 43 insertions(+), 6 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index bae557ff2da8..c981e258fed3 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1306,6 +1306,8 @@ int btf_struct_access(struct bpf_verifier_log *log, > const struct btf_type *t, int off, int size, > enum bpf_access_type atype, > u32 *next_btf_id); > +bool btf_struct_ids_match(struct bpf_verifier_log *log, > + int off, u32 id, u32 mid); > int btf_resolve_helper_id(struct bpf_verifier_log *log, > const struct bpf_func_proto *fn, int); > > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > index 1ab5fd5bf992..562d4453fad3 100644 > --- a/kernel/bpf/btf.c > +++ b/kernel/bpf/btf.c > @@ -4140,6 +4140,35 @@ int btf_struct_access(struct bpf_verifier_log *log, > return -EINVAL; > } > > +bool btf_struct_ids_match(struct bpf_verifier_log *log, > + int off, u32 id, u32 mid) > +{ > + const struct btf_type *type; > + u32 nid; > + int err; > + mid and nid are terrible names, especially as an input argument name. mid == need_type_id? nid == cur_type_id or something along those lines? > + do { > + type = btf_type_by_id(btf_vmlinux, id); > + if (!type) > + return false; > + err = btf_struct_walk(log, type, off, 1, &nid); > + if (err < 0) > + return false; > + > + /* We found nested struct object. If it matches > + * the requested ID, we're done. Otherwise let's > + * continue the search with offset 0 in the new > + * type. > + */ > + if (err == walk_struct && mid == nid) > + return true; > + off = 0; > + id = nid; > + } while (err == walk_struct); This seems like a slightly more obvious control flow: again: ... if (err != walk_struct) return false; if (mid != nid) { off = 0; id = nid; goto again; } return true; > + > + return false; > +} > + > int btf_resolve_helper_id(struct bpf_verifier_log *log, > const struct bpf_func_proto *fn, int arg) > { [...]