mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Fix return codes for {get,set}sockopt for some nullptr cases.
Updates #1092 PiperOrigin-RevId: 280547239
This commit is contained in:
@@ -447,16 +447,13 @@ func GetSockOpt(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sy
|
||||
return 0, nil, syserror.ENOTSOCK
|
||||
}
|
||||
|
||||
// Read the length if present. Reject negative values.
|
||||
// Read the length. Reject negative values.
|
||||
optLen := int32(0)
|
||||
if optLenAddr != 0 {
|
||||
if _, err := t.CopyIn(optLenAddr, &optLen); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if optLen < 0 {
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
if _, err := t.CopyIn(optLenAddr, &optLen); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if optLen < 0 {
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
|
||||
// Call syscall implementation then copy both value and value len out.
|
||||
@@ -465,11 +462,9 @@ func GetSockOpt(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sy
|
||||
return 0, nil, e.ToError()
|
||||
}
|
||||
|
||||
if optLenAddr != 0 {
|
||||
vLen := int32(binary.Size(v))
|
||||
if _, err := t.CopyOut(optLenAddr, vLen); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
vLen := int32(binary.Size(v))
|
||||
if _, err := t.CopyOut(optLenAddr, vLen); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if v != nil {
|
||||
|
||||
@@ -354,6 +354,38 @@ TEST_P(IPUnboundSocketTest, InvalidNegativeTOS) {
|
||||
EXPECT_EQ(get, expect);
|
||||
}
|
||||
|
||||
TEST_P(IPUnboundSocketTest, NullTOS) {
|
||||
auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
|
||||
TOSOption t = GetTOSOption(GetParam().domain);
|
||||
int set_sz = sizeof(int);
|
||||
if (GetParam().domain == AF_INET) {
|
||||
EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, nullptr, set_sz),
|
||||
SyscallFailsWithErrno(EFAULT));
|
||||
} else { // AF_INET6
|
||||
// The AF_INET6 behavior is not yet compatible. gVisor will try to read
|
||||
// optval from user memory at syscall handler, it needs substantial
|
||||
// refactoring to implement this behavior just for IPv6.
|
||||
if (IsRunningOnGvisor()) {
|
||||
EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, nullptr, set_sz),
|
||||
SyscallFailsWithErrno(EFAULT));
|
||||
} else {
|
||||
// Linux's IPv6 stack treats nullptr optval as input of 0, so the call
|
||||
// succeeds. (net/ipv6/ipv6_sockglue.c, do_ipv6_setsockopt())
|
||||
//
|
||||
// Linux's implementation would need fixing as passing a nullptr as optval
|
||||
// and non-zero optlen may not be valid.
|
||||
EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, nullptr, set_sz),
|
||||
SyscallSucceedsWithValue(0));
|
||||
}
|
||||
}
|
||||
socklen_t get_sz = sizeof(int);
|
||||
EXPECT_THAT(getsockopt(socket->get(), t.level, t.option, nullptr, &get_sz),
|
||||
SyscallFailsWithErrno(EFAULT));
|
||||
int get = -1;
|
||||
EXPECT_THAT(getsockopt(socket->get(), t.level, t.option, &get, nullptr),
|
||||
SyscallFailsWithErrno(EFAULT));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
IPUnboundSockets, IPUnboundSocketTest,
|
||||
::testing::ValuesIn(VecCat<SocketKind>(VecCat<SocketKind>(
|
||||
|
||||
Reference in New Issue
Block a user