summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Ghiti <alex@ghiti.fr>2019-09-23 18:38:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-24 18:54:11 -0400
commit67f3977f805b34cf0e41090679800d2091d41d49 (patch)
tree890420983b1d78727127650080058e6fea253d01
parente8d54b62c55ab6201de6d195fc2c276294c1f6ae (diff)
arm64, mm: move generic mmap layout functions to mm
arm64 handles top-down mmap layout in a way that can be easily reused by other architectures, so make it available in mm. It then introduces a new config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT that can be set by other architectures to benefit from those functions. Note that this new config depends on MMU being enabled, if selected without MMU support, a warning will be thrown. Link: http://lkml.kernel.org/r/20190730055113.23635-5-alex@ghiti.fr Signed-off-by: Alexandre Ghiti <alex@ghiti.fr> Suggested-by: Christoph Hellwig <hch@infradead.org> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Kees Cook <keescook@chromium.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Luis Chamberlain <mcgrof@kernel.org> Cc: Albert Ou <aou@eecs.berkeley.edu> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: James Hogan <jhogan@kernel.org> Cc: Palmer Dabbelt <palmer@sifive.com> Cc: Paul Burton <paul.burton@mips.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Will Deacon <will.deacon@arm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/Kconfig10
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/include/asm/processor.h2
-rw-r--r--arch/arm64/mm/mmap.c76
-rw-r--r--kernel/sysctl.c6
-rw-r--r--mm/util.c78
6 files changed, 92 insertions, 81 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index 0fcf8ec1e098..dfce421b8e8a 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -706,6 +706,16 @@ config HAVE_ARCH_COMPAT_MMAP_BASES
706 and vice-versa 32-bit applications to call 64-bit mmap(). 706 and vice-versa 32-bit applications to call 64-bit mmap().
707 Required for applications doing different bitness syscalls. 707 Required for applications doing different bitness syscalls.
708 708
709# This allows to use a set of generic functions to determine mmap base
710# address by giving priority to top-down scheme only if the process
711# is not in legacy mode (compat task, unlimited stack size or
712# sysctl_legacy_va_layout).
713# Architecture that selects this option can provide its own version of:
714# - STACK_RND_MASK
715config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
716 bool
717 depends on MMU
718
709config HAVE_COPY_THREAD_TLS 719config HAVE_COPY_THREAD_TLS
710 bool 720 bool
711 help 721 help
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 37c610963eee..2d4b7044063c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -71,6 +71,7 @@ config ARM64
71 select ARCH_SUPPORTS_INT128 if GCC_VERSION >= 50000 || CC_IS_CLANG 71 select ARCH_SUPPORTS_INT128 if GCC_VERSION >= 50000 || CC_IS_CLANG
72 select ARCH_SUPPORTS_NUMA_BALANCING 72 select ARCH_SUPPORTS_NUMA_BALANCING
73 select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT 73 select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT
74 select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
74 select ARCH_WANT_FRAME_POINTERS 75 select ARCH_WANT_FRAME_POINTERS
75 select ARCH_WANT_HUGE_PMD_SHARE if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36) 76 select ARCH_WANT_HUGE_PMD_SHARE if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
76 select ARCH_HAS_UBSAN_SANITIZE_ALL 77 select ARCH_HAS_UBSAN_SANITIZE_ALL
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index c67848c55009..5623685c7d13 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -280,8 +280,6 @@ static inline void spin_lock_prefetch(const void *ptr)
280 "nop") : : "p" (ptr)); 280 "nop") : : "p" (ptr));
281} 281}
282 282
283#define HAVE_ARCH_PICK_MMAP_LAYOUT
284
285extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */ 283extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */
286extern void __init minsigstksz_setup(void); 284extern void __init minsigstksz_setup(void);
287 285
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index e4acaead67de..3028bacbc4e9 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -21,82 +21,6 @@
21#include <asm/cputype.h> 21#include <asm/cputype.h>
22 22
23/* 23/*
24 * Leave enough space between the mmap area and the stack to honour ulimit in
25 * the face of randomisation.
26 */
27#define MIN_GAP (SZ_128M)
28#define MAX_GAP (STACK_TOP/6*5)
29
30static int mmap_is_legacy(struct rlimit *rlim_stack)
31{
32 if (current->personality & ADDR_COMPAT_LAYOUT)
33 return 1;
34
35 if (rlim_stack->rlim_cur == RLIM_INFINITY)
36 return 1;
37
38 return sysctl_legacy_va_layout;
39}
40
41unsigned long arch_mmap_rnd(void)
42{
43 unsigned long rnd;
44
45#ifdef CONFIG_COMPAT
46 if (is_compat_task())
47 rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
48 else
49#endif
50 rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
51 return rnd << PAGE_SHIFT;
52}
53
54static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack)
55{
56 unsigned long gap = rlim_stack->rlim_cur;
57 unsigned long pad = stack_guard_gap;
58
59 /* Account for stack randomization if necessary */
60 if (current->flags & PF_RANDOMIZE)
61 pad += (STACK_RND_MASK << PAGE_SHIFT);
62
63 /* Values close to RLIM_INFINITY can overflow. */
64 if (gap + pad > gap)
65 gap += pad;
66
67 if (gap < MIN_GAP)
68 gap = MIN_GAP;
69 else if (gap > MAX_GAP)
70 gap = MAX_GAP;
71
72 return PAGE_ALIGN(STACK_TOP - gap - rnd);
73}
74
75/*
76 * This function, called very early during the creation of a new process VM
77 * image, sets up which VM layout function to use:
78 */
79void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
80{
81 unsigned long random_factor = 0UL;
82
83 if (current->flags & PF_RANDOMIZE)
84 random_factor = arch_mmap_rnd();
85
86 /*
87 * Fall back to the standard layout if the personality bit is set, or
88 * if the expected stack growth is unlimited:
89 */
90 if (mmap_is_legacy(rlim_stack)) {
91 mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
92 mm->get_unmapped_area = arch_get_unmapped_area;
93 } else {
94 mm->mmap_base = mmap_base(random_factor, rlim_stack);
95 mm->get_unmapped_area = arch_get_unmapped_area_topdown;
96 }
97}
98
99/*
100 * You really shouldn't be using read() or write() on /dev/mem. This might go 24 * You really shouldn't be using read() or write() on /dev/mem. This might go
101 * away in the future. 25 * away in the future.
102 */ 26 */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 078950d9605b..00fcea236eba 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -264,7 +264,8 @@ extern struct ctl_table epoll_table[];
264extern struct ctl_table firmware_config_table[]; 264extern struct ctl_table firmware_config_table[];
265#endif 265#endif
266 266
267#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT 267#if defined(HAVE_ARCH_PICK_MMAP_LAYOUT) || \
268 defined(CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT)
268int sysctl_legacy_va_layout; 269int sysctl_legacy_va_layout;
269#endif 270#endif
270 271
@@ -1573,7 +1574,8 @@ static struct ctl_table vm_table[] = {
1573 .proc_handler = proc_dointvec, 1574 .proc_handler = proc_dointvec,
1574 .extra1 = SYSCTL_ZERO, 1575 .extra1 = SYSCTL_ZERO,
1575 }, 1576 },
1576#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT 1577#if defined(HAVE_ARCH_PICK_MMAP_LAYOUT) || \
1578 defined(CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT)
1577 { 1579 {
1578 .procname = "legacy_va_layout", 1580 .procname = "legacy_va_layout",
1579 .data = &sysctl_legacy_va_layout, 1581 .data = &sysctl_legacy_va_layout,
diff --git a/mm/util.c b/mm/util.c
index bf8af5e07c4a..7922726f0a8f 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -17,7 +17,12 @@
17#include <linux/vmalloc.h> 17#include <linux/vmalloc.h>
18#include <linux/userfaultfd_k.h> 18#include <linux/userfaultfd_k.h>
19#include <linux/elf.h> 19#include <linux/elf.h>
20#include <linux/elf-randomize.h>
21#include <linux/personality.h>
20#include <linux/random.h> 22#include <linux/random.h>
23#include <linux/processor.h>
24#include <linux/sizes.h>
25#include <linux/compat.h>
21 26
22#include <linux/uaccess.h> 27#include <linux/uaccess.h>
23 28
@@ -315,7 +320,78 @@ unsigned long randomize_stack_top(unsigned long stack_top)
315#endif 320#endif
316} 321}
317 322
318#if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT) 323#ifdef CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
324#ifdef CONFIG_ARCH_HAS_ELF_RANDOMIZE
325unsigned long arch_mmap_rnd(void)
326{
327 unsigned long rnd;
328
329#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS
330 if (is_compat_task())
331 rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
332 else
333#endif /* CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS */
334 rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
335
336 return rnd << PAGE_SHIFT;
337}
338#endif /* CONFIG_ARCH_HAS_ELF_RANDOMIZE */
339
340static int mmap_is_legacy(struct rlimit *rlim_stack)
341{
342 if (current->personality & ADDR_COMPAT_LAYOUT)
343 return 1;
344
345 if (rlim_stack->rlim_cur == RLIM_INFINITY)
346 return 1;
347
348 return sysctl_legacy_va_layout;
349}
350
351/*
352 * Leave enough space between the mmap area and the stack to honour ulimit in
353 * the face of randomisation.
354 */
355#define MIN_GAP (SZ_128M)
356#define MAX_GAP (STACK_TOP / 6 * 5)
357
358static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack)
359{
360 unsigned long gap = rlim_stack->rlim_cur;
361 unsigned long pad = stack_guard_gap;
362
363 /* Account for stack randomization if necessary */
364 if (current->flags & PF_RANDOMIZE)
365 pad += (STACK_RND_MASK << PAGE_SHIFT);
366
367 /* Values close to RLIM_INFINITY can overflow. */
368 if (gap + pad > gap)
369 gap += pad;
370
371 if (gap < MIN_GAP)
372 gap = MIN_GAP;
373 else if (gap > MAX_GAP)
374 gap = MAX_GAP;
375
376 return PAGE_ALIGN(STACK_TOP - gap - rnd);
377}
378
379void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
380{
381 unsigned long random_factor = 0UL;
382
383 if (current->flags & PF_RANDOMIZE)
384 random_factor = arch_mmap_rnd();
385
386 if (mmap_is_legacy(rlim_stack)) {
387 mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
388 mm->get_unmapped_area = arch_get_unmapped_area;
389 } else {
390 mm->mmap_base = mmap_base(random_factor, rlim_stack);
391 mm->get_unmapped_area = arch_get_unmapped_area_topdown;
392 }
393}
394#elif defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
319void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack) 395void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
320{ 396{
321 mm->mmap_base = TASK_UNMAPPED_BASE; 397 mm->mmap_base = TASK_UNMAPPED_BASE;