Unlimited stack size (ulimit -s unlimited) causes kernel to use legacy layout for applications. Thus, if VDSO isn't mapped above STACK_TOP, it will be mapped at a very low address. This will probably cause an early brk() failure and then a segmentation fault, because the application's initial mm->brk is usually below VDSO (especially when COMPAT_BRK is enabled) and there is no more room to expand its heap. This patch reserve 4 MB space above STACK_TOP, and use the low 2 MB for VDSO randomization (as a result, VDSO pages can use as much as 2 MB). Cc: stable@xxxxxxxxxxxxxxx Signed-off-by: Huacai Chen <chenhc@xxxxxxxxxx> --- arch/mips/include/asm/processor.h | 5 +++-- arch/mips/kernel/vdso.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 95b8c47..1c99e2c 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -13,6 +13,7 @@ #include <linux/atomic.h> #include <linux/cpumask.h> +#include <linux/sizes.h> #include <linux/threads.h> #include <asm/cachectl.h> @@ -82,9 +83,9 @@ extern unsigned int vced_count, vcei_count; /* * One page above the stack is used for branch delay slot "emulation". - * See dsemul.c for details. + * See dsemul.c for details, other pages are for VDSO. */ -#define STACK_TOP ((TASK_SIZE & PAGE_MASK) - PAGE_SIZE) +#define STACK_TOP ((TASK_SIZE & PAGE_MASK) - SZ_4M) /* * This decides where the kernel will search for a free chunk of vm diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index 093517e..71fecec 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -15,6 +15,7 @@ #include <linux/ioport.h> #include <linux/irqchip/mips-gic.h> #include <linux/mm.h> +#include <linux/random.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/timekeeper_internal.h> @@ -95,6 +96,19 @@ void update_vsyscall_tz(void) } } +static unsigned long vdso_base(void) +{ + unsigned long offset = 0UL; + + if (current->flags & PF_RANDOMIZE) { + offset = get_random_int(); + offset <<= PAGE_SHIFT; + offset &= 0x1ffffful; /* 2 MB */ + } + + return STACK_TOP + PAGE_SIZE + offset; +} + int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mips_vdso_image *image = current->thread.abi->vdso; @@ -129,7 +143,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) vvar_size = gic_size + PAGE_SIZE; size = vvar_size + image->size; - base = get_unmapped_area(NULL, 0, size, 0, 0); + base = get_unmapped_area(NULL, vdso_base(), size, 0, 0); if (IS_ERR_VALUE(base)) { ret = base; goto out; -- 2.7.0