From 7d6689055fbed308324a80769c334a649edcab56 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 12 Aug 2019 19:33:24 +0200 Subject: [PATCH] Kernel+LibC+crash: Add mprotect() syscall This patch adds the mprotect() syscall to allow changing the protection flags for memory regions. We don't do any region splitting/merging yet, so this only works on whole mmap() regions. Added a "crash -r" flag to verify that we crash when you attempt to write to read-only memory. :^) --- Kernel/Process.cpp | 10 ++++++++++ Kernel/Process.h | 1 + Kernel/Syscall.cpp | 2 ++ Kernel/Syscall.h | 3 ++- Libraries/LibC/mman.cpp | 6 ++++++ Libraries/LibC/mman.h | 1 + Userland/crash.cpp | 14 ++++++++++++++ 7 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 4029b235ac5..82bb9bfe5b3 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -224,6 +224,16 @@ int Process::sys$munmap(void* addr, size_t size) return 0; } +int Process::sys$mprotect(void* addr, size_t size, int prot) +{ + auto* region = region_from_range(VirtualAddress((u32)addr), size); + if (!region) + return -EINVAL; + region->set_writable(prot & PROT_WRITE); + MM.remap_region(page_directory(), *region); + return 0; +} + int Process::sys$gethostname(char* buffer, ssize_t size) { if (size < 0) diff --git a/Kernel/Process.h b/Kernel/Process.h index fa478f7f679..8e1c38a85b1 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -145,6 +145,7 @@ public: void* sys$mmap(const Syscall::SC_mmap_params*); int sys$munmap(void*, size_t size); int sys$set_mmap_name(void*, size_t, const char*); + int sys$mprotect(void*, size_t, int prot); int sys$select(const Syscall::SC_select_params*); int sys$poll(pollfd*, int nfds, int timeout); ssize_t sys$get_dir_entries(int fd, void*, ssize_t); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 48b9313a92d..8d43d8a56ce 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -305,6 +305,8 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3 return current->process().sys$share_buffer_globally((int)arg1); case Syscall::SC_set_process_icon: return current->process().sys$set_process_icon((int)arg1); + case Syscall::SC_mprotect: + return current->process().sys$mprotect((void*)arg1, (size_t)arg2, (int)arg3); default: kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3); return -ENOSYS; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 0451c415da0..cec9a23749c 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -122,7 +122,8 @@ struct timeval; __ENUMERATE_SYSCALL(dbgputstr) \ __ENUMERATE_SYSCALL(watch_file) \ __ENUMERATE_SYSCALL(share_buffer_globally) \ - __ENUMERATE_SYSCALL(set_process_icon) + __ENUMERATE_SYSCALL(set_process_icon) \ + __ENUMERATE_SYSCALL(mprotect) namespace Syscall { diff --git a/Libraries/LibC/mman.cpp b/Libraries/LibC/mman.cpp index 38c08b6825a..11e89ae4be4 100644 --- a/Libraries/LibC/mman.cpp +++ b/Libraries/LibC/mman.cpp @@ -33,6 +33,12 @@ int munmap(void* addr, size_t size) __RETURN_WITH_ERRNO(rc, rc, -1); } +int mprotect(void* addr, size_t size, int prot) +{ + int rc = syscall(SC_mprotect, addr, size, prot); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + int set_mmap_name(void* addr, size_t size, const char* name) { int rc = syscall(SC_set_mmap_name, addr, size, name); diff --git a/Libraries/LibC/mman.h b/Libraries/LibC/mman.h index f8b408026dd..513328bb064 100644 --- a/Libraries/LibC/mman.h +++ b/Libraries/LibC/mman.h @@ -21,6 +21,7 @@ __BEGIN_DECLS void* mmap(void* addr, size_t, int prot, int flags, int fd, off_t); void* mmap_with_name(void* addr, size_t, int prot, int flags, int fd, off_t, const char* name); int munmap(void*, size_t); +int mprotect(void*, size_t, int prot); int set_mmap_name(void*, size_t, const char*); int shm_open(const char* name, int flags, mode_t); int shm_unlink(const char* name); diff --git a/Userland/crash.cpp b/Userland/crash.cpp index 3d702bc3b36..a7f15e9167b 100644 --- a/Userland/crash.cpp +++ b/Userland/crash.cpp @@ -1,6 +1,7 @@ #include #include #include +#include static void print_usage_and_exit() { @@ -20,6 +21,7 @@ int main(int argc, char** argv) WriteToFreedMemory, ReadFromUninitializedMallocMemory, ReadFromFreedMemory, + WriteToReadonlyMemory, }; Mode mode = SegmentationViolation; @@ -42,6 +44,8 @@ int main(int argc, char** argv) mode = WriteToUninitializedMallocMemory; else if (String(argv[1]) == "-F") mode = WriteToFreedMemory; + else if (String(argv[1]) == "-r") + mode = WriteToReadonlyMemory; else print_usage_and_exit(); @@ -97,6 +101,16 @@ int main(int argc, char** argv) ASSERT_NOT_REACHED(); } + if (mode == WriteToReadonlyMemory) { + auto* ptr = (u8*)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0); + ASSERT(ptr != MAP_FAILED); + *ptr = 'x'; // This should work fine. + int rc = mprotect(ptr, 4096, PROT_READ); + ASSERT(rc == 0); + ASSERT(*ptr == 'x'); + *ptr = 'y'; // This should crash! + } + ASSERT_NOT_REACHED(); return 0; }