[PATCH v8 bpf-next 17/18] selftests/bpf: add BPF token-enabled tests

Andrii Nakryiko andrii.nakryiko at gmail.com
Tue Oct 17 17:44:00 UTC 2023


On Tue, Oct 17, 2023 at 10:32 AM Andrii Nakryiko
<andrii.nakryiko at gmail.com> wrote:
>
> On Tue, Oct 17, 2023 at 4:02 AM Jiri Olsa <olsajiri at gmail.com> wrote:
> >
> > On Mon, Oct 16, 2023 at 11:02:19AM -0700, Andrii Nakryiko wrote:
> > > Add a selftest that attempts to conceptually replicate intended BPF
> > > token use cases inside user namespaced container.
> > >
> > > Child process is forked. It is then put into its own userns and mountns.
> > > Child creates BPF FS context object and sets it up as desired. This
> > > ensures child userns is captures as owning userns for this instance of
> > > BPF FS.
> > >
> > > This context is passed back to privileged parent process through Unix
> > > socket, where parent creates and mounts it as a detached mount. This
> > > mount FD is passed back to the child to be used for BPF token creation,
> > > which allows otherwise privileged BPF operations to succeed inside
> > > userns.
> > >
> > > We validate that all of token-enabled privileged commands (BPF_BTF_LOAD,
> > > BPF_MAP_CREATE, and BPF_PROG_LOAD) work as intended. They should only
> > > succeed inside the userns if a) BPF token is provided with proper
> > > allowed sets of commands and types; and b) namespaces CAP_BPF and other
> > > privileges are set. Lacking a) or b) should lead to -EPERM failures.
> > >
> > > Based on suggested workflow by Christian Brauner ([0]).
> > >
> > >   [0] https://lore.kernel.org/bpf/20230704-hochverdient-lehne-eeb9eeef785e@brauner/
> > >
> > > Signed-off-by: Andrii Nakryiko <andrii at kernel.org>
> > > ---
> > >  .../testing/selftests/bpf/prog_tests/token.c  | 629 ++++++++++++++++++
> > >  1 file changed, 629 insertions(+)
> > >  create mode 100644 tools/testing/selftests/bpf/prog_tests/token.c
> > >
> > > diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c
> > > new file mode 100644
> > > index 000000000000..41cee6b4731e
> > > --- /dev/null
> > > +++ b/tools/testing/selftests/bpf/prog_tests/token.c
> > > @@ -0,0 +1,629 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
> > > +#define _GNU_SOURCE
> > > +#include <test_progs.h>
> > > +#include <bpf/btf.h>
> > > +#include "cap_helpers.h"
> > > +#include <fcntl.h>
> > > +#include <sched.h>
> > > +#include <signal.h>
> > > +#include <unistd.h>
> > > +#include <linux/filter.h>
> > > +#include <linux/unistd.h>
> > > +#include <sys/mount.h>
> > > +#include <sys/socket.h>
> > > +#include <sys/syscall.h>
> > > +#include <sys/un.h>
> > > +
> > > +/* copied from include/uapi/linux/mount.h, as including it conflicts with
> > > + * sys/mount.h include
> > > + */
> > > +enum fsconfig_command {
> > > +     FSCONFIG_SET_FLAG       = 0,    /* Set parameter, supplying no value */
> > > +     FSCONFIG_SET_STRING     = 1,    /* Set parameter, supplying a string value */
> > > +     FSCONFIG_SET_BINARY     = 2,    /* Set parameter, supplying a binary blob value */
> > > +     FSCONFIG_SET_PATH       = 3,    /* Set parameter, supplying an object by path */
> > > +     FSCONFIG_SET_PATH_EMPTY = 4,    /* Set parameter, supplying an object by (empty) path */
> > > +     FSCONFIG_SET_FD         = 5,    /* Set parameter, supplying an object by fd */
> > > +     FSCONFIG_CMD_CREATE     = 6,    /* Invoke superblock creation */
> > > +     FSCONFIG_CMD_RECONFIGURE = 7,   /* Invoke superblock reconfiguration */
> > > +};
> >
> > I'm getting compilation fail, because fsconfig_command seems to be
> > included through the sys/mount.h include, but CI is green hum :-\
> >
> > when I get -E output I can see:
> >
> >         ...
> >         # 16 "./cap_helpers.h"
> >         int cap_enable_effective(__u64 caps, __u64 *old_caps);
> >         int cap_disable_effective(__u64 caps, __u64 *old_caps);
> >         # 7 "/home/jolsa/kernel/linux-qemu/tools/testing/selftests/bpf/prog_tests/token.c" 2
> >
> >         # 1 "/usr/include/sys/mount.h" 1 3 4
> >         # 27 "/usr/include/sys/mount.h" 3 4
> >         # 1 "/usr/lib/gcc/x86_64-redhat-linux/13/include/stddef.h" 1 3 4
> >         # 28 "/usr/include/sys/mount.h" 2 3 4
> >
> >         # 1 "/home/jolsa/kernel/linux-qemu/tools/include/uapi/linux/mount.h" 1 3 4
> >         # 96 "/home/jolsa/kernel/linux-qemu/tools/include/uapi/linux/mount.h" 3 4
> >
> >         # 96 "/home/jolsa/kernel/linux-qemu/tools/include/uapi/linux/mount.h" 3 4
> >         enum fsconfig_command {
> >          FSCONFIG_SET_FLAG = 0,
> >          FSCONFIG_SET_STRING = 1,
> >          FSCONFIG_SET_BINARY = 2,
> >          FSCONFIG_SET_PATH = 3,
> >          FSCONFIG_SET_PATH_EMPTY = 4,
> >          FSCONFIG_SET_FD = 5,
> >          FSCONFIG_CMD_CREATE = 6,
> >          FSCONFIG_CMD_RECONFIGURE = 7,
> >         };
> >
> >
> >         ...
> >
> >
> >         # 21 "/home/jolsa/kernel/linux-qemu/tools/testing/selftests/bpf/prog_tests/token.c"
> >         enum fsconfig_command {
> >          FSCONFIG_SET_FLAG = 0,
> >          FSCONFIG_SET_STRING = 1,
> >          FSCONFIG_SET_BINARY = 2,
> >          FSCONFIG_SET_PATH = 3,
> >          FSCONFIG_SET_PATH_EMPTY = 4,
> >          FSCONFIG_SET_FD = 5,
> >          FSCONFIG_CMD_CREATE = 6,
> >          FSCONFIG_CMD_RECONFIGURE = 7,
> >         };
> >
> >
> > it's probably included through this bit in the /usr/include/sys/mount.h:
> >
> >         #ifdef __has_include
> >         # if __has_include ("linux/mount.h")
> >         #  include "linux/mount.h"
> >         # endif
> >         #endif
> >
> > which was added 'recently' in https://sourceware.org/git/?p=glibc.git;a=commit;h=774058d72942249f71d74e7f2b639f77184160a6
> >
> > maybe you use older glibs headers? or perhaps it might be my build setup
>
> No, I'm pretty sure I have older headers. I'd like this to work in
> both environments, so I need to fix this. I'll try to make this work
> with uapi header, I guess. Thanks for reporting!
>

Ok, I just dropped sys/mount.h include and defined my own

static inline int sys_mount(const char *dev_name, const char *dir_name,
                            const char *type, unsigned long flags,
                            const void *data)
{
        return syscall(__NR_mount, dev_name, dir_name, type, flags, data);
}


That was the only thing I needed sys/mount.h for. So consider this fixed.


> >
> > jirka
> >
>
> [...]



More information about the Linux-security-module-archive mailing list