diff options
author | Jamie Liu <jamieliu@google.com> | 2021-09-16 12:10:03 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-09-16 12:12:59 -0700 |
commit | 51b96514cd9397870b39506e3693017a355319dd (patch) | |
tree | 46f465ed03e12efdff1625886604558968d94f56 /test | |
parent | 282a4dd52b337dccfb578e9d32dd1005c864dd8d (diff) |
Limit most file mmaps to the range of an int64.
In the general case, files may have offsets between MaxInt64 and MaxUint64; in
Linux pgoff is consistently represented by an unsigned long, and in gVisor the
offset types in memmap.MappableRange are uint64. However, regular file mmap is
constrained to int64 offsets (on 64-bit systems) by
mm/mmap.c:file_mmap_size_max() => MAX_LFS_FILESIZE == LLONG_MAX.
As a related fix, check for chunkStart overflow in fsutil.HostFileMapper; chunk
offsets are uint64s, but as noted above some file types may use uint64 offsets
beyond MaxInt64.
Reported-by: syzbot+71342a1585aed97ed9f7@syzkaller.appspotmail.com
PiperOrigin-RevId: 397136751
Diffstat (limited to 'test')
-rw-r--r-- | test/syscalls/linux/mmap.cc | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/test/syscalls/linux/mmap.cc b/test/syscalls/linux/mmap.cc index fda176261..bb2a0cb57 100644 --- a/test/syscalls/linux/mmap.cc +++ b/test/syscalls/linux/mmap.cc @@ -29,6 +29,7 @@ #include <sys/wait.h> #include <unistd.h> +#include <limits> #include <vector> #include "gmock/gmock.h" @@ -913,13 +914,41 @@ TEST_F(MMapFileTest, MapOffsetBeyondEnd) { ::testing::KilledBySignal(SIGBUS), ""); } -// Verify mmap fails when sum of length and offset overflows. -TEST_F(MMapFileTest, MapLengthPlusOffsetOverflows) { +TEST_F(MMapFileTest, MapSecondToLastPositivePage) { SKIP_IF(!FSSupportsMap()); - const size_t length = static_cast<size_t>(-kPageSize); - const off_t offset = kPageSize; - ASSERT_THAT(Map(0, length, PROT_READ, MAP_PRIVATE, fd_.get(), offset), - SyscallFailsWithErrno(ENOMEM)); + EXPECT_THAT( + Map(0, kPageSize, PROT_READ, MAP_SHARED, fd_.get(), + (std::numeric_limits<off_t>::max() - kPageSize) & ~(kPageSize - 1)), + SyscallSucceeds()); +} + +TEST_F(MMapFileTest, MapLastPositivePage) { + SKIP_IF(!FSSupportsMap()); + // For regular files, this should fail due to integer overflow of the end + // offset. + EXPECT_THAT(Map(0, kPageSize, PROT_READ, MAP_SHARED, fd_.get(), + std::numeric_limits<off_t>::max() & ~(kPageSize - 1)), + SyscallFailsWithErrno(EOVERFLOW)); +} + +TEST_F(MMapFileTest, MapFirstNegativePage) { + SKIP_IF(!FSSupportsMap()); + EXPECT_THAT(Map(0, kPageSize, PROT_READ, MAP_SHARED, fd_.get(), + std::numeric_limits<off_t>::min()), + SyscallFailsWithErrno(EOVERFLOW)); +} + +TEST_F(MMapFileTest, MapSecondToLastNegativePage) { + SKIP_IF(!FSSupportsMap()); + EXPECT_THAT( + Map(0, kPageSize, PROT_READ, MAP_SHARED, fd_.get(), -(2 * kPageSize)), + SyscallFailsWithErrno(EOVERFLOW)); +} + +TEST_F(MMapFileTest, MapLastNegativePage) { + SKIP_IF(!FSSupportsMap()); + EXPECT_THAT(Map(0, kPageSize, PROT_READ, MAP_SHARED, fd_.get(), -kPageSize), + SyscallFailsWithErrno(EOVERFLOW)); } // MAP_PRIVATE PROT_WRITE is allowed on read-only FDs. |