diff --git a/pkg/sentry/syscalls/linux/sys_file.go b/pkg/sentry/syscalls/linux/sys_file.go index e78a01acc4..8a677b329f 100644 --- a/pkg/sentry/syscalls/linux/sys_file.go +++ b/pkg/sentry/syscalls/linux/sys_file.go @@ -15,8 +15,6 @@ package linux import ( - "math" - "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/fspath" @@ -455,7 +453,7 @@ func CloseRange(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uint last := args[1].Uint() flags := args[2].Uint() - if (first > last) || (last > math.MaxInt32) { + if first > last { return 0, nil, linuxerr.EINVAL } @@ -463,6 +461,12 @@ func CloseRange(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uint return 0, nil, linuxerr.EINVAL } + // close_range allows fd arguments to be up to MaxUint32, but only fds + // up to kernel.MaxFdLimit are valid, so cap it here. + if last > uint32(kernel.MaxFdLimit) { + last = uint32(kernel.MaxFdLimit) + } + cloexec := flags & linux.CLOSE_RANGE_CLOEXEC unshare := flags & linux.CLOSE_RANGE_UNSHARE @@ -474,7 +478,7 @@ func CloseRange(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uint if cloexec == 0 && int32(last) >= t.FDTable().GetLastFd() { t.UnshareFdTable(int32(first)) } else { - t.UnshareFdTable(math.MaxInt32) + t.UnshareFdTable(kernel.MaxFdLimit) } } diff --git a/test/syscalls/linux/close_range.cc b/test/syscalls/linux/close_range.cc index 012a80704b..786228cbe9 100644 --- a/test/syscalls/linux/close_range.cc +++ b/test/syscalls/linux/close_range.cc @@ -353,6 +353,23 @@ TEST_F(CloseRangeTest, RangeFirstGreaterThanLast) { SyscallFailsWithErrno(EINVAL)); } +// Test that calling with maximum last argument succeeds and closes all fds in +// the range. +TEST_F(CloseRangeTest, RangeMaxLast) { + SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); + int num_files_in_range = 10; + unsigned int flags = 0; + + CreateFiles(num_files_in_range); + OpenFilesRdwr(); + + EXPECT_THAT(close_range(fds_[0], -1, flags), SyscallSucceeds()); + for (int fd : fds_) { + auto ret = ReadAllFd(fd); + EXPECT_THAT(ret, PosixErrorIs(EBADF)); + } +} + // Test that calling with invalid flags does not succeed. TEST_F(CloseRangeTest, InvalidFlags) { SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS);