On Thu, Oct 5, 2023 at 3:52 PM Jiri Olsa <olsajiri@xxxxxxxxx> wrote: > > On Thu, Oct 05, 2023 at 03:27:35PM +0200, KP Singh wrote: > > On Thu, Oct 5, 2023 at 3:26 PM KP Singh <kpsingh@xxxxxxxxxx> wrote: > > > > > > On Thu, Oct 5, 2023 at 10:09 AM Jiri Olsa <olsajiri@xxxxxxxxx> wrote: > > > > > > > > On Thu, Sep 28, 2023 at 10:24:09PM +0200, KP Singh wrote: > > > > > > > > SNIP > > > > > > > > > diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c > > > > > index e97aeda3a86b..df9699bce372 100644 > > > > > --- a/kernel/bpf/trampoline.c > > > > > +++ b/kernel/bpf/trampoline.c > > > > > @@ -13,6 +13,7 @@ > > > > > #include <linux/bpf_verifier.h> > > > > > #include <linux/bpf_lsm.h> > > > > > #include <linux/delay.h> > > > > > +#include <linux/bpf_lsm.h> > > > > > > > > > > /* dummy _ops. The verifier will operate on target program's ops. */ > > > > > const struct bpf_verifier_ops bpf_extension_verifier_ops = { > > > > > @@ -514,7 +515,7 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_tr > > > > > { > > > > > enum bpf_tramp_prog_type kind; > > > > > struct bpf_tramp_link *link_exiting; > > > > I think this is a typo here. It should be existing, no? > > yes, I was wondering about that as well ;-) > > jirka > > > > > > > > - int err = 0; > > > > > + int err = 0, num_lsm_progs = 0; > > > > > int cnt = 0, i; > > > > > > > > > > kind = bpf_attach_type_to_tramp(link->link.prog); > > > > > @@ -545,8 +546,14 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_tr > > > > > continue; > > > > > /* prog already linked */ > > > > > return -EBUSY; > > > > > + > > > > > + if (link_exiting->link.prog->type == BPF_PROG_TYPE_LSM) > > > > > + num_lsm_progs++; > > > > > > > > this looks wrong, it's never reached.. seems like we should add separate > > > > hlist_for_each_entry loop over trampoline's links for this check/init of > > > > num_lsm_progs ? > > > > > > > > jirka > > > > > > Good catch, I missed this during my rebase, after > > > https://lore.kernel.org/bpf/20220510205923.3206889-2-kuifeng@xxxxxx/ > > > this condition is basically never reached. I will do a general loop > > > over to count LSM programs and toggle the hook to true (and same for > > > unlink). So, there is something that is unclear about this code, i.e. what happens when there is an error from bpf_trampoline_update fails and the link and unlink seem to have different expectations: * link seems to go back to the linked list and removes the trampoline and restores the refcount: [...] err = bpf_trampoline_update(tr, true /* lock_direct_mutex */); if (err) { hlist_del_init(&link->tramp_hlist); tr->progs_cnt[kind]--; } return err; } * unlink does restore the side effect (i.e. it does not put the removed trampoline back and increments the refcount). hlist_del_init(&link->tramp_hlist); tr->progs_cnt[kind]--; return bpf_trampoline_update(tr, true /* lock_direct_mutex */); However, I think I will make it simpler and enforce the invariant that if an LSM program is attached, the hook is enabled and vice versa. How about: diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index df9699bce372..4f31384b5637 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -511,11 +511,30 @@ static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog) } } +static void bpf_trampoline_toggle_lsm(struct bpf_trampoline *tr, + enum bpf_tramp_prog_type kind) +{ + struct bpf_tramp_link *link; + volatile bool found = false; + + /* Loop through the links and if any LSM program is attached, ensure + * that the hook is enabled. + */ + hlist_for_each_entry(link, &tr->progs_hlist[kind], tramp_hlist) { + if (link->link.prog->type == BPF_PROG_TYPE_LSM) { + found = true; + break; + } + } + + bpf_lsm_toggle_hook(tr->func.addr, found); +} + static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr) { enum bpf_tramp_prog_type kind; struct bpf_tramp_link *link_exiting; - int err = 0, num_lsm_progs = 0; + int err = 0; int cnt = 0, i; kind = bpf_attach_type_to_tramp(link->link.prog); @@ -547,15 +566,14 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_tr /* prog already linked */ return -EBUSY; - if (link_exiting->link.prog->type == BPF_PROG_TYPE_LSM) - num_lsm_progs++; } - if (!num_lsm_progs && link->link.prog->type == BPF_PROG_TYPE_LSM) - bpf_lsm_toggle_hook(tr->func.addr, true); - hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]); tr->progs_cnt[kind]++; + + if (link->link.prog->type == BPF_PROG_TYPE_LSM) + bpf_trampoline_toggle_lsm(tr, kind); + err = bpf_trampoline_update(tr, true /* lock_direct_mutex */); if (err) { hlist_del_init(&link->tramp_hlist); @@ -578,7 +596,6 @@ static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link, struct bpf_ { struct bpf_tramp_link *link_exiting; enum bpf_tramp_prog_type kind; - bool lsm_link_found = false; int err, num_lsm_progs = 0; kind = bpf_attach_type_to_tramp(link->link.prog); @@ -595,18 +612,14 @@ static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link, struct bpf_ tramp_hlist) { if (link_exiting->link.prog->type == BPF_PROG_TYPE_LSM) num_lsm_progs++; - - if (link_exiting->link.prog == link->link.prog) - lsm_link_found = true; } } hlist_del_init(&link->tramp_hlist); tr->progs_cnt[kind]--; - if (lsm_link_found && num_lsm_progs == 1) - bpf_lsm_toggle_hook(tr->func.addr, false); - + if (link->link.prog->type == BPF_PROG_TYPE_LSM) + bpf_trampoline_toggle_lsm(tr, kind); return bpf_trampoline_update(tr, true /* lock_direct_mutex */); } - KP