From 007a91a911084e46efffc4e2531ff8dee5cf1917 Mon Sep 17 00:00:00 2001 From: Nayana Bidari Date: Tue, 29 Mar 2022 15:46:02 -0700 Subject: [PATCH] Silence the error log message for SO_RCVLOWAT option. Removed the unimplemented syscall message for SO_RCVLOWAT option and added a test for {g,s}etsockopt. PiperOrigin-RevId: 438145815 --- pkg/sentry/socket/netstack/netstack.go | 19 ++++++++++++ pkg/sentry/socket/socket.go | 1 - pkg/tcpip/socketops.go | 18 +++++++++++ .../linux/socket_generic_test_cases.cc | 30 +++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index 80779299a..6e917696d 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -1064,6 +1064,14 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam vP := primitive.Int32(boolToInt32(v)) return &vP, nil + case linux.SO_RCVLOWAT: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } + + v := primitive.Int32(ep.SocketOptions().GetRcvlowat()) + return &v, nil + default: socket.GetSockOptEmitUnimplementedEvent(t, name) } @@ -2002,6 +2010,17 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam var v tcpip.SocketDetachFilterOption return syserr.TranslateNetstackError(ep.SetSockOpt(&v)) + // TODO(b/226603727): Add support for SO_RCVLOWAT option. For now, only + // the unsupported syscall message is removed. + case linux.SO_RCVLOWAT: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument + } + + v := hostarch.ByteOrder.Uint32(optVal) + ep.SocketOptions().SetRcvlowat(int32(v)) + return nil + default: socket.SetSockOptEmitUnimplementedEvent(t, name) } diff --git a/pkg/sentry/socket/socket.go b/pkg/sentry/socket/socket.go index 8e1fa4764..bf0599568 100644 --- a/pkg/sentry/socket/socket.go +++ b/pkg/sentry/socket/socket.go @@ -583,7 +583,6 @@ func emitUnimplementedEvent(t *kernel.Task, name int) { linux.SO_PEEK_OFF, linux.SO_PRIORITY, linux.SO_RCVBUF, - linux.SO_RCVLOWAT, linux.SO_RCVTIMEO, linux.SO_REUSEADDR, linux.SO_REUSEPORT, diff --git a/pkg/tcpip/socketops.go b/pkg/tcpip/socketops.go index c204d2058..90a5f2d1e 100644 --- a/pkg/tcpip/socketops.go +++ b/pkg/tcpip/socketops.go @@ -245,6 +245,10 @@ type SocketOptions struct { // linger determines the amount of time the socket should linger before // close. We currently implement this option for TCP socket only. linger LingerOption + + // rcvlowat specifies the minimum number of bytes which should be + // received to indicate the socket as readable. + rcvlowat int32 } // InitHandler initializes the handler. This must be called before using the @@ -702,3 +706,17 @@ func (so *SocketOptions) SetReceiveBufferSize(receiveBufferSize int64, notify bo } so.receiveBufferSize.Store(receiveBufferSize) } + +// GetRcvlowat gets value for SO_RCVLOWAT option. +func (so *SocketOptions) GetRcvlowat() int32 { + // TODO(b/226603727): Return so.rcvlowat after adding complete support + // for SO_RCVLOWAT option. For now, return the default value of 1. + defaultRcvlowat := int32(1) + return defaultRcvlowat +} + +// SetRcvlowat sets value for SO_RCVLOWAT option. +func (so *SocketOptions) SetRcvlowat(rcvlowat int32) Error { + atomic.StoreInt32(&so.rcvlowat, rcvlowat) + return nil +} diff --git a/test/syscalls/linux/socket_generic_test_cases.cc b/test/syscalls/linux/socket_generic_test_cases.cc index 6f36d7369..0f48d52ff 100644 --- a/test/syscalls/linux/socket_generic_test_cases.cc +++ b/test/syscalls/linux/socket_generic_test_cases.cc @@ -968,5 +968,35 @@ TEST_P(AllSocketPairTest, GetSocketRcvbufOption) { EXPECT_EQ(opt, minRcvBufSizeLinux); } } + +TEST_P(AllSocketPairTest, GetSetSocketRcvlowatOption) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + int opt = 0; + socklen_t opt_len = sizeof(opt); + constexpr int defaultSz = 1; + ASSERT_THAT( + getsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVLOWAT, &opt, &opt_len), + SyscallSucceeds()); + ASSERT_EQ(opt_len, sizeof(opt)); + EXPECT_EQ(opt, defaultSz); + + int rcvlowatSz = 100; + ASSERT_THAT(setsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVLOWAT, + &rcvlowatSz, sizeof(rcvlowatSz)), + SyscallSucceeds()); + + ASSERT_THAT( + getsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVLOWAT, &opt, &opt_len), + SyscallSucceeds()); + ASSERT_EQ(opt_len, sizeof(opt)); + + if (IsRunningOnGvisor()) { + // TODO(b/226603727): Add support for setting SO_RCVLOWAT option in gVisor. + EXPECT_EQ(opt, defaultSz); + } else { + EXPECT_EQ(opt, rcvlowatSz); + } +} } // namespace testing } // namespace gvisor