summaryrefslogtreecommitdiff
path: root/Tests/Kernel
diff options
context:
space:
mode:
authorAndrew Kaster <akaster@serenityos.org>2021-07-06 20:21:14 -0600
committerAndreas Kling <kling@serenityos.org>2021-07-11 19:42:00 +0200
commit4cc75501d754b1b78cd21cf53291d3feac832df6 (patch)
tree99288611462f566ef426363587c9b144760ca61b /Tests/Kernel
parent578d45b480c5b167df916ebc42e13bc1bd6153c1 (diff)
downloadserenity-4cc75501d754b1b78cd21cf53291d3feac832df6.zip
Utilities+Tests: Convert test_efault to be LibTest based
This test exposed a kernel panic in is_user_range calculations, so let's convert it to be a LibTest test so we can prevent regressions in mmap, the page allocator, and the memory manager.
Diffstat (limited to 'Tests/Kernel')
-rw-r--r--Tests/Kernel/TestEFault.cpp98
1 files changed, 98 insertions, 0 deletions
diff --git a/Tests/Kernel/TestEFault.cpp b/Tests/Kernel/TestEFault.cpp
new file mode 100644
index 0000000000..831f843cc1
--- /dev/null
+++ b/Tests/Kernel/TestEFault.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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);
+
+ // Test every kernel page just because.
+ constexpr auto user_range_ceiling = 0xbe000000u;
+ u8* jerk_page = nullptr;
+ for (u64 kernel_address = user_range_ceiling; kernel_address <= 0xffffffff; 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, MAP_FAILED);
+ EXPECT_EQ(errno, EFAULT);
+
+ // Test the page just before that
+ jerk_page = (u8*)mmap((void*)(user_range_ceiling - (2 * PAGE_SIZE)), PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
+ EXPECT_EQ(jerk_page, (u8*)(user_range_ceiling - (2 * PAGE_SIZE)));
+
+ EXPECT_OK(read, jerk_page, 4096);
+ EXPECT_EFAULT(read, jerk_page, 4097);
+
+ // Test something that would wrap around the 2^32 mark.
+ EXPECT_EFAULT(read, jerk_page, 0x50000000);
+}