On Mon, Mar 23, 2020 at 9:45 AM KP Singh <kpsingh@xxxxxxxxxxxx> wrote: > > From: KP Singh <kpsingh@xxxxxxxxxx> > > JITed BPF programs are dynamically attached to the LSM hooks > using BPF trampolines. The trampoline prologue generates code to handle > conversion of the signature of the hook to the appropriate BPF context. > > The allocated trampoline programs are attached to the nop functions > initialized as LSM hooks. > > BPF_PROG_TYPE_LSM programs must have a GPL compatible license and > and need CAP_SYS_ADMIN (required for loading eBPF programs). > > Upon attachment: > > * A BPF fexit trampoline is used for LSM hooks with a void return type. > * A BPF fmod_ret trampoline is used for LSM hooks which return an > int. The attached programs can override the return value of the > bpf LSM hook to indicate a MAC Policy decision. > > Signed-off-by: KP Singh <kpsingh@xxxxxxxxxx> > Reviewed-by: Brendan Jackman <jackmanb@xxxxxxxxxx> > Reviewed-by: Florent Revest <revest@xxxxxxxxxx> > --- > include/linux/bpf.h | 4 ++++ > include/linux/bpf_lsm.h | 11 +++++++++++ > kernel/bpf/bpf_lsm.c | 29 +++++++++++++++++++++++++++++ > kernel/bpf/btf.c | 9 ++++++++- > kernel/bpf/syscall.c | 26 ++++++++++++++++++++++---- > kernel/bpf/trampoline.c | 17 +++++++++++++---- > kernel/bpf/verifier.c | 19 +++++++++++++++---- > 7 files changed, 102 insertions(+), 13 deletions(-) > [...] > > +#define BPF_LSM_SYM_PREFX "bpf_lsm_" > + > +int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog, > + const struct bpf_prog *prog) > +{ > + /* Only CAP_MAC_ADMIN users are allowed to make changes to LSM hooks > + */ > + if (!capable(CAP_MAC_ADMIN)) > + return -EPERM; > + > + if (!prog->gpl_compatible) { > + bpf_log(vlog, > + "LSM programs must have a GPL compatible license\n"); > + return -EINVAL; > + } > + > + if (strncmp(BPF_LSM_SYM_PREFX, prog->aux->attach_func_name, > + strlen(BPF_LSM_SYM_PREFX))) { sizeof(BPF_LSM_SYM_PREFIX) - 1? > + bpf_log(vlog, "attach_btf_id %u points to wrong type name %s\n", > + prog->aux->attach_btf_id, prog->aux->attach_func_name); > + return -EINVAL; > + } > + > + return 0; > +} > + [...] > @@ -2367,10 +2369,24 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog) > struct file *link_file; > int link_fd, err; > > - if (prog->expected_attach_type != BPF_TRACE_FENTRY && > - prog->expected_attach_type != BPF_TRACE_FEXIT && > - prog->expected_attach_type != BPF_MODIFY_RETURN && > - prog->type != BPF_PROG_TYPE_EXT) { > + switch (prog->type) { > + case BPF_PROG_TYPE_TRACING: > + if (prog->expected_attach_type != BPF_TRACE_FENTRY && > + prog->expected_attach_type != BPF_TRACE_FEXIT && > + prog->expected_attach_type != BPF_MODIFY_RETURN) { > + err = -EINVAL; > + goto out_put_prog; > + } > + break; > + case BPF_PROG_TYPE_EXT: It looks like an omission that we don't enforce expected_attach_type to be 0 here. Should we fix it until it's too late? > + break; > + case BPF_PROG_TYPE_LSM: > + if (prog->expected_attach_type != BPF_LSM_MAC) { > + err = -EINVAL; > + goto out_put_prog; > + } > + break; > + default: > err = -EINVAL; > goto out_put_prog; > } > @@ -2452,12 +2468,14 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr) > if (prog->type != BPF_PROG_TYPE_RAW_TRACEPOINT && > prog->type != BPF_PROG_TYPE_TRACING && > prog->type != BPF_PROG_TYPE_EXT && > + prog->type != BPF_PROG_TYPE_LSM && > prog->type != BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE) { > err = -EINVAL; > goto out_put_prog; > } > > if (prog->type == BPF_PROG_TYPE_TRACING || > + prog->type == BPF_PROG_TYPE_LSM || > prog->type == BPF_PROG_TYPE_EXT) { can you please refactor this into a nicer explicit switch instead of combination of if/elses? > if (attr->raw_tracepoint.name) { > /* The attach point for this category of programs > diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c > index f30bca2a4d01..9be85aa4ec5f 100644 > --- a/kernel/bpf/trampoline.c > +++ b/kernel/bpf/trampoline.c > @@ -6,6 +6,7 @@ > #include <linux/ftrace.h> > #include <linux/rbtree_latch.h> > #include <linux/perf_event.h> > +#include <linux/btf.h> > [...]