[PATCH v7 6/18] bpf: add BPF token support to BPF_PROG_LOAD command
Andrii Nakryiko
andrii.nakryiko at gmail.com
Fri Oct 13 21:55:24 UTC 2023
On Fri, Oct 13, 2023 at 2:15 PM Paul Moore <paul at paul-moore.com> wrote:
>
> On Oct 12, 2023 Andrii Nakryiko <andrii at kernel.org> wrote:
> >
> > Add basic support of BPF token to BPF_PROG_LOAD. Wire through a set of
> > allowed BPF program types and attach types, derived from BPF FS at BPF
> > token creation time. Then make sure we perform bpf_token_capable()
> > checks everywhere where it's relevant.
> >
> > Signed-off-by: Andrii Nakryiko <andrii at kernel.org>
> > ---
> > include/linux/bpf.h | 6 ++
> > include/uapi/linux/bpf.h | 2 +
> > kernel/bpf/core.c | 1 +
> > kernel/bpf/inode.c | 6 +-
> > kernel/bpf/syscall.c | 87 ++++++++++++++-----
> > kernel/bpf/token.c | 27 ++++++
> > tools/include/uapi/linux/bpf.h | 2 +
> > .../selftests/bpf/prog_tests/libbpf_probes.c | 2 +
> > .../selftests/bpf/prog_tests/libbpf_str.c | 3 +
> > 9 files changed, 110 insertions(+), 26 deletions(-)
>
> ...
>
> > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> > index a2c9edcbcd77..c6b00aee3b62 100644
> > --- a/kernel/bpf/syscall.c
> > +++ b/kernel/bpf/syscall.c
> > @@ -2584,13 +2584,15 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
> > }
> >
> > /* last field in 'union bpf_attr' used by this command */
> > -#define BPF_PROG_LOAD_LAST_FIELD log_true_size
> > +#define BPF_PROG_LOAD_LAST_FIELD prog_token_fd
> >
> > static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
> > {
> > enum bpf_prog_type type = attr->prog_type;
> > struct bpf_prog *prog, *dst_prog = NULL;
> > struct btf *attach_btf = NULL;
> > + struct bpf_token *token = NULL;
> > + bool bpf_cap;
> > int err;
> > char license[128];
> >
> > @@ -2606,10 +2608,31 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
> > BPF_F_XDP_DEV_BOUND_ONLY))
> > return -EINVAL;
> >
> > + bpf_prog_load_fixup_attach_type(attr);
> > +
> > + if (attr->prog_token_fd) {
> > + token = bpf_token_get_from_fd(attr->prog_token_fd);
> > + if (IS_ERR(token))
> > + return PTR_ERR(token);
> > + /* if current token doesn't grant prog loading permissions,
> > + * then we can't use this token, so ignore it and rely on
> > + * system-wide capabilities checks
> > + */
> > + if (!bpf_token_allow_cmd(token, BPF_PROG_LOAD) ||
> > + !bpf_token_allow_prog_type(token, attr->prog_type,
> > + attr->expected_attach_type)) {
> > + bpf_token_put(token);
> > + token = NULL;
> > + }
>
> At the start of this effort I mentioned how we wanted to have LSM
> control points when the token is created and when it is used. It is
> for this reason that we still want a hook inside the
> bpf_token_allow_cmd() function as it allows us to enable/disable use
> of the token when its use is first attempted. If the LSM decides to
> disallow use of the token in this particular case then the token is
> disabled (set to NULL) while the operation is still allowed to move
> forward, simply without the token. It's a much cleaner and well
> behaved approach as it allows the normal BPF access controls to do
> their work.
I see, ok, so you want to be able to say "no BPF token for you", but
not just error out the entire operation. Makes sense.
>
> > + }
> > +
> > + bpf_cap = bpf_token_capable(token, CAP_BPF);
>
> Similar to the above comment, we want to a LSM control point in
> bpf_token_capable() so that the LSM can control the token's
> ability to delegate capability privileges when they are used. Having
> to delay this access control point to security_bpf_prog_load() is not
> only awkward but it requires either manual synchronization between
> all of the different LSMs and the the capability checks in the
> bpf_prog_load() function or a completely different set of LSM
> permissions for a token-based BPF program load over a normal BPF
> program load.
>
> We really need these hooks Andrii, I wouldn't have suggested them if
> I didn't believe they were important.
No problem, I'll add both of them. I really didn't want to add hooks
for allow_{maps,progs,attachs} (which you agreed shouldn't be added,
so we are good), but I think allow_cmds and capable checks are fine.
Will add in the next revision.
>
> > + err = -EPERM;
> > +
> > if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
> > (attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
> > - !bpf_capable())
> > - return -EPERM;
> > + !bpf_cap)
> > + goto put_token;
> >
[...]
More information about the Linux-security-module-archive
mailing list