From 58e7d876ffd50a309b50fbc98dfb77150156f890 Mon Sep 17 00:00:00 2001 From: Etienne Perot Date: Fri, 28 Aug 2026 13:28:04 -0700 Subject: [PATCH] Fix `//test/syscalls:tcp_socket_test_native` failing on newer kernels. As of Linux commit 5d39580f68e6, SO_ATTACH_FILTER requires CAP_NET_ADMIN for TCP sockets. Skip in tests if we don't have it, and update Netstack to require it too. FUTURE_COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/14478 from EtiennePerot:socket-test-fix 2e2e65ee665a7d48e0358e58191d813174dac8cd PiperOrigin-RevId: 972759993 --- pkg/sentry/socket/netstack/netstack.go | 10 +++++++- test/syscalls/linux/BUILD | 1 + test/syscalls/linux/tcp_socket.cc | 32 +++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index de5092ee5ea..e1bdaba200d 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -36,6 +36,7 @@ import ( "golang.org/x/sys/unix" "google.golang.org/protobuf/proto" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/abi/linux/errno" "gvisor.dev/gvisor/pkg/context" @@ -2151,6 +2152,14 @@ func SetSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, name i }) return nil + case linux.SO_ATTACH_FILTER: + if socket.IsTCP(s) && + !t.HasCapabilityIn(linux.CAP_NET_ADMIN, t.NetworkNamespace().UserNamespace()) { + return syserr.ErrNotPermitted + } + incrementBadSetSocketOptionMetric(t, &socketLevelSocketFieldValue, name) + return nil + case linux.SO_DETACH_FILTER: // optval is ignored. var v tcpip.SocketDetachFilterOption @@ -2188,7 +2197,6 @@ func SetSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, name i linux.SO_BSDCOMPAT, linux.SO_PEERCRED, linux.SO_SNDLOWAT, - linux.SO_ATTACH_FILTER, linux.SO_PEERNAME, linux.SO_TIMESTAMP, linux.SO_ACCEPTCONN, diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD index 5532f54770f..6fd5698f0b0 100644 --- a/test/syscalls/linux/BUILD +++ b/test/syscalls/linux/BUILD @@ -4480,6 +4480,7 @@ cc_binary( linkstatic = 1, malloc = "//test/util:errno_safe_allocator", deps = select_gtest() + [ + "//test/util:capability_util", "//test/util:file_descriptor", "//test/util:posix_error", "//test/util:socket_util", diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc index 5caa0d6f751..fd4d8163012 100644 --- a/test/syscalls/linux/tcp_socket.cc +++ b/test/syscalls/linux/tcp_socket.cc @@ -38,6 +38,7 @@ #include "absl/status/statusor.h" #include "absl/time/clock.h" #include "absl/time/time.h" +#include "test/util/capability_util.h" #include "test/util/file_descriptor.h" #include "test/util/posix_error.h" #include "test/util/socket_util.h" @@ -2297,9 +2298,14 @@ TEST_P(SimpleTcpSocketTest, SetSocketAttachDetachFilter) { .len = std::size(code), .filter = code, }; - ASSERT_THAT( - setsockopt(s.get(), SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)), - SyscallSucceeds()); + int ret = + setsockopt(s.get(), SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); + if (ret < 0 && errno == EPERM) { + // Linux 5d39580f68e6 ("tcp: restrict SO_ATTACH_FILTER to priv users") + // requires CAP_NET_ADMIN over the socket's network namespace. + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN))); + } + ASSERT_THAT(ret, SyscallSucceeds()); constexpr int val = 0; ASSERT_THAT( @@ -2307,6 +2313,26 @@ TEST_P(SimpleTcpSocketTest, SetSocketAttachDetachFilter) { SyscallSucceeds()); } +TEST_P(SimpleTcpSocketTest, SetSocketAttachFilterWithoutNetAdmin) { + FileDescriptor s = + ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP)); + struct sock_filter code[] = {{0x6, 0, 0, 0x00040000}}; // ret 0x40000 + struct sock_fprog bpf = { + .len = std::size(code), + .filter = code, + }; + AutoCapability cap(CAP_NET_ADMIN, false); + int ret = + setsockopt(s.get(), SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); + if (!IsRunningOnGvisor() || IsRunningWithHostinet()) { + // Only Linux 5d39580f68e6 ("tcp: restrict SO_ATTACH_FILTER to priv + // users") and later requires CAP_NET_ADMIN, so this can succeed on + // old kernels (including with hostinet on an old kernel). + SKIP_IF(ret == 0); + } + EXPECT_THAT(ret, SyscallFailsWithErrno(EPERM)); +} + #endif // __linux__ TEST_P(SimpleTcpSocketTest, SetSocketDetachFilterNoInstalledFilter) {