1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- /*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/Assertions.h>
- #include <AK/Format.h>
- #include <AK/Types.h>
- #include <LibTest/TestCase.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <sys/mman.h>
- #include <unistd.h>
- #define EXPECT_OK(syscall, address, size) \
- do { \
- rc = syscall(fd, (void*)(address), (size_t)(size)); \
- EXPECT(rc >= 0); \
- if (rc < 0) { \
- warnln("Expected success: " #syscall "({:p}, {}), got rc={}, errno={}", (void*)(address), (size_t)(size), rc, errno); \
- } \
- } while (0)
- #define EXPECT_EFAULT(syscall, address, size) \
- do { \
- rc = syscall(fd, (void*)(address), (size_t)(size)); \
- EXPECT(rc < 0); \
- EXPECT_EQ(errno, EFAULT); \
- if (rc >= 0 || errno != EFAULT) { \
- warnln("Expected EFAULT: " #syscall "({:p}, {}), got rc={}, errno={}", (void*)(address), (size_t)(size), rc, errno); \
- } \
- } while (0)
- #define EXPECT_EFAULT_NO_FD(syscall, address, size) \
- do { \
- rc = syscall((address), (size_t)(size)); \
- EXPECT(rc < 0); \
- EXPECT_EQ(errno, EFAULT); \
- if (rc >= 0 || errno != EFAULT) { \
- warnln("Expected EFAULT: " #syscall "({:p}, {}), got rc={}, errno={}", (void*)(address), (size_t)(size), rc, errno); \
- } \
- } while (0)
- TEST_CASE(test_efault)
- {
- int fd = open("/dev/zero", O_RDONLY);
- int rc = -1;
- // Test a one-page mapping (4KB)
- u8* one_page = (u8*)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
- VERIFY(one_page);
- EXPECT_OK(read, one_page, 4096);
- EXPECT_EFAULT(read, one_page, 4097);
- EXPECT_EFAULT(read, one_page - 1, 4096);
- // Test a two-page mapping (8KB)
- u8* two_page = (u8*)mmap(nullptr, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
- VERIFY(two_page);
- EXPECT_OK(read, two_page, 4096);
- EXPECT_OK(read, two_page + 4096, 4096);
- EXPECT_OK(read, two_page, 8192);
- EXPECT_OK(read, two_page + 4095, 4097);
- EXPECT_OK(read, two_page + 1, 8191);
- EXPECT_EFAULT(read, two_page, 8193);
- EXPECT_EFAULT(read, two_page - 1, 1);
- // Check validation of pages between the first and last address.
- ptrdiff_t distance = two_page - one_page;
- EXPECT_EFAULT(read, one_page, (u32)distance + 1024);
- constexpr auto user_range_ceiling = (sizeof(void*) == 4 ? 0xbe000000u : 0x1ffe000000);
- u8* jerk_page = nullptr;
- // Test every kernel page just because.
- constexpr auto kernel_range_ceiling = (sizeof(void*) == 4 ? 0xffffffffu : 0x203fffffff);
- for (u64 kernel_address = user_range_ceiling; kernel_address <= kernel_range_ceiling; kernel_address += PAGE_SIZE) {
- jerk_page = (u8*)mmap((void*)kernel_address, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0, 0);
- EXPECT_EQ(jerk_page, MAP_FAILED);
- EXPECT_EQ(errno, EFAULT);
- }
- // Test the page just below where the user VM ends.
- jerk_page = (u8*)mmap((void*)(user_range_ceiling - PAGE_SIZE), PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0, 0);
- EXPECT_EQ(jerk_page, (u8*)(user_range_ceiling - PAGE_SIZE));
- EXPECT_OK(read, jerk_page, PAGE_SIZE);
- EXPECT_EFAULT(read, jerk_page, PAGE_SIZE + 1);
- // Test something that would wrap around the 2^32 mark.
- EXPECT_EFAULT(read, jerk_page, 0x50000000);
- }
|