On Mon, Aug 30, 2021 at 11:04:17PM +0530, Kumar Kartikeya Dwivedi wrote: > This change adds support on the kernel side to allow for BPF programs to > call kernel module functions. Userspace will prepare an array of module > BTF fds that is passed in during BPF_PROG_LOAD. In the kernel, the > module BTF array is placed in the auxilliary struct for bpf_prog. > > The verifier then uses insn->off to index into this table. insn->off is > used by subtracting one from it, as userspace has to set the index of > array in insn->off incremented by 1. This lets us denote vmlinux btf by > insn->off == 0, and the prog->aux->kfunc_btf_tab[insn->off - 1] for > module BTFs. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> > --- > include/linux/bpf.h | 1 + > include/linux/filter.h | 9 ++++ > include/uapi/linux/bpf.h | 3 +- > kernel/bpf/core.c | 14 ++++++ > kernel/bpf/syscall.c | 55 +++++++++++++++++++++- > kernel/bpf/verifier.c | 85 ++++++++++++++++++++++++++-------- > tools/include/uapi/linux/bpf.h | 3 +- > 7 files changed, 147 insertions(+), 23 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index f4c16f19f83e..39f59e5f3a26 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -874,6 +874,7 @@ struct bpf_prog_aux { > void *jit_data; /* JIT specific data. arch dependent */ > struct bpf_jit_poke_descriptor *poke_tab; > struct bpf_kfunc_desc_tab *kfunc_tab; > + struct bpf_kfunc_btf_tab *kfunc_btf_tab; > u32 size_poke_tab; > struct bpf_ksym ksym; > const struct bpf_prog_ops *ops; > diff --git a/include/linux/filter.h b/include/linux/filter.h > index 7d248941ecea..46451891633d 100644 > --- a/include/linux/filter.h > +++ b/include/linux/filter.h > @@ -592,6 +592,15 @@ struct bpf_prog { > struct bpf_insn insnsi[]; > }; > > +#define MAX_KFUNC_DESCS 256 > +/* There can only be at most MAX_KFUNC_DESCS module BTFs for kernel module > + * function calls. > + */ > +struct bpf_kfunc_btf_tab { > + u32 nr_btfs; > + struct btf_mod_pair btfs[]; > +}; > + > struct sk_filter { > refcount_t refcnt; > struct rcu_head rcu; > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > index 791f31dd0abe..4cbb2082a553 100644 > --- a/include/uapi/linux/bpf.h > +++ b/include/uapi/linux/bpf.h > @@ -1334,8 +1334,9 @@ union bpf_attr { > /* or valid module BTF object fd or 0 to attach to vmlinux */ > __u32 attach_btf_obj_fd; > }; > - __u32 :32; /* pad */ > + __u32 kfunc_btf_fds_cnt; /* reuse hole for count of BTF fds below */ No need for size. > __aligned_u64 fd_array; /* array of FDs */ > + __aligned_u64 kfunc_btf_fds; /* array of BTF FDs for module kfunc support */ Just reuse fd_array. No need for another array of FDs. > + tab = prog->aux->kfunc_btf_tab; > + for (i = 0; i < n; i++) { > + struct btf_mod_pair *p; > + struct btf *mod_btf; > + > + mod_btf = btf_get_by_fd(fds[i]); > + if (IS_ERR(mod_btf)) { > + err = PTR_ERR(mod_btf); > + goto free_prog; > + } > + if (!btf_is_module(mod_btf)) { > + err = -EINVAL; > + btf_put(mod_btf); > + goto free_prog; > + } just do that dynamically like access to fd_array is handled in other places. no need to preload.