Vanilla API to map vdso with prctl() checks if vdso/vvar area is
already present and returns EEXIST in that case.

With the current API previous vdso/vvar blob is unmapped during
prctl() - but (1) that's less flexible and (2) CRIU calls
ARCH_MAP_VDSO_32 to check if it can do 32-bit C/R and expects
EEXIST.

Adjust API to be the same as in ms.

Signed-off-by: Dmitry Safonov <[email protected]>
---
 arch/x86/vdso/vdso32-setup.c | 29 +++++++++++++++--------------
 include/linux/mm.h           |  2 ++
 mm/mmap.c                    | 20 ++++++++++++++++++++
 3 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 5056d0ec9ab7..59ec0e2ebee0 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -494,11 +494,20 @@ up_fail:
 
 #ifdef CONFIG_X86_64
 
+static bool vdso_or_vvar_present(struct mm_struct *mm)
+{
+       struct vm_area_struct *vma;
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next)
+               if (vma_is_vdso_or_vvar(vma, mm))
+                       return true;
+       return false;
+}
+
 int do_map_compat_vdso(unsigned long req_addr)
 {
        struct mm_struct *mm = current->mm;
        unsigned long vdso_addr;
-       struct vm_area_struct *vdso_vma;
        int ret;
        bool compat;
 
@@ -514,7 +523,11 @@ int do_map_compat_vdso(unsigned long req_addr)
                goto up_fail;
        }
 
-       /* Don't wanna copy security checks like security_mmap_addr() */
+       if (vdso_or_vvar_present(mm)) {
+               ret = -EEXIST;
+               goto up_fail;
+       }
+
        vdso_addr = get_unmapped_area(NULL, req_addr, PAGE_SIZE, 0, 0);
        if (IS_ERR_VALUE(vdso_addr)) {
                ret = vdso_addr;
@@ -526,18 +539,6 @@ int do_map_compat_vdso(unsigned long req_addr)
                goto up_fail;
        }
 
-       /*
-        * Firstly, unmap old vdso - as install_special_mapping may not
-        * do rlimit/cgroup accounting right - get rid of the old one by
-        * remove_vma().
-        */
-       vdso_vma = find_vma_intersection(mm, (unsigned long)mm->context.vdso,
-                       (unsigned long)mm->context.vdso +
-                       PAGE_SIZE*init_uts_ns.vdso.nr_pages);
-       if (vdso_vma)
-               do_munmap(mm, vdso_vma->vm_start,
-                       vdso_vma->vm_end - vdso_vma->vm_start);
-
        ret = __arch_setup_additional_pages(req_addr, compat);
        if (ret)
                current->mm->context.vdso = NULL;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a8f5630fc997..c7a1acd50901 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1848,6 +1848,8 @@ extern struct file *get_mm_exe_file(struct mm_struct *mm);
 extern struct file *get_task_exe_file(struct task_struct *task);
 
 extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
+extern bool vma_is_vdso_or_vvar(const struct vm_area_struct *vma,
+                                  const struct mm_struct *mm);
 extern int install_special_mapping(struct mm_struct *mm,
                                   unsigned long addr, unsigned long len,
                                   unsigned long flags, struct page **pages);
diff --git a/mm/mmap.c b/mm/mmap.c
index 54c188e8b0f1..33d324459844 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -3173,6 +3173,26 @@ out:
        return ret;
 }
 
+bool vma_is_vdso_or_vvar(const struct vm_area_struct *vma,
+                  const struct mm_struct *mm)
+{
+       /*
+        * As we have uts name virtualization, we can't tell if area
+        * is VVAR/VDSO the same way as in mainline: vma->vm_private_data
+        * is different, allocated in uts_prep_vdso_pages_locked().
+        * As install_special_mapping() can be used currently only by
+        * uprobes (besides vdso and vvar), check if special mapping
+        * is related to uprobes, if not - it's vdso/vvar.
+        */
+       struct page *xol_page = NULL;
+
+       if (mm->uprobes_state.xol_area)
+               xol_page = mm->uprobes_state.xol_area->page;
+
+       return (vma->vm_ops == &special_mapping_vmops) &&
+               (vma->vm_private_data != xol_page);
+}
+
 static DEFINE_MUTEX(mm_all_locks_mutex);
 
 static void vm_lock_anon_vma(struct mm_struct *mm, struct anon_vma *anon_vma)
-- 
2.12.2

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to