diff --git a/pkg/sentry/socket/hostinet/socket_unsafe.go b/pkg/sentry/socket/hostinet/socket_unsafe.go index 4e62571d4..2ee703207 100644 --- a/pkg/sentry/socket/hostinet/socket_unsafe.go +++ b/pkg/sentry/socket/hostinet/socket_unsafe.go @@ -222,7 +222,11 @@ func accept4(fd int, addr *byte, addrlen *uint32, flags int) (int, error) { func getsockopt(fd int, level, name int, opt []byte) ([]byte, error) { optlen32 := int32(len(opt)) - _, _, errno := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(firstBytePtr(opt)), uintptr(unsafe.Pointer(&optlen32)), 0) + var optPtr uintptr + if optlen32 > 0 { + optPtr = uintptr(firstBytePtr(opt)) + } + _, _, errno := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), optPtr, uintptr(unsafe.Pointer(&optlen32)), 0) if errno != 0 { return nil, errno } diff --git a/pkg/sentry/socket/hostinet/sockopt.go b/pkg/sentry/socket/hostinet/sockopt.go index bc14ebee3..db6fc9859 100644 --- a/pkg/sentry/socket/hostinet/sockopt.go +++ b/pkg/sentry/socket/hostinet/sockopt.go @@ -50,6 +50,8 @@ type SockOpt struct { // SockOpts are the socket options supported by hostinet. var SockOpts = []SockOpt{ + {linux.SOL_IP, linux.IP_MULTICAST_LOOP, sizeofInt32, true, true}, + {linux.SOL_IP, linux.IP_MULTICAST_TTL, sizeofInt32, true, true}, {linux.SOL_IP, linux.IP_PKTINFO, sizeofInt32, true, true}, {linux.SOL_IP, linux.IP_RECVERR, sizeofInt32, true, true}, {linux.SOL_IP, linux.IP_RECVORIGDSTADDR, sizeofInt32, true, true}, @@ -70,21 +72,28 @@ var SockOpts = []SockOpt{ {linux.SOL_SOCKET, linux.SO_ACCEPTCONN, sizeofInt32, true, true}, {linux.SOL_SOCKET, linux.SO_BROADCAST, sizeofInt32, true, true}, - {linux.SOL_SOCKET, linux.SO_ERROR, sizeofInt32, false, true}, + {linux.SOL_SOCKET, linux.SO_ERROR, sizeofInt32, true, false}, {linux.SOL_SOCKET, linux.SO_KEEPALIVE, sizeofInt32, true, true}, {linux.SOL_SOCKET, linux.SO_LINGER, linux.SizeOfLinger, true, true}, + {linux.SOL_SOCKET, linux.SO_OOBINLINE, sizeofInt32, true, true}, {linux.SOL_SOCKET, linux.SO_RCVBUF, sizeofInt32, true, true}, {linux.SOL_SOCKET, linux.SO_REUSEADDR, sizeofInt32, true, true}, {linux.SOL_SOCKET, linux.SO_SNDBUF, sizeofInt32, true, true}, {linux.SOL_SOCKET, linux.SO_TIMESTAMP, sizeofInt32, true, true}, - {linux.SOL_SOCKET, linux.SO_TYPE, sizeofInt32, false, true}, + {linux.SOL_SOCKET, linux.SO_TYPE, sizeofInt32, true, false}, {linux.SOL_TCP, linux.TCP_CONGESTION, 0 /* string */, true, true}, + {linux.SOL_TCP, linux.TCP_CORK, sizeofInt32, true, true}, {linux.SOL_TCP, linux.TCP_DEFER_ACCEPT, sizeofInt32, true, true}, {linux.SOL_TCP, linux.TCP_INFO, uint64(linux.SizeOfTCPInfo), true, false}, {linux.SOL_TCP, linux.TCP_INQ, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_KEEPCNT, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_KEEPIDLE, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_KEEPINTVL, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_LINGER2, sizeofInt32, true, true}, {linux.SOL_TCP, linux.TCP_MAXSEG, sizeofInt32, true, true}, {linux.SOL_TCP, linux.TCP_NODELAY, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_QUICKACK, sizeofInt32, true, true}, {linux.SOL_TCP, linux.TCP_SYNCNT, sizeofInt32, true, true}, {linux.SOL_TCP, linux.TCP_USER_TIMEOUT, sizeofInt32, true, true}, {linux.SOL_TCP, linux.TCP_WINDOW_CLAMP, sizeofInt32, true, true}, @@ -139,6 +148,9 @@ func (s *Socket) GetSockOpt(t *kernel.Task, level, name int, optValAddr hostarch if !ok { return nil, syserr.ErrProtocolNotAvailable } + if !sockOpt.AllowGet { + return nil, syserr.ErrInvalidArgument + } var opt []byte if sockOpt.Size > 0 { // Validate size of input buffer. @@ -206,6 +218,9 @@ func (s *Socket) SetSockOpt(t *kernel.Task, level, name int, opt []byte) *syserr // seems dangerous, but it's what netstack does... return nil } + if !sockOpt.AllowSet { + return syserr.ErrInvalidArgument + } if sockOpt.Size > 0 { if uint64(len(opt)) < sockOpt.Size { return syserr.ErrInvalidArgument diff --git a/test/syscalls/BUILD b/test/syscalls/BUILD index 2fb39de92..cf9a89b97 100644 --- a/test/syscalls/BUILD +++ b/test/syscalls/BUILD @@ -734,6 +734,7 @@ syscall_test( syscall_test( size = "large", + add_hostinet = True, shard_count = most_shards, test = "//test/syscalls/linux:socket_ip_tcp_generic_loopback_test", ) diff --git a/test/syscalls/linux/socket_generic_test_cases.cc b/test/syscalls/linux/socket_generic_test_cases.cc index e9e24b14a..ca0a5828b 100644 --- a/test/syscalls/linux/socket_generic_test_cases.cc +++ b/test/syscalls/linux/socket_generic_test_cases.cc @@ -958,7 +958,7 @@ TEST_P(AllSocketPairTest, GetSocketRcvbufOption) { SyscallSucceeds()); ASSERT_EQ(opt_len, sizeof(opt)); - if (IsRunningOnGvisor()) { + if (IsRunningOnGvisor() && !IsRunningWithHostinet()) { // Minimum buffer size in gVisor is 4KiB. const int minRcvBufSizeGvisor = 4096; EXPECT_EQ(opt, minRcvBufSizeGvisor); @@ -991,7 +991,7 @@ TEST_P(AllSocketPairTest, GetSetSocketRcvlowatOption) { SyscallSucceeds()); ASSERT_EQ(opt_len, sizeof(opt)); - if (IsRunningOnGvisor()) { + if (IsRunningOnGvisor() && !IsRunningWithHostinet()) { // TODO(b/226603727): Add support for setting SO_RCVLOWAT option in gVisor. EXPECT_EQ(opt, defaultSz); } else { diff --git a/test/syscalls/linux/socket_ip_tcp_generic.cc b/test/syscalls/linux/socket_ip_tcp_generic.cc index e9d7509c5..9de5231e4 100644 --- a/test/syscalls/linux/socket_ip_tcp_generic.cc +++ b/test/syscalls/linux/socket_ip_tcp_generic.cc @@ -1273,7 +1273,7 @@ TEST_P(TCPSocketPairTest, SetAndGetLingerOption) { // Linux returns a different value as it uses HZ to convert the seconds to // jiffies which overflows for negative values. We want to be compatible with // linux for getsockopt return value. - if (IsRunningOnGvisor()) { + if (IsRunningOnGvisor() && !IsRunningWithHostinet()) { EXPECT_EQ(sl.l_linger, got_linger.l_linger); }