mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
netstack: support SO_RCVBUFFORCE
TCP is fully supported. As with SO_RCVBUF, other transport protocols perform no-ops per DefaultSocketOptionsHandler.OnSetReceiveBufferSize. PiperOrigin-RevId: 385023239
This commit is contained in:
committed by
gVisor bot
parent
67d9050752
commit
cd45d7b6c8
@@ -49,6 +49,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
|
||||
"gvisor.dev/gvisor/pkg/sentry/inet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netfilter"
|
||||
@@ -1682,12 +1683,12 @@ func SetSockOpt(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, level int
|
||||
return nil
|
||||
}
|
||||
|
||||
func clampBufSize(newSz, min, max int64) int64 {
|
||||
func clampBufSize(newSz, min, max int64, ignoreMax bool) int64 {
|
||||
// packetOverheadFactor is used to multiply the value provided by the user on
|
||||
// a setsockopt(2) for setting the send/receive buffer sizes sockets.
|
||||
const packetOverheadFactor = 2
|
||||
|
||||
if newSz > max {
|
||||
if !ignoreMax && newSz > max {
|
||||
newSz = max
|
||||
}
|
||||
|
||||
@@ -1712,7 +1713,7 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
|
||||
|
||||
v := hostarch.ByteOrder.Uint32(optVal)
|
||||
min, max := ep.SocketOptions().SendBufferLimits()
|
||||
clamped := clampBufSize(int64(v), min, max)
|
||||
clamped := clampBufSize(int64(v), min, max, false /* ignoreMax */)
|
||||
ep.SocketOptions().SetSendBufferSize(clamped, true /* notify */)
|
||||
return nil
|
||||
|
||||
@@ -1723,7 +1724,22 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
|
||||
|
||||
v := hostarch.ByteOrder.Uint32(optVal)
|
||||
min, max := ep.SocketOptions().ReceiveBufferLimits()
|
||||
clamped := clampBufSize(int64(v), min, max)
|
||||
clamped := clampBufSize(int64(v), min, max, false /* ignoreMax */)
|
||||
ep.SocketOptions().SetReceiveBufferSize(clamped, true /* notify */)
|
||||
return nil
|
||||
|
||||
case linux.SO_RCVBUFFORCE:
|
||||
if len(optVal) < sizeOfInt32 {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
if creds := auth.CredentialsFromContext(t); !creds.HasCapability(linux.CAP_NET_ADMIN) {
|
||||
return syserr.ErrNotPermitted
|
||||
}
|
||||
|
||||
v := hostarch.ByteOrder.Uint32(optVal)
|
||||
min, max := ep.SocketOptions().ReceiveBufferLimits()
|
||||
clamped := clampBufSize(int64(v), min, max, true /* ignoreMax */)
|
||||
ep.SocketOptions().SetReceiveBufferSize(clamped, true /* notify */)
|
||||
return nil
|
||||
|
||||
|
||||
@@ -509,7 +509,6 @@ func SetSockOptEmitUnimplementedEvent(t *kernel.Task, name int) {
|
||||
linux.SO_ATTACH_REUSEPORT_EBPF,
|
||||
linux.SO_CNX_ADVICE,
|
||||
linux.SO_DETACH_FILTER,
|
||||
linux.SO_RCVBUFFORCE,
|
||||
linux.SO_SNDBUFFORCE:
|
||||
|
||||
t.Kernel().EmitUnimplementedEvent(t)
|
||||
|
||||
@@ -54,7 +54,7 @@ type SocketOptionsHandler interface {
|
||||
// buffer size. It also returns the newly set value.
|
||||
OnSetSendBufferSize(v int64) (newSz int64)
|
||||
|
||||
// OnSetReceiveBufferSize is invoked to set the SO_RCVBUFSIZE.
|
||||
// OnSetReceiveBufferSize is invoked by SO_RCVBUF and SO_RCVBUFFORCE.
|
||||
OnSetReceiveBufferSize(v, oldSz int64) (newSz int64)
|
||||
}
|
||||
|
||||
|
||||
@@ -2395,6 +2395,7 @@ cc_library(
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
gtest,
|
||||
"//test/util:capability_util",
|
||||
"//test/util:test_util",
|
||||
],
|
||||
alwayslink = 1,
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
|
||||
#include "test/syscalls/linux/socket_generic.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/capability.h>
|
||||
#endif // __linux__
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -24,6 +27,7 @@
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "test/syscalls/linux/socket_test_util.h"
|
||||
#include "test/syscalls/linux/unix_domain_socket_test_util.h"
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/util/test_util.h"
|
||||
|
||||
// This file is a generic socket test file. It must be built with another file
|
||||
@@ -400,6 +404,46 @@ TEST_P(AllSocketPairTest, RcvBufSucceeds) {
|
||||
EXPECT_GT(size, 0);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
// Check that setting SO_RCVBUFFORCE above max is not clamped to the maximum
|
||||
// receive buffer size.
|
||||
TEST_P(AllSocketPairTest, SetSocketRecvBufForceAboveMax) {
|
||||
std::unique_ptr<SocketPair> sockets =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
// Discover maxmimum buffer size by setting to a really large value.
|
||||
constexpr int kRcvBufSz = 0xffffffff;
|
||||
ASSERT_THAT(setsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVBUF, &kRcvBufSz,
|
||||
sizeof(kRcvBufSz)),
|
||||
SyscallSucceeds());
|
||||
|
||||
int max = 0;
|
||||
socklen_t max_len = sizeof(max);
|
||||
ASSERT_THAT(
|
||||
getsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVBUF, &max, &max_len),
|
||||
SyscallSucceeds());
|
||||
|
||||
int above_max = max + 1;
|
||||
int sso = setsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVBUFFORCE,
|
||||
&above_max, sizeof(above_max));
|
||||
if (!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN))) {
|
||||
ASSERT_THAT(sso, SyscallFailsWithErrno(EPERM));
|
||||
return;
|
||||
}
|
||||
ASSERT_THAT(sso, SyscallSucceeds());
|
||||
|
||||
int val = 0;
|
||||
socklen_t val_len = sizeof(val);
|
||||
ASSERT_THAT(
|
||||
getsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVBUF, &val, &val_len),
|
||||
SyscallSucceeds());
|
||||
// The system doubles the passed-in maximum.
|
||||
ASSERT_EQ(above_max * 2, val);
|
||||
}
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
TEST_P(AllSocketPairTest, GetSndBufSucceeds) {
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
int size = 0;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "test/util/capability_util.h"
|
||||
|
||||
#include <linux/capability.h>
|
||||
@@ -79,3 +81,5 @@ PosixErrorOr<bool> CanCreateUserNamespace() {
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_
|
||||
#define GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <errno.h>
|
||||
#include <linux/capability.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -120,4 +122,7 @@ class AutoCapability {
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
#endif // GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_
|
||||
|
||||
Reference in New Issue
Block a user