Skip to contentSkip to conversation

tcp: restrict SO_ATTACH_BPF to privileged users

PATCH NAK Manjunath Patil 2 participants 3 messages Oct 28

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 tcp: restrict SO_ATTACH_BPF to privileged users

Commit 5d39580f68e6 ("tcp: restrict SO_ATTACH_FILTER to priv users") requires CAP_NET_ADMIN to attach a classic BPF filter to a TCP socket. However, a caller can still attach an eBPF socket filter through SO_ATTACH_BPF without this capability. Both options install a filter that runs on incoming TCP packets.

Disabling unprivileged BPF loading does not close this gap: a caller that already holds a socket-filter program file descriptor can still use SO_ATTACH_BPF.

Use one CAP_NET_ADMIN check for both attachment options before taking the socket lock. Use the same namespace-aware capability helper already used by SO_ATTACH_FILTER. Leave other socket types unchanged.

Fixes 5d39580f68e6 ("tcp: restrict SO_ATTACH_FILTER to priv users")
Assisted-by Codex:gpt-6
---
 net/core/sock.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
net/core/sock.c +6 -5
index e7405be8941f..5f6d8b9ff4f6 100644
@@ -1310,6 +1310,12 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
 					optlen, optname == SO_RCVTIMEO_OLD);
 	}
 
+	/* Restrict TCP socket filters to prevent sequence/ack-number probing. */
+	if ((optname == SO_ATTACH_FILTER || optname == SO_ATTACH_BPF) &&
+	    sk_is_tcp(sk) &&
+	    !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
+		return -EPERM;
+
 	sockopt_lock_sock(sk);
 
 	switch (optname) {
@@ -1466,11 +1472,6 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
 	case SO_ATTACH_FILTER: {
 		struct sock_fprog fprog;
 
-		if (sk_is_tcp(sk) &&
-		    !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
-			ret = -EPERM;
-			break;
-		}
 		ret = copy_bpf_fprog_from_user(&fprog, optval, optlen);
 		if (!ret)
 			ret = sk_attach_filter(&fprog, sk);

base-commit: 65ba8f34ec886ec72b2c07ddc8cf3d815c32869d

Signature · 1 line
2.52.0
#1 lore raw
Quoted 5 lines · Manjunath Patil

Commit 5d39580f68e6 ("tcp: restrict SO_ATTACH_FILTER to priv users") requires CAP_NET_ADMIN to attach a classic BPF filter to a TCP socket. However, a caller can still attach an eBPF socket filter through SO_ATTACH_BPF without this capability. Both options install a filter that runs on incoming TCP packets.

Nack.
SO_ATTACH_FILTER takes insns that the caller wrote. SO_ATTACH_BPF takes a prog FD, and BPF_PROG_LOAD is the gate for it. unprivileged_bpf_disabled is 2 by default, so the load needs CAP_BPF. An admin who sets it to 0 allows every user to load socket filters.

Quoted 3 lines

Disabling unprivileged BPF loading does not close this gap: a caller that already holds a socket-filter program file descriptor can still use SO_ATTACH_BPF.

That's not a gap. The FD is the permission.
A process with CAP_BPF loads the prog and passes the FD to a process without caps. See the comment in bpf_prog_load() and
commit c8644cd0efe7 ("bpf: refine kernel.unprivileged_bpf_disabled behaviour"). This patch breaks it. It also breaks a process that has CAP_BPF and doesn't have CAP_NET_ADMIN.

pw-bot: cr

#2 lore raw

Hi,

Quoted 10 lines · Alexei Starovoitov

On Wed, Oct 28, 2026 at 02: 58 PM Manjunath Patil <manjunath. b. patil@  oracle. com> wrote: > Commit 5d39580f68e6 ("tcp: restrict SO_ATTACH_FILTER to priv users") > requires CAP_NET_ADMIN to attach a classic BPF filter to a TCP socket.

Quoted 5 lines · Manjunath Patil

Commit 5d39580f68e6 ("tcp: restrict SO_ATTACH_FILTER to priv users") requires CAP_NET_ADMIN to attach a classic BPF filter to a TCP socket. However, a caller can still attach an eBPF socket filter through SO_ATTACH_BPF without this capability. Both options install a filter that runs on incoming TCP packets.

Quoted 3 lines

Nack.
SO_ATTACH_FILTER takes insns that the caller wrote. SO_ATTACH_BPF takes a prog FD, and BPF_PROG_LOAD is the gate for it.

Thanks for the explanation. I overlooked this distinction and treated the different attachment checks as a missing permission check.

Quoted 10 lines

unprivileged_bpf_disabled is 2 by default, so the load needs CAP_BPF. An admin who sets it to 0 allows every user to load socket filters.

Quoted 3 lines

Disabling unprivileged BPF loading does not close this gap: a caller that already holds a socket-filter program file descriptor can still use SO_ATTACH_BPF.

That's not a gap. The FD is the permission.
A process with CAP_BPF loads the prog and passes the FD to a process without caps.

My test loaded the socket-filter program as root, then retained its FD in a worker that dropped its capabilities. That exercises supported delegation; it does not establish a security bypass.

See the comment in bpf_prog_load() and

Quoted 3 lines

commit c8644cd0efe7 ("bpf: refine kernel.unprivileged_bpf_disabled behaviour"). This patch breaks it. It also breaks a process that has CAP_BPF and doesn't have CAP_NET_ADMIN.

I agree. I am withdrawing this patch.

-Thanks,
Manjunath>

Quoted 2 lines

pw-bot: cr