aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/vdso.c
diff options
context:
space:
mode:
authorSven Schnelle <svens@linux.ibm.com>2022-04-06 09:17:21 +0200
committerHeiko Carstens <hca@linux.ibm.com>2022-04-25 13:54:15 +0200
commit41cd81abafdc4e58a93fcb677712a76885e3ca25 (patch)
tree4b24529929f568256b7316f7eaa696722f089af9 /arch/s390/kernel/vdso.c
parents390/vdso: map vdso above stack (diff)
downloadlinux-dev-41cd81abafdc4e58a93fcb677712a76885e3ca25.tar.xz
linux-dev-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/vdso.c')
-rw-r--r--arch/s390/kernel/vdso.c33
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)