Merge branch 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[deliverable/linux.git] / arch / x86 / entry / vdso / vma.c
index 25b0368de7f6752e4758f664417d8c7b8e52259e..f840766659a8f4fc2c68d778c7b495ad9b40cf98 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/random.h>
 #include <linux/elf.h>
 #include <linux/cpu.h>
+#include <linux/ptrace.h>
 #include <asm/pvclock.h>
 #include <asm/vgtod.h>
 #include <asm/proto.h>
@@ -97,10 +98,40 @@ static int vdso_fault(const struct vm_special_mapping *sm,
        return 0;
 }
 
-static const struct vm_special_mapping text_mapping = {
-       .name = "[vdso]",
-       .fault = vdso_fault,
-};
+static void vdso_fix_landing(const struct vdso_image *image,
+               struct vm_area_struct *new_vma)
+{
+#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
+       if (in_ia32_syscall() && image == &vdso_image_32) {
+               struct pt_regs *regs = current_pt_regs();
+               unsigned long vdso_land = image->sym_int80_landing_pad;
+               unsigned long old_land_addr = vdso_land +
+                       (unsigned long)current->mm->context.vdso;
+
+               /* Fixing userspace landing - look at do_fast_syscall_32 */
+               if (regs->ip == old_land_addr)
+                       regs->ip = new_vma->vm_start + vdso_land;
+       }
+#endif
+}
+
+static int vdso_mremap(const struct vm_special_mapping *sm,
+               struct vm_area_struct *new_vma)
+{
+       unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
+       const struct vdso_image *image = current->mm->context.vdso_image;
+
+       if (image->size != new_size)
+               return -EINVAL;
+
+       if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))
+               return -EFAULT;
+
+       vdso_fix_landing(image, new_vma);
+       current->mm->context.vdso = (void __user *)new_vma->vm_start;
+
+       return 0;
+}
 
 static int vvar_fault(const struct vm_special_mapping *sm,
                      struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -151,6 +182,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
        struct vm_area_struct *vma;
        unsigned long addr, text_start;
        int ret = 0;
+
+       static const struct vm_special_mapping vdso_mapping = {
+               .name = "[vdso]",
+               .fault = vdso_fault,
+               .mremap = vdso_mremap,
+       };
        static const struct vm_special_mapping vvar_mapping = {
                .name = "[vvar]",
                .fault = vvar_fault,
@@ -185,7 +222,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
                                       image->size,
                                       VM_READ|VM_EXEC|
                                       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
-                                      &text_mapping);
+                                      &vdso_mapping);
 
        if (IS_ERR(vma)) {
                ret = PTR_ERR(vma);
This page took 0.12606 seconds and 5 git commands to generate.