arm64: vdso: put vdso datapage in a separate vma
authorWill Deacon <will.deacon@arm.com>
Wed, 9 Jul 2014 18:22:11 +0000 (19:22 +0100)
committerMark Brown <broonie@linaro.org>
Tue, 22 Jul 2014 23:37:26 +0000 (00:37 +0100)
The VDSO datapage doesn't need to be executable (no code there) or
CoW-able (the kernel writes the page, so a private copy is totally
useless).

This patch moves the datapage into its own VMA, identified as "[vvar]"
in /proc/<pid>/maps.

Cc: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
(cherry picked from commit 8715493852783358ef8656a0054a14bf822509cf)
Signed-off-by: Mark Brown <broonie@linaro.org>
arch/arm64/kernel/vdso.c

index 10c27f5f6d237f5b9ef1f8e580eafea8080314c2..40ba5dea2ed7bfc9030cf6d66e589ccce6401dfb 100644 (file)
@@ -135,11 +135,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
                                int uses_interp)
 {
        struct mm_struct *mm = current->mm;
-       unsigned long vdso_base, vdso_mapping_len;
+       unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
        int ret;
 
+       vdso_text_len = vdso_pages << PAGE_SHIFT;
        /* Be sure to map the data page */
-       vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT;
+       vdso_mapping_len = vdso_text_len + PAGE_SIZE;
 
        down_write(&mm->mmap_sem);
        vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
@@ -149,35 +150,52 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
        }
        mm->context.vdso = (void *)vdso_base;
 
-       ret = install_special_mapping(mm, vdso_base, vdso_mapping_len,
+       ret = install_special_mapping(mm, vdso_base, vdso_text_len,
                                      VM_READ|VM_EXEC|
                                      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                                      vdso_pagelist);
-       if (ret) {
-               mm->context.vdso = NULL;
+       if (ret)
+               goto up_fail;
+
+       vdso_base += vdso_text_len;
+       ret = install_special_mapping(mm, vdso_base, PAGE_SIZE,
+                                     VM_READ|VM_MAYREAD,
+                                     vdso_pagelist + vdso_pages);
+       if (ret)
                goto up_fail;
-       }
 
-up_fail:
        up_write(&mm->mmap_sem);
+       return 0;
 
+up_fail:
+       mm->context.vdso = NULL;
+       up_write(&mm->mmap_sem);
        return ret;
 }
 
 const char *arch_vma_name(struct vm_area_struct *vma)
 {
+       unsigned long vdso_text;
+
+       if (!vma->vm_mm)
+               return NULL;
+
+       vdso_text = (unsigned long)vma->vm_mm->context.vdso;
+
        /*
         * We can re-use the vdso pointer in mm_context_t for identifying
         * the vectors page for compat applications. The vDSO will always
         * sit above TASK_UNMAPPED_BASE and so we don't need to worry about
         * it conflicting with the vectors base.
         */
-       if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) {
+       if (vma->vm_start == vdso_text) {
 #ifdef CONFIG_COMPAT
                if (vma->vm_start == AARCH32_VECTORS_BASE)
                        return "[vectors]";
 #endif
                return "[vdso]";
+       } else if (vma->vm_start == (vdso_text + (vdso_pages << PAGE_SHIFT))) {
+               return "[vvar]";
        }
 
        return NULL;