diff mbox series

riscv: Make mmap allocation top-down by default

Message ID 20190127165348.16183-1-alex@ghiti.fr (mailing list archive)
State New, archived
Headers show
Series riscv: Make mmap allocation top-down by default | expand

Commit Message

Alexandre Ghiti Jan. 27, 2019, 4:53 p.m. UTC
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>
---
 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
diff mbox series

Patch

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index e0d7d61779a6..684f3e00e9f8 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -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
 
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 0531f49af5c3..5ea9119f173c 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -23,6 +23,7 @@ 
  * space during mmap's.
  */
 #define TASK_UNMAPPED_BASE	PAGE_ALIGN(TASK_SIZE >> 1)
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
 
 #define STACK_TOP		TASK_SIZE
 #define STACK_TOP_MAX		STACK_TOP
diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile
index eb22ab49b3e0..0eb23b10d0bd 100644
--- a/arch/riscv/mm/Makefile
+++ b/arch/riscv/mm/Makefile
@@ -3,3 +3,4 @@  obj-y += fault.o
 obj-y += extable.o
 obj-y += ioremap.o
 obj-y += cacheflush.o
+obj-y += mmap.o
diff --git a/arch/riscv/mm/mmap.c b/arch/riscv/mm/mmap.c
new file mode 100644
index 000000000000..d182ac66d2e7
--- /dev/null
+++ b/arch/riscv/mm/mmap.c
@@ -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;
+	}
+}