Commit 67f3977f authored by Alexandre Ghiti's avatar Alexandre Ghiti Committed by Linus Torvalds
Browse files

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: default avatarAlexandre Ghiti <alex@ghiti.fr>
Suggested-by: default avatarChristoph Hellwig <hch@infradead.org>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Acked-by: default avatarKees Cook <keescook@chromium.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarLuis 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e8d54b62
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -706,6 +706,16 @@ config HAVE_ARCH_COMPAT_MMAP_BASES
	  and vice-versa 32-bit applications to call 64-bit mmap().
	  Required for applications doing different bitness syscalls.

# This allows to use a set of generic functions to determine mmap base
# address by giving priority to top-down scheme only if the process
# is not in legacy mode (compat task, unlimited stack size or
# sysctl_legacy_va_layout).
# Architecture that selects this option can provide its own version of:
# - STACK_RND_MASK
config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
	bool
	depends on MMU

config HAVE_COPY_THREAD_TLS
	bool
	help
+1 −0
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ config ARM64
	select ARCH_SUPPORTS_INT128 if GCC_VERSION >= 50000 || CC_IS_CLANG
	select ARCH_SUPPORTS_NUMA_BALANCING
	select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT
	select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
	select ARCH_WANT_FRAME_POINTERS
	select ARCH_WANT_HUGE_PMD_SHARE if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
	select ARCH_HAS_UBSAN_SANITIZE_ALL
+0 −2
Original line number Diff line number Diff line
@@ -280,8 +280,6 @@ static inline void spin_lock_prefetch(const void *ptr)
		     "nop") : : "p" (ptr));
}

#define HAVE_ARCH_PICK_MMAP_LAYOUT

extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */
extern void __init minsigstksz_setup(void);

+0 −76
Original line number Diff line number Diff line
@@ -20,82 +20,6 @@

#include <asm/cputype.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	(STACK_TOP/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;
}

unsigned long arch_mmap_rnd(void)
{
	unsigned long rnd;

#ifdef CONFIG_COMPAT
	if (is_compat_task())
		rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
	else
#endif
		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;
	unsigned long pad = stack_guard_gap;

	/* Account for stack randomization if necessary */
	if (current->flags & PF_RANDOMIZE)
		pad += (STACK_RND_MASK << PAGE_SHIFT);

	/* Values close to RLIM_INFINITY can overflow. */
	if (gap + pad > gap)
		gap += pad;

	if (gap < MIN_GAP)
		gap = MIN_GAP;
	else if (gap > MAX_GAP)
		gap = MAX_GAP;

	return PAGE_ALIGN(STACK_TOP - 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;
	}
}

/*
 * You really shouldn't be using read() or write() on /dev/mem.  This might go
 * away in the future.
+4 −2
Original line number Diff line number Diff line
@@ -264,7 +264,8 @@ extern struct ctl_table epoll_table[];
extern struct ctl_table firmware_config_table[];
#endif

#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
#if defined(HAVE_ARCH_PICK_MMAP_LAYOUT) || \
    defined(CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT)
int sysctl_legacy_va_layout;
#endif

@@ -1573,7 +1574,8 @@ static struct ctl_table vm_table[] = {
		.proc_handler	= proc_dointvec,
		.extra1		= SYSCTL_ZERO,
	},
#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
#if defined(HAVE_ARCH_PICK_MMAP_LAYOUT) || \
    defined(CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT)
	{
		.procname	= "legacy_va_layout",
		.data		= &sysctl_legacy_va_layout,
Loading