From 2962329f7c86fc51c177d4049c0f15a95ebd270c Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sun, 1 Nov 2026 19:05:21 +0000 Subject: [PATCH] bpf: Require prog fd or capability for cgroup detach Since the commit below a cgroup prog detach does not require CAP_NET_ADMIN. The fd of the attached prog gives the permission instead. But the detach requires this fd only with BPF_F_ALLOW_MULTI. Without this flag a cgroup has only one prog per attach type. Then find_detach_entry() returns this prog and does not compare it with the prog of the caller. Thus the kernel detaches this prog for a caller with neither the fd nor a capability. Compare the two progs. If they are different, require CAP_NET_ADMIN or CAP_SYS_ADMIN in the initial user namespace. The error is -EPERM. A detach from tcx or netkit without a prog fd already requires these capabilities. With BPF_F_ALLOW_MULTI nothing changes. Without these capabilities, a caller of bpf_prog_detach() of libbpf must now use bpf_prog_detach2() with the fd of the attached prog. Fixes: 2c78ee898d8f ("bpf: Implement CAP_BPF") Signed-off-by: Chris Mason Signed-off-by: Alexei Starovoitov Link: https://patch.msgid.link/20261101190535.1454146-14-alexei.starovoitov@gmail.com --- kernel/bpf/cgroup.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index ce82963bcfc7..ca681d626c9e 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1279,9 +1279,14 @@ static struct bpf_prog_list *find_detach_entry(struct hlist_head *progs, return ERR_PTR(-ENOENT); /* to maintain backward compatibility NONE and OVERRIDE cgroups - * allow detaching with invalid FD (prog==NULL) in legacy mode + * allow detaching with invalid FD (prog==NULL) in legacy mode. + * Without the FD of the attached program the caller needs + * CAP_NET_ADMIN or CAP_SYS_ADMIN in the initial user namespace. */ - return hlist_entry(progs->first, typeof(*pl), node); + pl = hlist_entry(progs->first, typeof(*pl), node); + if (pl->prog != prog && !bpf_net_capable()) + return ERR_PTR(-EPERM); + return pl; } if (!prog && !link)