bpf: Move unprivileged checks into map_create() and bpf_prog_load()
authorAndrii Nakryiko <andrii@kernel.org>
Tue, 13 Jun 2023 22:35:30 +0000 (15:35 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Mon, 19 Jun 2023 12:04:04 +0000 (14:04 +0200)
Make each bpf() syscall command a bit more self-contained, making it
easier to further enhance it. We move sysctl_unprivileged_bpf_disabled
handling down to map_create() and bpf_prog_load(), two special commands
in this regard.

Also swap the order of checks, calling bpf_capable() only if
sysctl_unprivileged_bpf_disabled is true, avoiding unnecessary audit
messages.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Stanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/bpf/20230613223533.3689589-2-andrii@kernel.org
kernel/bpf/syscall.c

index 12955415d376f19089d46649218bae3964ada4ad..7c41a623f405cbc46dfd444093aa09cd22f890c4 100644 (file)
@@ -1157,6 +1157,15 @@ static int map_create(union bpf_attr *attr)
             !node_online(numa_node)))
                return -EINVAL;
 
+       /* Intent here is for unprivileged_bpf_disabled to block BPF map
+        * creation for unprivileged users; other actions depend
+        * on fd availability and access to bpffs, so are dependent on
+        * object creation success. Even with unprivileged BPF disabled,
+        * capability checks are still carried out.
+        */
+       if (sysctl_unprivileged_bpf_disabled && !bpf_capable())
+               return -EPERM;
+
        /* find map type and init map: hashtable vs rbtree vs bloom vs ... */
        map = find_and_alloc_map(attr);
        if (IS_ERR(map))
@@ -2532,6 +2541,16 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
        /* eBPF programs must be GPL compatible to use GPL-ed functions */
        is_gpl = license_is_gpl_compatible(license);
 
+       /* Intent here is for unprivileged_bpf_disabled to block BPF program
+        * creation for unprivileged users; other actions depend
+        * on fd availability and access to bpffs, so are dependent on
+        * object creation success. Even with unprivileged BPF disabled,
+        * capability checks are still carried out for these
+        * and other operations.
+        */
+       if (sysctl_unprivileged_bpf_disabled && !bpf_capable())
+               return -EPERM;
+
        if (attr->insn_cnt == 0 ||
            attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS))
                return -E2BIG;
@@ -5030,23 +5049,8 @@ out_prog_put:
 static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
 {
        union bpf_attr attr;
-       bool capable;
        int err;
 
-       capable = bpf_capable() || !sysctl_unprivileged_bpf_disabled;
-
-       /* Intent here is for unprivileged_bpf_disabled to block key object
-        * creation commands for unprivileged users; other actions depend
-        * of fd availability and access to bpffs, so are dependent on
-        * object creation success.  Capabilities are later verified for
-        * operations such as load and map create, so even with unprivileged
-        * BPF disabled, capability checks are still carried out for these
-        * and other operations.
-        */
-       if (!capable &&
-           (cmd == BPF_MAP_CREATE || cmd == BPF_PROG_LOAD))
-               return -EPERM;
-
        err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);
        if (err)
                return err;