summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Syscalls/mmap.cpp22
-rw-r--r--Kernel/UnixTypes.h1
-rw-r--r--Kernel/VM/RangeAllocator.cpp25
-rw-r--r--Kernel/VM/RangeAllocator.h1
-rw-r--r--Userland/Libraries/LibC/mman.h1
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<const Syscall::SC_mmap_params*> 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<const Syscall::SC_mmap_params*> 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> 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<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)
{
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<Range> allocate_anywhere(size_t, size_t alignment = PAGE_SIZE);
Optional<Range> allocate_specific(VirtualAddress, size_t);
+ Optional<Range> 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