diff options
author | Helge Deller <deller@gmx.de> | 2015-05-11 16:01:27 -0400 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2015-05-12 16:03:44 -0400 |
commit | d045c77c1a69703143a36169c224429c48b9eecd (patch) | |
tree | f71e78b7585011274db82483cd95718e11171277 | |
parent | 5fec97d0e3d93717f1d6a958a03e579078088861 (diff) |
parisc,metag: Fix crashes due to stack randomization on stack-grows-upwards architectures
On architectures where the stack grows upwards (CONFIG_STACK_GROWSUP=y,
currently parisc and metag only) stack randomization sometimes leads to crashes
when the stack ulimit is set to lower values than STACK_RND_MASK (which is 8 MB
by default if not defined in arch-specific headers).
The problem is, that when the stack vm_area_struct is set up in fs/exec.c, the
additional space needed for the stack randomization (as defined by the value of
STACK_RND_MASK) was not taken into account yet and as such, when the stack
randomization code added a random offset to the stack start, the stack
effectively got smaller than what the user defined via rlimit_max(RLIMIT_STACK)
which then sometimes leads to out-of-stack situations and crashes.
This patch fixes it by adding the maximum possible amount of memory (based on
STACK_RND_MASK) which theoretically could be added by the stack randomization
code to the initial stack size. That way, the user-defined stack size is always
guaranteed to be at minimum what is defined via rlimit_max(RLIMIT_STACK).
This bug is currently not visible on the metag architecture, because on metag
STACK_RND_MASK is defined to 0 which effectively disables stack randomization.
The changes to fs/exec.c are inside an "#ifdef CONFIG_STACK_GROWSUP"
section, so it does not affect other platformws beside those where the
stack grows upwards (parisc and metag).
Signed-off-by: Helge Deller <deller@gmx.de>
Cc: linux-parisc@vger.kernel.org
Cc: James Hogan <james.hogan@imgtec.com>
Cc: linux-metag@vger.kernel.org
Cc: stable@vger.kernel.org # v3.16+
-rw-r--r-- | arch/parisc/include/asm/elf.h | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/sys_parisc.c | 3 | ||||
-rw-r--r-- | fs/exec.c | 3 |
3 files changed, 10 insertions, 0 deletions
diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index 3391d061eccc..78c9fd32c554 100644 --- a/arch/parisc/include/asm/elf.h +++ b/arch/parisc/include/asm/elf.h | |||
@@ -348,6 +348,10 @@ struct pt_regs; /* forward declaration... */ | |||
348 | 348 | ||
349 | #define ELF_HWCAP 0 | 349 | #define ELF_HWCAP 0 |
350 | 350 | ||
351 | #define STACK_RND_MASK (is_32bit_task() ? \ | ||
352 | 0x7ff >> (PAGE_SHIFT - 12) : \ | ||
353 | 0x3ffff >> (PAGE_SHIFT - 12)) | ||
354 | |||
351 | struct mm_struct; | 355 | struct mm_struct; |
352 | extern unsigned long arch_randomize_brk(struct mm_struct *); | 356 | extern unsigned long arch_randomize_brk(struct mm_struct *); |
353 | #define arch_randomize_brk arch_randomize_brk | 357 | #define arch_randomize_brk arch_randomize_brk |
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index e1ffea2f9a0b..5aba01ac457f 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c | |||
@@ -77,6 +77,9 @@ static unsigned long mmap_upper_limit(void) | |||
77 | if (stack_base > STACK_SIZE_MAX) | 77 | if (stack_base > STACK_SIZE_MAX) |
78 | stack_base = STACK_SIZE_MAX; | 78 | stack_base = STACK_SIZE_MAX; |
79 | 79 | ||
80 | /* Add space for stack randomization. */ | ||
81 | stack_base += (STACK_RND_MASK << PAGE_SHIFT); | ||
82 | |||
80 | return PAGE_ALIGN(STACK_TOP - stack_base); | 83 | return PAGE_ALIGN(STACK_TOP - stack_base); |
81 | } | 84 | } |
82 | 85 | ||
@@ -659,6 +659,9 @@ int setup_arg_pages(struct linux_binprm *bprm, | |||
659 | if (stack_base > STACK_SIZE_MAX) | 659 | if (stack_base > STACK_SIZE_MAX) |
660 | stack_base = STACK_SIZE_MAX; | 660 | stack_base = STACK_SIZE_MAX; |
661 | 661 | ||
662 | /* Add space for stack randomization. */ | ||
663 | stack_base += (STACK_RND_MASK << PAGE_SHIFT); | ||
664 | |||
662 | /* Make sure we didn't let the argument array grow too large. */ | 665 | /* Make sure we didn't let the argument array grow too large. */ |
663 | if (vma->vm_end - vma->vm_start > stack_base) | 666 | if (vma->vm_end - vma->vm_start > stack_base) |
664 | return -ENOMEM; | 667 | return -ENOMEM; |