]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: Fix tcx/netkit detach permissions when prog fd isn't given
authorGuillaume Gonnet <ggonnet.linux@gmail.com>
Tue, 27 Jan 2026 16:02:00 +0000 (17:02 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 28 Jan 2026 02:39:58 +0000 (18:39 -0800)
This commit fixes a security issue where BPF_PROG_DETACH on tcx or
netkit devices could be executed by any user when no program fd was
provided, bypassing permission checks. The fix adds a capability
check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Fixes: e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")
Signed-off-by: Guillaume Gonnet <ggonnet.linux@gmail.com>
Link: https://lore.kernel.org/r/20260127160200.10395-1-ggonnet.linux@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf.h
include/linux/bpf_mprog.h
kernel/bpf/syscall.c

index 4427c6e9833196615d02468d78572c09e14f342a..9272a237cced25d38a18c6d28387819cc66a3906 100644 (file)
@@ -3362,6 +3362,11 @@ static inline void bpf_prog_report_arena_violation(bool write, unsigned long add
 }
 #endif /* CONFIG_BPF_SYSCALL */
 
+static inline bool bpf_net_capable(void)
+{
+       return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
+}
+
 static __always_inline int
 bpf_probe_read_kernel_common(void *dst, u32 size, const void *unsafe_ptr)
 {
index 929225f7b09594803a9480866dffa85d7efd86b1..0b9f4caeeb0a327795b16ef16c4802aaaf13c14c 100644 (file)
@@ -340,4 +340,14 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type)
                return false;
        }
 }
+
+static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
+{
+       switch (type) {
+       case BPF_PROG_TYPE_SCHED_CLS:
+               return bpf_net_capable();
+       default:
+               return false;
+       }
+}
 #endif /* __BPF_MPROG_H */
index b9184545c3fd09956c3917f2f83f4b782918e4be..5f59dd47a5b1c3b80652dabd64ad7853ac1db083 100644 (file)
@@ -1363,11 +1363,6 @@ free_map_tab:
        return ret;
 }
 
-static bool bpf_net_capable(void)
-{
-       return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
-}
-
 #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size
 /* called via syscall */
 static int map_create(union bpf_attr *attr, bpfptr_t uattr)
@@ -4579,6 +4574,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
                        prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
                        if (IS_ERR(prog))
                                return PTR_ERR(prog);
+               } else if (!bpf_mprog_detach_empty(ptype)) {
+                       return -EPERM;
                }
        } else if (is_cgroup_prog_type(ptype, 0, false)) {
                if (attr->attach_flags || attr->relative_fd)