Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion pkg/sentry/socket/netstack/netstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions test/syscalls/linux/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
31 changes: 28 additions & 3 deletions test/syscalls/linux/tcp_socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -2297,16 +2298,40 @@ 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(
setsockopt(s.get(), SOL_SOCKET, SO_DETACH_FILTER, &val, sizeof(val)),
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) {
Expand Down
Loading