From b6937e2560308379460a9f6d4a61bbf55e17dfde Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 28 Jan 2021 14:55:06 +0100 Subject: [PATCH] Kernel+LibC: Add MAP_RANDOMIZED flag for sys$mmap() This can be used to request random VM placement instead of the highly predictable regular mmap(nullptr, ...) VM allocation strategy. It will soon be used to implement ASLR in the dynamic loader. :^) --- Kernel/Syscalls/mmap.cpp | 22 +++++++++++++++------- Kernel/UnixTypes.h | 1 + Kernel/VM/RangeAllocator.cpp | 25 +++++++++++++++++++++++++ Kernel/VM/RangeAllocator.h | 1 + Userland/Libraries/LibC/mman.h | 1 + 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Kernel/Syscalls/mmap.cpp b/Kernel/Syscalls/mmap.cpp index aa555b71f3..be1ebdf818 100644 --- a/Kernel/Syscalls/mmap.cpp +++ b/Kernel/Syscalls/mmap.cpp @@ -119,6 +119,7 @@ void* Process::sys$mmap(Userspace user_params) bool map_stack = flags & MAP_STACK; bool map_fixed = flags & MAP_FIXED; bool map_noreserve = flags & MAP_NORESERVE; + bool map_randomized = flags & MAP_RANDOMIZED; if (map_shared && map_private) return (void*)-EINVAL; @@ -133,16 +134,23 @@ void* Process::sys$mmap(Userspace user_params) return (void*)-EINVAL; Region* region = nullptr; - auto range = allocate_range(VirtualAddress(addr), size, alignment); - if (!range.has_value()) { - if (addr && !map_fixed) { - // If there's an address but MAP_FIXED wasn't specified, the address is just a hint. - range = allocate_range({}, size, alignment); + Optional range; + + if (map_randomized) { + range = page_directory().range_allocator().allocate_randomized(size, alignment); + } else { + range = allocate_range(VirtualAddress(addr), size, alignment); + if (!range.has_value()) { + if (addr && !map_fixed) { + // If there's an address but MAP_FIXED wasn't specified, the address is just a hint. + range = allocate_range({}, size, alignment); + } } - if (!range.has_value()) - return (void*)-ENOMEM; } + if (!range.has_value()) + return (void*)-ENOMEM; + if (map_anonymous) { auto strategy = map_noreserve ? AllocationStrategy::None : AllocationStrategy::Reserve; auto region_or_error = allocate_region(range.value(), !name.is_null() ? name : "mmap", prot, strategy); diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index 09c19d0ef4..271d4a45f0 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -95,6 +95,7 @@ enum { #define MAP_ANON MAP_ANONYMOUS #define MAP_STACK 0x40 #define MAP_NORESERVE 0x80 +#define MAP_RANDOMIZED 0x100 #define PROT_READ 0x1 #define PROT_WRITE 0x2 diff --git a/Kernel/VM/RangeAllocator.cpp b/Kernel/VM/RangeAllocator.cpp index f092962ae8..a61b6d1512 100644 --- a/Kernel/VM/RangeAllocator.cpp +++ b/Kernel/VM/RangeAllocator.cpp @@ -106,6 +106,31 @@ void RangeAllocator::carve_at_index(int index, const Range& range) m_available_ranges.insert(index + 1, move(remaining_parts[1])); } +Optional RangeAllocator::allocate_randomized(size_t size, size_t alignment) +{ + if (!size) + return {}; + + ASSERT((size % PAGE_SIZE) == 0); + ASSERT((alignment % PAGE_SIZE) == 0); + + // FIXME: I'm sure there's a smarter way to do this. + static constexpr size_t maximum_randomization_attempts = 1000; + for (size_t i = 0; i < maximum_randomization_attempts; ++i) { + VirtualAddress random_address { get_good_random() }; + random_address.mask(PAGE_MASK); + + if (!m_total_range.contains(random_address)) + continue; + + auto range = allocate_specific(random_address, size); + if (range.has_value()) + return range; + } + + return allocate_anywhere(size, alignment); +} + Optional RangeAllocator::allocate_anywhere(size_t size, size_t alignment) { if (!size) diff --git a/Kernel/VM/RangeAllocator.h b/Kernel/VM/RangeAllocator.h index 0839e0bb57..97e58d02ec 100644 --- a/Kernel/VM/RangeAllocator.h +++ b/Kernel/VM/RangeAllocator.h @@ -87,6 +87,7 @@ public: Optional allocate_anywhere(size_t, size_t alignment = PAGE_SIZE); Optional allocate_specific(VirtualAddress, size_t); + Optional allocate_randomized(size_t, size_t alignment); void deallocate(const Range&); void dump() const; diff --git a/Userland/Libraries/LibC/mman.h b/Userland/Libraries/LibC/mman.h index 0d44ee2d9c..0786573785 100644 --- a/Userland/Libraries/LibC/mman.h +++ b/Userland/Libraries/LibC/mman.h @@ -37,6 +37,7 @@ #define MAP_ANON MAP_ANONYMOUS #define MAP_STACK 0x40 #define MAP_NORESERVE 0x80 +#define MAP_RANDOMIZED 0x100 #define PROT_READ 0x1 #define PROT_WRITE 0x2