Serenity Operating System
at master 93 lines 5.0 kB view raw
1/* 2 * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/Assertions.h> 9#include <AK/Format.h> 10#include <AK/Types.h> 11#include <LibTest/TestCase.h> 12#include <errno.h> 13#include <fcntl.h> 14#include <stdio.h> 15#include <sys/mman.h> 16#include <unistd.h> 17 18#define EXPECT_OK(syscall, address, size) \ 19 do { \ 20 errno = 0; \ 21 rc = syscall(fd, (void*)(address), (size_t)(size)); \ 22 EXPECT(rc >= 0); \ 23 if (rc < 0) { \ 24 warnln("Expected success: " #syscall "({:p}, {}), got rc={}, errno={}", (void*)(address), (size_t)(size), rc, errno); \ 25 } \ 26 } while (0) 27 28#define EXPECT_EFAULT(syscall, address, size) \ 29 do { \ 30 errno = 0; \ 31 rc = syscall(fd, (void*)(address), (size_t)(size)); \ 32 EXPECT(rc < 0); \ 33 EXPECT_EQ(errno, EFAULT); \ 34 if (rc >= 0 || errno != EFAULT) { \ 35 warnln("Expected EFAULT: " #syscall "({:p}, {}), got rc={}, errno={}", (void*)(address), (size_t)(size), rc, errno); \ 36 } \ 37 } while (0) 38 39TEST_CASE(test_efault) 40{ 41 int fd = open("/dev/zero", O_RDONLY); 42 int rc = -1; 43 44 // Make an inaccessible hole before the next mapping. 45 (void)mmap(nullptr, 4096, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 46 47 // Test a one-page mapping (4KB) 48 u8* one_page = (u8*)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 49 VERIFY(one_page); 50 EXPECT_OK(read, one_page, 4096); 51 EXPECT_EFAULT(read, one_page, 4097); 52 EXPECT_EFAULT(read, one_page - 1, 4096); 53 54 // Make an unused hole mapping to create some inaccessible distance between our one and two-page mappings. 55 (void)mmap(nullptr, 16384, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 56 57 // Test a two-page mapping (8KB) 58 u8* two_page = (u8*)mmap(nullptr, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 59 VERIFY(two_page); 60 61 EXPECT_OK(read, two_page, 4096); 62 EXPECT_OK(read, two_page + 4096, 4096); 63 EXPECT_OK(read, two_page, 8192); 64 EXPECT_OK(read, two_page + 4095, 4097); 65 EXPECT_OK(read, two_page + 1, 8191); 66 EXPECT_EFAULT(read, two_page, 8193); 67 EXPECT_EFAULT(read, two_page - 1, 1); 68 69 // Check validation of pages between the first and last address. 70 ptrdiff_t distance = two_page - one_page; 71 EXPECT_EFAULT(read, one_page, (u32)distance + 1024); 72 73 constexpr auto user_range_ceiling = (sizeof(void*) == 4 ? 0xbe000000u : 0x1ffe000000); 74 u8* jerk_page = nullptr; 75 76 // Test every kernel page just because. 77 constexpr auto kernel_range_ceiling = (sizeof(void*) == 4 ? 0xffffffffu : 0x203fffffff); 78 for (u64 kernel_address = user_range_ceiling; kernel_address <= kernel_range_ceiling; kernel_address += PAGE_SIZE) { 79 jerk_page = (u8*)mmap((void*)kernel_address, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0, 0); 80 EXPECT_EQ(jerk_page, MAP_FAILED); 81 EXPECT_EQ(errno, EFAULT); 82 } 83 84 // Test the page just below where the user VM ends. 85 jerk_page = (u8*)mmap((void*)(user_range_ceiling - PAGE_SIZE), PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0, 0); 86 EXPECT_EQ(jerk_page, (u8*)(user_range_ceiling - PAGE_SIZE)); 87 88 EXPECT_OK(read, jerk_page, PAGE_SIZE); 89 EXPECT_EFAULT(read, jerk_page, PAGE_SIZE + 1); 90 91 // Test something that would wrap around the 2^32 mark. 92 EXPECT_EFAULT(read, jerk_page, 0x50000000); 93}