@@ -47,6 +47,18 @@ config RISCV
select GENERIC_IRQ_MULTI_HANDLER
select ARCH_HAS_PTE_SPECIAL
+config HAVE_ARCH_MMAP_RND_BITS
+ def_bool y
+
+config ARCH_MMAP_RND_BITS_MIN
+ default 18
+
+# max bits determined by the following formula:
+# VA_BITS - PAGE_SHIFT - 3
+config ARCH_MMAP_RND_BITS_MAX
+ default 33 if 64BIT # SV48 based
+ default 18
+
config MMU
def_bool y
@@ -23,6 +23,7 @@
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3)
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
#define STACK_TOP TASK_SIZE
#define STACK_TOP_MAX STACK_TOP
@@ -3,3 +3,4 @@ obj-y += fault.o
obj-y += extable.o
obj-y += ioremap.o
obj-y += cacheflush.o
+obj-y += mmap.o
new file mode 100644
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/mm.h>
+#include <linux/sched/mm.h>
+#include <linux/sizes.h>
+#include <linux/personality.h>
+#include <linux/random.h>
+
+/*
+ * Leave enough space between the mmap area and the stack to honour ulimit in
+ * the face of randomisation.
+ */
+#define MIN_GAP (SZ_128M)
+#define MAX_GAP (TASK_SIZE / 6 * 5)
+
+static int mmap_is_legacy(struct rlimit *rlim_stack)
+{
+ if (current->personality & ADDR_COMPAT_LAYOUT)
+ return 1;
+
+ if (rlim_stack->rlim_cur == RLIM_INFINITY)
+ return 1;
+
+ return sysctl_legacy_va_layout;
+}
+
+static unsigned long arch_mmap_rnd(void)
+{
+ unsigned long rnd;
+
+ rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
+
+ return rnd << PAGE_SHIFT;
+}
+
+static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack)
+{
+ unsigned long gap = rlim_stack->rlim_cur;
+
+ if (gap < MIN_GAP)
+ gap = MIN_GAP;
+ else if (gap > MAX_GAP)
+ gap = MAX_GAP;
+
+ return PAGE_ALIGN(TASK_SIZE - gap - rnd);
+}
+
+/*
+ * This function, called very early during the creation of a new process VM
+ * image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
+{
+ unsigned long random_factor = 0UL;
+
+ if (current->flags & PF_RANDOMIZE)
+ random_factor = arch_mmap_rnd();
+
+ /*
+ * Fall back to the standard layout if the personality bit is set, or
+ * if the expected stack growth is unlimited:
+ */
+ if (mmap_is_legacy(rlim_stack)) {
+ mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ } else {
+ mm->mmap_base = mmap_base(random_factor, rlim_stack);
+ mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+ }
+}
In order to avoid wasting user address space by using bottom-up mmap allocation scheme, prefer top-down scheme when possible. This patch is based on arm64 implementation. Before: root@qemuriscv64:~# cat /proc/176/maps 00010000-000be000 r-xp 00000000 fe:00 6355 /bin/bash.bash 000be000-000bf000 r--p 000ad000 fe:00 6355 /bin/bash.bash 000bf000-000c8000 rw-p 000ae000 fe:00 6355 /bin/bash.bash 000c8000-00114000 rw-p 00000000 00:00 0 [heap] 2000000000-2000017000 r-xp 00000000 fe:00 7193 /lib/ld-2.28.so 2000017000-2000018000 r--p 00016000 fe:00 7193 /lib/ld-2.28.so 2000018000-2000019000 rw-p 00017000 fe:00 7193 /lib/ld-2.28.so 2000019000-200001a000 rw-p 00000000 00:00 0 200001a000-200001c000 r-xp 00000000 00:00 0 [vdso] 200001e000-2000020000 rw-p 00000000 00:00 0 2000020000-2000041000 r-xp 00000000 fe:00 7176 /lib/libtinfo.so.5.9 2000041000-2000045000 r--p 00020000 fe:00 7176 /lib/libtinfo.so.5.9 2000045000-2000046000 rw-p 00024000 fe:00 7176 /lib/libtinfo.so.5.9 2000046000-2000048000 r-xp 00000000 fe:00 7112 /lib/libdl-2.28.so 2000048000-2000049000 r--p 00001000 fe:00 7112 /lib/libdl-2.28.so 2000049000-200004a000 rw-p 00002000 fe:00 7112 /lib/libdl-2.28.so 200004a000-2000148000 r-xp 00000000 fe:00 7187 /lib/libc-2.28.so 2000148000-200014c000 r--p 000fd000 fe:00 7187 /lib/libc-2.28.so 200014c000-200014e000 rw-p 00101000 fe:00 7187 /lib/libc-2.28.so 200014e000-2000154000 rw-p 00000000 00:00 0 2000154000-2000159000 r-xp 00000000 fe:00 7100 /lib/libnss_compat-2.28.so 2000159000-200015a000 r--p 00004000 fe:00 7100 /lib/libnss_compat-2.28.so 200015a000-200015b000 rw-p 00005000 fe:00 7100 /lib/libnss_compat-2.28.so 3fff9a4000-3fff9c5000 rw-p 00000000 00:00 0 [stack] After: root@qemuriscv64:~# cat /proc/173/maps 00010000-000be000 r-xp 00000000 fe:00 6355 /bin/bash.bash 000be000-000bf000 r--p 000ad000 fe:00 6355 /bin/bash.bash 000bf000-000c8000 rw-p 000ae000 fe:00 6355 /bin/bash.bash 000c8000-00114000 rw-p 00000000 00:00 0 [heap] 3fdd8d0000-3fdd8d5000 r-xp 00000000 fe:00 7100 /lib/libnss_compat-2.28.so 3fdd8d5000-3fdd8d6000 r--p 00004000 fe:00 7100 /lib/libnss_compat-2.28.so 3fdd8d6000-3fdd8d7000 rw-p 00005000 fe:00 7100 /lib/libnss_compat-2.28.so 3fdd8d7000-3fdd8d9000 rw-p 00000000 00:00 0 3fdd8d9000-3fdd9d7000 r-xp 00000000 fe:00 7187 /lib/libc-2.28.so 3fdd9d7000-3fdd9db000 r--p 000fd000 fe:00 7187 /lib/libc-2.28.so 3fdd9db000-3fdd9dd000 rw-p 00101000 fe:00 7187 /lib/libc-2.28.so 3fdd9dd000-3fdd9e1000 rw-p 00000000 00:00 0 3fdd9e1000-3fdd9e3000 r-xp 00000000 fe:00 7112 /lib/libdl-2.28.so 3fdd9e3000-3fdd9e4000 r--p 00001000 fe:00 7112 /lib/libdl-2.28.so 3fdd9e4000-3fdd9e5000 rw-p 00002000 fe:00 7112 /lib/libdl-2.28.so 3fdd9e5000-3fdda06000 r-xp 00000000 fe:00 7176 /lib/libtinfo.so.5.9 3fdda06000-3fdda0a000 r--p 00020000 fe:00 7176 /lib/libtinfo.so.5.9 3fdda0a000-3fdda0b000 rw-p 00024000 fe:00 7176 /lib/libtinfo.so.5.9 3fdda0b000-3fdda0d000 rw-p 00000000 00:00 0 3fdda0f000-3fdda11000 r-xp 00000000 00:00 0 [vdso] 3fdda11000-3fdda28000 r-xp 00000000 fe:00 7193 /lib/ld-2.28.so 3fdda28000-3fdda29000 r--p 00016000 fe:00 7193 /lib/ld-2.28.so 3fdda29000-3fdda2a000 rw-p 00017000 fe:00 7193 /lib/ld-2.28.so 3fdda2a000-3fdda2b000 rw-p 00000000 00:00 0 3ffff8e000-3ffffaf000 rw-p 00000000 00:00 0 [stack] Signed-off-by: Alexandre Ghiti <alex@ghiti.fr> --- Changes in v2: - Rebased on top of previous patch "riscv: Adjust mmap base address at a third of task size" arch/riscv/Kconfig | 12 ++++++ arch/riscv/include/asm/processor.h | 1 + arch/riscv/mm/Makefile | 1 + arch/riscv/mm/mmap.c | 69 ++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 arch/riscv/mm/mmap.c