Fix SIOCGIFCONF in hostinet

Add a syscall test with a bad nested pointer.
The implementation properly copies out a sentry buffer.

PiperOrigin-RevId: 421847766
This commit is contained in:
Dionna Glaze
2022-01-14 09:41:03 -08:00
committed by gVisor bot
parent 0a22b6c29f
commit 3cf606d9a4
3 changed files with 33 additions and 2 deletions
+16 -2
View File
@@ -97,10 +97,24 @@ func ioctl(ctx context.Context, fd int, io usermem.IO, args arch.SyscallArgument
if _, err := ifc.CopyIn(cc, args[2].Pointer()); err != nil {
return 0, err
}
// TODO(b/209503078): Check ifc.Ptr range is in untrusted range.
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), cmd, uintptr(unsafe.Pointer(&ifc))); errno != 0 {
// The user's ifconf can have a nullable pointer to a buffer. Use a Sentry array if non-null.
ifcNested := linux.IFConf{Len: ifc.Len}
var ifcBuf []byte
if ifc.Ptr != 0 {
ifcBuf = make([]byte, ifc.Len)
ifcNested.Ptr = uint64(uintptr(unsafe.Pointer(&ifcBuf[0])))
}
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), cmd, uintptr(unsafe.Pointer(&ifcNested))); errno != 0 {
return 0, translateIOSyscallError(errno)
}
// Copy out the buffer if it was non-null.
if ifc.Ptr != 0 {
if _, err := cc.CopyOutBytes(hostarch.Addr(ifc.Ptr), ifcBuf); err != nil {
return 0, err
}
}
ifc.Len = ifcNested.Len
_, err := ifc.CopyOut(cc, args[2].Pointer())
return 0, err
case linux.SIOCETHTOOL:
+1
View File
@@ -241,6 +241,7 @@ syscall_test(
syscall_test(
size = "medium",
add_hostinet = True,
add_overlay = True,
test = "//test/syscalls/linux:ioctl_test",
)
+16
View File
@@ -350,6 +350,22 @@ TEST_P(IoctlTestSIOCGIFCONF, ValidateNoPartialIfrsReturned) {
ASSERT_NE(ifr.ifr_name[0], '\0'); // An interface can now be returned.
}
// This test validates that nested pointers aren't allowed to escape the
// address space.
TEST_P(IoctlTestSIOCGIFCONF, ValidateNestedPointerCheck) {
auto fd = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
struct ifconf ifconf = {};
ifconf.ifc_len = sizeof(ifreq);
// Address chosen with ASLR disabled, pausing here, and inspecting the
// process with /proc/<pid>/maps to find a writable mapping in the low range
// of gr0 memory.
ifconf.ifc_ifcu.ifcu_req = reinterpret_cast<ifreq*>(0x3f9000d51000);
ASSERT_THAT(ioctl(fd->get(), SIOCGIFCONF, &ifconf),
SyscallFailsWithErrno(EFAULT));
}
TEST_P(IoctlTestSIOCGIFCONF, ValidateLoopbackIsPresent) {
auto fd = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());