Thread (23 messages) 23 messages, 3 authors, 2023-10-13

Re: [PATCH v7 6/18] bpf: add BPF token support to BPF_PROG_LOAD command

From: Andrii Nakryiko <hidden>
Date: 2023-10-13 21:55:38
Also in: bpf, linux-fsdevel, netdev

On Fri, Oct 13, 2023 at 2:15 PM Paul Moore [off-list ref] wrote:
On Oct 12, 2023 Andrii Nakryiko [off-list ref] wrote:
quoted
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@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(-)
...
quoted
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.
quoted
+     }
+
+     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.
quoted
+     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;
[...]
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help