diff options
author | Sven Schnelle <svens@linux.ibm.com> | 2022-04-06 09:17:21 +0200 |
---|---|---|
committer | Heiko Carstens <hca@linux.ibm.com> | 2022-04-25 13:54:15 +0200 |
commit | 41cd81abafdc4e58a93fcb677712a76885e3ca25 (patch) | |
tree | 4b24529929f568256b7316f7eaa696722f089af9 /arch/s390/kernel | |
parent | 9e37a2e8546f9e48ea76c839116fa5174d14e033 (diff) | |
download | linux-41cd81abafdc4e58a93fcb677712a76885e3ca25.tar.gz linux-41cd81abafdc4e58a93fcb677712a76885e3ca25.tar.bz2 linux-41cd81abafdc4e58a93fcb677712a76885e3ca25.zip |
s390/vdso: add vdso randomization
Randomize the address of vdso if randomize_va_space is enabled.
Note that this keeps the vdso address on the same PMD as the stack
to avoid allocating an extra page table just for vdso.
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/vdso.c | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 7ba84a88ea2a..5075cde77b29 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/smp.h> #include <linux/time_namespace.h> +#include <linux/random.h> #include <vdso/datapage.h> #include <asm/vdso.h> @@ -208,6 +209,31 @@ out: return rc; } +static unsigned long vdso_addr(unsigned long start, unsigned long len) +{ + unsigned long addr, end, offset; + + /* + * Round up the start address. It can start out unaligned as a result + * of stack start randomization. + */ + start = PAGE_ALIGN(start); + + /* Round the lowest possible end address up to a PMD boundary. */ + end = (start + len + PMD_SIZE - 1) & PMD_MASK; + if (end >= VDSO_BASE) + end = VDSO_BASE; + end -= len; + + if (end > start) { + offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1); + addr = start + (offset << PAGE_SHIFT); + } else { + addr = start; + } + return addr; +} + unsigned long vdso_size(void) { unsigned long size = VVAR_NR_PAGES * PAGE_SIZE; @@ -221,7 +247,12 @@ unsigned long vdso_size(void) int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { - return map_vdso(VDSO_BASE, vdso_size()); + unsigned long addr = VDSO_BASE; + unsigned long size = vdso_size(); + + if (current->flags & PF_RANDOMIZE) + addr = vdso_addr(current->mm->start_stack + PAGE_SIZE, size); + return map_vdso(addr, size); } static struct page ** __init vdso_setup_pages(void *start, void *end) |