瀏覽代碼

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. :^)
Andreas Kling 4 年之前
父節點
當前提交
b6937e2560
共有 5 個文件被更改,包括 43 次插入7 次删除
  1. 15 7
      Kernel/Syscalls/mmap.cpp
  2. 1 0
      Kernel/UnixTypes.h
  3. 25 0
      Kernel/VM/RangeAllocator.cpp
  4. 1 0
      Kernel/VM/RangeAllocator.h
  5. 1 0
      Userland/Libraries/LibC/mman.h

+ 15 - 7
Kernel/Syscalls/mmap.cpp

@@ -119,6 +119,7 @@ void* Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
     bool map_stack = flags & MAP_STACK;
     bool map_stack = flags & MAP_STACK;
     bool map_fixed = flags & MAP_FIXED;
     bool map_fixed = flags & MAP_FIXED;
     bool map_noreserve = flags & MAP_NORESERVE;
     bool map_noreserve = flags & MAP_NORESERVE;
+    bool map_randomized = flags & MAP_RANDOMIZED;
 
 
     if (map_shared && map_private)
     if (map_shared && map_private)
         return (void*)-EINVAL;
         return (void*)-EINVAL;
@@ -133,16 +134,23 @@ void* Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
         return (void*)-EINVAL;
         return (void*)-EINVAL;
 
 
     Region* region = nullptr;
     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> 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) {
     if (map_anonymous) {
         auto strategy = map_noreserve ? AllocationStrategy::None : AllocationStrategy::Reserve;
         auto strategy = map_noreserve ? AllocationStrategy::None : AllocationStrategy::Reserve;
         auto region_or_error = allocate_region(range.value(), !name.is_null() ? name : "mmap", prot, strategy);
         auto region_or_error = allocate_region(range.value(), !name.is_null() ? name : "mmap", prot, strategy);

+ 1 - 0
Kernel/UnixTypes.h

@@ -95,6 +95,7 @@ enum {
 #define MAP_ANON MAP_ANONYMOUS
 #define MAP_ANON MAP_ANONYMOUS
 #define MAP_STACK 0x40
 #define MAP_STACK 0x40
 #define MAP_NORESERVE 0x80
 #define MAP_NORESERVE 0x80
+#define MAP_RANDOMIZED 0x100
 
 
 #define PROT_READ 0x1
 #define PROT_READ 0x1
 #define PROT_WRITE 0x2
 #define PROT_WRITE 0x2

+ 25 - 0
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]));
         m_available_ranges.insert(index + 1, move(remaining_parts[1]));
 }
 }
 
 
+Optional<Range> 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<FlatPtr>() };
+        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<Range> RangeAllocator::allocate_anywhere(size_t size, size_t alignment)
 Optional<Range> RangeAllocator::allocate_anywhere(size_t size, size_t alignment)
 {
 {
     if (!size)
     if (!size)

+ 1 - 0
Kernel/VM/RangeAllocator.h

@@ -87,6 +87,7 @@ public:
 
 
     Optional<Range> allocate_anywhere(size_t, size_t alignment = PAGE_SIZE);
     Optional<Range> allocate_anywhere(size_t, size_t alignment = PAGE_SIZE);
     Optional<Range> allocate_specific(VirtualAddress, size_t);
     Optional<Range> allocate_specific(VirtualAddress, size_t);
+    Optional<Range> allocate_randomized(size_t, size_t alignment);
     void deallocate(const Range&);
     void deallocate(const Range&);
 
 
     void dump() const;
     void dump() const;

+ 1 - 0
Userland/Libraries/LibC/mman.h

@@ -37,6 +37,7 @@
 #define MAP_ANON MAP_ANONYMOUS
 #define MAP_ANON MAP_ANONYMOUS
 #define MAP_STACK 0x40
 #define MAP_STACK 0x40
 #define MAP_NORESERVE 0x80
 #define MAP_NORESERVE 0x80
+#define MAP_RANDOMIZED 0x100
 
 
 #define PROT_READ 0x1
 #define PROT_READ 0x1
 #define PROT_WRITE 0x2
 #define PROT_WRITE 0x2