Merge branch 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 4 Oct 2016 00:29:01 +0000 (17:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 4 Oct 2016 00:29:01 +0000 (17:29 -0700)
Pull x86 vdso updates from Ingo Molnar:
 "The main changes in this cycle centered around adding support for
  32-bit compatible C/R of the vDSO on 64-bit kernels, by Dmitry
  Safonov"

* 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/vdso: Use CONFIG_X86_X32_ABI to enable vdso prctl
  x86/vdso: Only define map_vdso_randomized() if CONFIG_X86_64
  x86/vdso: Only define prctl_map_vdso() if CONFIG_CHECKPOINT_RESTORE
  x86/signal: Add SA_{X32,IA32}_ABI sa_flags
  x86/ptrace: Down with test_thread_flag(TIF_IA32)
  x86/coredump: Use pr_reg size, rather that TIF_IA32 flag
  x86/arch_prctl/vdso: Add ARCH_MAP_VDSO_*
  x86/vdso: Replace calculate_addr in map_vdso() with addr
  x86/vdso: Unmap vdso blob on vvar mapping failure

1  2 
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/signal.c
mm/mmap.c

index de9acaf2d371b8dd8fb23e94a6384e89ef4751b0,b4603b71a65905067f817d835b20ad2009b55e69..ee944bd2310d8b0017954e558d6067c3e85b3001
  #include <asm/debugreg.h>
  #include <asm/switch_to.h>
  #include <asm/xen/hypervisor.h>
+ #include <asm/vdso.h>
  
 -asmlinkage extern void ret_from_fork(void);
 -
  __visible DEFINE_PER_CPU(unsigned long, rsp_scratch);
  
  /* Prints also some state that isn't saved in the pt_regs */
@@@ -139,17 -142,12 +140,17 @@@ int copy_thread_tls(unsigned long clone
  {
        int err;
        struct pt_regs *childregs;
 +      struct fork_frame *fork_frame;
 +      struct inactive_task_frame *frame;
        struct task_struct *me = current;
  
        p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE;
        childregs = task_pt_regs(p);
 -      p->thread.sp = (unsigned long) childregs;
 -      set_tsk_thread_flag(p, TIF_FORK);
 +      fork_frame = container_of(childregs, struct fork_frame, regs);
 +      frame = &fork_frame->frame;
 +      frame->bp = 0;
 +      frame->ret_addr = (unsigned long) ret_from_fork;
 +      p->thread.sp = (unsigned long) fork_frame;
        p->thread.io_bitmap_ptr = NULL;
  
        savesegment(gs, p->thread.gsindex);
        if (unlikely(p->flags & PF_KTHREAD)) {
                /* kernel thread */
                memset(childregs, 0, sizeof(struct pt_regs));
 -              childregs->sp = (unsigned long)childregs;
 -              childregs->ss = __KERNEL_DS;
 -              childregs->bx = sp; /* function */
 -              childregs->bp = arg;
 -              childregs->orig_ax = -1;
 -              childregs->cs = __KERNEL_CS | get_kernel_rpl();
 -              childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
 +              frame->bx = sp;         /* function */
 +              frame->r12 = arg;
                return 0;
        }
 +      frame->bx = 0;
        *childregs = *current_pt_regs();
  
        childregs->ax = 0;
@@@ -510,7 -512,7 +511,7 @@@ void set_personality_ia32(bool x32
                current->personality &= ~READ_IMPLIES_EXEC;
                /* in_compat_syscall() uses the presence of the x32
                   syscall bit flag to determine compat status */
 -              current_thread_info()->status &= ~TS_COMPAT;
 +              current->thread.status &= ~TS_COMPAT;
        } else {
                set_thread_flag(TIF_IA32);
                clear_thread_flag(TIF_X32);
                        current->mm->context.ia32_compat = TIF_IA32;
                current->personality |= force_personality32;
                /* Prepare the first "return" to user space */
 -              current_thread_info()->status |= TS_COMPAT;
 +              current->thread.status |= TS_COMPAT;
        }
  }
  EXPORT_SYMBOL_GPL(set_personality_ia32);
  
+ #ifdef CONFIG_CHECKPOINT_RESTORE
+ static long prctl_map_vdso(const struct vdso_image *image, unsigned long addr)
+ {
+       int ret;
+       ret = map_vdso_once(image, addr);
+       if (ret)
+               return ret;
+       return (long)image->size;
+ }
+ #endif
  long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
  {
        int ret = 0;
                break;
        }
  
+ #ifdef CONFIG_CHECKPOINT_RESTORE
+ # ifdef CONFIG_X86_X32_ABI
+       case ARCH_MAP_VDSO_X32:
+               return prctl_map_vdso(&vdso_image_x32, addr);
+ # endif
+ # if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
+       case ARCH_MAP_VDSO_32:
+               return prctl_map_vdso(&vdso_image_32, addr);
+ # endif
+       case ARCH_MAP_VDSO_64:
+               return prctl_map_vdso(&vdso_image_64, addr);
+ #endif
        default:
                ret = -EINVAL;
                break;
diff --combined arch/x86/kernel/ptrace.c
index ce94c38cf4d6bd3acb5bbebab057d6eeab21f72a,ad0bab8fc5949d4abe01f9aae6df116841721baf..0e63c0267f99c3360906e8b27a2a1fa646a65dde
@@@ -173,8 -173,8 +173,8 @@@ unsigned long kernel_stack_pointer(stru
                return sp;
  
        prev_esp = (u32 *)(context);
 -      if (prev_esp)
 -              return (unsigned long)prev_esp;
 +      if (*prev_esp)
 +              return (unsigned long)*prev_esp;
  
        return (unsigned long)regs;
  }
@@@ -934,7 -934,7 +934,7 @@@ static int putreg32(struct task_struct 
                 */
                regs->orig_ax = value;
                if (syscall_get_nr(child, regs) >= 0)
 -                      task_thread_info(child)->status |= TS_I386_REGS_POKED;
 +                      child->thread.status |= TS_I386_REGS_POKED;
                break;
  
        case offsetof(struct user32, regs.eflags):
@@@ -1250,7 -1250,7 +1250,7 @@@ long compat_arch_ptrace(struct task_str
  
  #ifdef CONFIG_X86_64
  
 -static struct user_regset x86_64_regsets[] __read_mostly = {
 +static struct user_regset x86_64_regsets[] __ro_after_init = {
        [REGSET_GENERAL] = {
                .core_note_type = NT_PRSTATUS,
                .n = sizeof(struct user_regs_struct) / sizeof(long),
@@@ -1291,7 -1291,7 +1291,7 @@@ static const struct user_regset_view us
  #endif        /* CONFIG_X86_64 */
  
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
 -static struct user_regset x86_32_regsets[] __read_mostly = {
 +static struct user_regset x86_32_regsets[] __ro_after_init = {
        [REGSET_GENERAL] = {
                .core_note_type = NT_PRSTATUS,
                .n = sizeof(struct user_regs_struct32) / sizeof(u32),
@@@ -1344,7 -1344,7 +1344,7 @@@ static const struct user_regset_view us
   */
  u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
  
 -void update_regset_xstate_info(unsigned int size, u64 xstate_mask)
 +void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask)
  {
  #ifdef CONFIG_X86_64
        x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64);
  const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  {
  #ifdef CONFIG_IA32_EMULATION
-       if (test_tsk_thread_flag(task, TIF_IA32))
+       if (!user_64bit_mode(task_pt_regs(task)))
  #endif
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
                return &user_x86_32_view;
diff --combined arch/x86/kernel/signal.c
index da20ecb5397a4d127532c7282b22cca46cece397,b1a5d252d482a8dbbbb2f741b48e1873b5713fbe..763af1d0de64d8f8bbd323453e9ca7d266864c13
@@@ -42,6 -42,7 +42,7 @@@
  #include <asm/syscalls.h>
  
  #include <asm/sigframe.h>
+ #include <asm/signal.h>
  
  #define COPY(x)                       do {                    \
        get_user_ex(regs->x, &sc->x);                   \
@@@ -547,7 -548,7 +548,7 @@@ static int x32_setup_rt_frame(struct ks
                return -EFAULT;
  
        if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
-               if (copy_siginfo_to_user32(&frame->info, &ksig->info))
+               if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true))
                        return -EFAULT;
        }
  
@@@ -660,20 -661,21 +661,21 @@@ badframe
        return 0;
  }
  
- static inline int is_ia32_compat_frame(void)
+ static inline int is_ia32_compat_frame(struct ksignal *ksig)
  {
        return IS_ENABLED(CONFIG_IA32_EMULATION) &&
-              test_thread_flag(TIF_IA32);
+               ksig->ka.sa.sa_flags & SA_IA32_ABI;
  }
  
- static inline int is_ia32_frame(void)
+ static inline int is_ia32_frame(struct ksignal *ksig)
  {
-       return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame();
+       return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(ksig);
  }
  
- static inline int is_x32_frame(void)
+ static inline int is_x32_frame(struct ksignal *ksig)
  {
-       return IS_ENABLED(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32);
+       return IS_ENABLED(CONFIG_X86_X32_ABI) &&
+               ksig->ka.sa.sa_flags & SA_X32_ABI;
  }
  
  static int
@@@ -684,12 -686,12 +686,12 @@@ setup_rt_frame(struct ksignal *ksig, st
        compat_sigset_t *cset = (compat_sigset_t *) set;
  
        /* Set up the stack frame */
-       if (is_ia32_frame()) {
+       if (is_ia32_frame(ksig)) {
                if (ksig->ka.sa.sa_flags & SA_SIGINFO)
                        return ia32_setup_rt_frame(usig, ksig, cset, regs);
                else
                        return ia32_setup_frame(usig, ksig, cset, regs);
-       } else if (is_x32_frame()) {
+       } else if (is_x32_frame(ksig)) {
                return x32_setup_rt_frame(ksig, cset, regs);
        } else {
                return __setup_rt_frame(ksig->sig, ksig, set, regs);
@@@ -783,7 -785,7 +785,7 @@@ static inline unsigned long get_nr_rest
         * than the tracee.
         */
  #ifdef CONFIG_IA32_EMULATION
 -      if (current_thread_info()->status & (TS_COMPAT|TS_I386_REGS_POKED))
 +      if (current->thread.status & (TS_COMPAT|TS_I386_REGS_POKED))
                return __NR_ia32_restart_syscall;
  #endif
  #ifdef CONFIG_X86_X32_ABI
diff --combined mm/mmap.c
index 69cad562cd002331b104746de9a5e88d3742ef84,6373ebd358c0eb3a90b3c8588c717f836580767f..7a0707a480479f1837cc6537182300bd6d94d51f
+++ b/mm/mmap.c
@@@ -88,11 -88,6 +88,11 @@@ static void unmap_region(struct mm_stru
   *            w: (no) no      w: (no) no      w: (copy) copy  w: (no) no
   *            x: (no) no      x: (no) yes     x: (no) yes     x: (yes) yes
   *
 + * On arm64, PROT_EXEC has the following behaviour for both MAP_SHARED and
 + * MAP_PRIVATE:
 + *                                                            r: (no) no
 + *                                                            w: (no) no
 + *                                                            x: (yes) yes
   */
  pgprot_t protection_map[16] = {
        __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
        return ERR_PTR(ret);
  }
  
+ bool vma_is_special_mapping(const struct vm_area_struct *vma,
+       const struct vm_special_mapping *sm)
+ {
+       return vma->vm_private_data == sm &&
+               (vma->vm_ops == &special_mapping_vmops ||
+                vma->vm_ops == &legacy_special_mapping_vmops);
+ }
  /*
   * Called with mm->mmap_sem held for writing.
   * Insert a new vma covering the given region, with the given flags.