Fix return codes for {get,set}sockopt for some nullptr cases.

Updates #1092

PiperOrigin-RevId: 280547239
This commit is contained in:
Ting-Yu Wang
2019-11-14 17:04:34 -08:00
committed by gVisor bot
parent 339536de5e
commit af323eb7c1
2 changed files with 41 additions and 14 deletions
+9 -14
View File
@@ -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 {
+32
View File
@@ -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>(