Merge branches 'fixes', 'misc' and 'spectre' into for-next
authorRussell King <rmk+kernel@armlinux.org.uk>
Wed, 10 Oct 2018 12:53:33 +0000 (13:53 +0100)
committerRussell King <rmk+kernel@armlinux.org.uk>
Wed, 10 Oct 2018 12:53:33 +0000 (13:53 +0100)
1  2  3 
arch/arm/include/asm/assembler.h
arch/arm/include/asm/uaccess.h
arch/arm/kernel/signal.c
arch/arm/kernel/sys_oabi-compat.c
arch/arm/vfp/vfpmodule.c

index b17ee03d280b6ff9ff706f04ab4d3be57f20bfe8,b17ee03d280b6ff9ff706f04ab4d3be57f20bfe8,39651c1ec157120117ad3feaa286dc66407f7e89..88286dd483ff901bd1d215fb5450db32add47bd2
@@@@ -467,6 -467,6 -467,17 +467,17 @@@@ THUMB(  orr     \reg , \reg , #PSR_T_BIT        
   #endif
        .endm
   
++      .macro uaccess_mask_range_ptr, addr:req, size:req, limit:req, tmp:req
++ #ifdef CONFIG_CPU_SPECTRE
++      sub     \tmp, \limit, #1
++      subs    \tmp, \tmp, \addr       @ tmp = limit - 1 - addr
++      addhs   \tmp, \tmp, #1          @ if (tmp >= 0) {
++      subhss  \tmp, \tmp, \size       @ tmp = limit - (addr + size) }
++      movlo   \addr, #0               @ if (tmp < 0) addr = NULL
++      csdb
++ #endif
++      .endm
++ 
        .macro  uaccess_disable, tmp, isb=1
   #ifdef CONFIG_CPU_SW_DOMAIN_PAN
        /*
   #endif
        .endm
   
  +#ifdef CONFIG_KPROBES
  +#define _ASM_NOKPROBE(entry)                         \
  +     .pushsection "_kprobe_blacklist", "aw" ;        \
  +     .balign 4 ;                                     \
  +     .long entry;                                    \
  +     .popsection
  +#else
  +#define _ASM_NOKPROBE(entry)
  +#endif
  +
   #endif /* __ASM_ASSEMBLER_H__ */
index 5451e1f05a193c002f3b30af921975a28c232833,5451e1f05a193c002f3b30af921975a28c232833,a5807b67ca8a31702345d5af47fff41aaa2cf391..c136eef8f690be60bba14f6a871dff286a5942f0
@@@@ -69,6 -69,6 -69,14 +69,14 @@@@ extern int __put_user_bad(void)
   static inline void set_fs(mm_segment_t fs)
   {
        current_thread_info()->addr_limit = fs;
++ 
++      /*
++       * Prevent a mispredicted conditional call to set_fs from forwarding
++       * the wrong address limit to access_ok under speculation.
++       */
++      dsb(nsh);
++      isb();
++ 
        modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
   }
   
   #define __inttype(x) \
        __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
   
++ /*
++  * Sanitise a uaccess pointer such that it becomes NULL if addr+size
++  * is above the current addr_limit.
++  */
++ #define uaccess_mask_range_ptr(ptr, size)                    \
++      ((__typeof__(ptr))__uaccess_mask_range_ptr(ptr, size))
++ static inline void __user *__uaccess_mask_range_ptr(const void __user *ptr,
++                                                  size_t size)
++ {
++      void __user *safe_ptr = (void __user *)ptr;
++      unsigned long tmp;
++ 
++      asm volatile(
++      "       sub     %1, %3, #1\n"
++      "       subs    %1, %1, %0\n"
++      "       addhs   %1, %1, #1\n"
++      "       subhss  %1, %1, %2\n"
++      "       movlo   %0, #0\n"
++      : "+r" (safe_ptr), "=&r" (tmp)
++      : "r" (size), "r" (current_thread_info()->addr_limit)
++      : "cc");
++ 
++      csdb();
++      return safe_ptr;
++ }
++ 
   /*
    * Single-value transfer routines.  They automatically use the right
    * size if we just have the right pointer type.  Note that the functions
@@@@ -159,7 -159,7 -193,7 +193,7 @@@@ extern int __get_user_64t_4(void *)
   #define __get_user_check(x, p)                                               \
        ({                                                              \
                unsigned long __limit = current_thread_info()->addr_limit - 1; \
  -             register const typeof(*(p)) __user *__p asm("r0") = (p);\
  +             register typeof(*(p)) __user *__p asm("r0") = (p);      \
                register __inttype(x) __r2 asm("r2");                   \
                register unsigned long __l asm("r1") = __limit;         \
                register int __e asm("r0");                             \
@@@@ -362,6 -362,6 -396,14 +396,14 @@@@ do {                                                                    
        __pu_err;                                                       \
   })
   
++ #ifdef CONFIG_CPU_SPECTRE
++ /*
++  * When mitigating Spectre variant 1.1, all accessors need to include
++  * verification of the address space.
++  */
++ #define __put_user(x, ptr) put_user(x, ptr)
++ 
++ #else
   #define __put_user(x, ptr)                                           \
   ({                                                                   \
        long __pu_err = 0;                                              \
        __pu_err;                                                       \
   })
   
-- #define __put_user_error(x, ptr, err)                                        \
-- ({                                                                   \
--      __put_user_switch((x), (ptr), (err), __put_user_nocheck);       \
--      (void) 0;                                                       \
-- })
-- 
   #define __put_user_nocheck(x, __pu_ptr, __err, __size)                       \
        do {                                                            \
                unsigned long __pu_addr = (unsigned long)__pu_ptr;      \
        : "r" (x), "i" (-EFAULT)                                \
        : "cc")
   
++ #endif /* !CONFIG_CPU_SPECTRE */
   
   #ifdef CONFIG_MMU
   extern unsigned long __must_check
diff --combined arch/arm/kernel/signal.c
index b8f766cf3a905d5c226f8caa2f0cc367b73671f6,b8f766cf3a905d5c226f8caa2f0cc367b73671f6,a8155fdf352dcc273cefbcbe325d421fad1eca7b..b908382b69ff55a4036fc03208e327df6bc3fbd0
@@@@ -77,8 -77,8 -77,6 +77,6 @@@@ static int preserve_iwmmxt_context(stru
                kframe->magic = IWMMXT_MAGIC;
                kframe->size = IWMMXT_STORAGE_SIZE;
                iwmmxt_task_copy(current_thread_info(), &kframe->storage);
-- 
--              err = __copy_to_user(frame, kframe, sizeof(*frame));
        } else {
                /*
                 * For bug-compatibility with older kernels, some space
                 * Set the magic and size appropriately so that properly
                 * written userspace can skip it reliably:
                 */
--              __put_user_error(DUMMY_MAGIC, &frame->magic, err);
--              __put_user_error(IWMMXT_STORAGE_SIZE, &frame->size, err);
++              *kframe = (struct iwmmxt_sigframe) {
++                      .magic = DUMMY_MAGIC,
++                      .size  = IWMMXT_STORAGE_SIZE,
++              };
        }
   
++      err = __copy_to_user(frame, kframe, sizeof(*kframe));
++ 
        return err;
   }
   
@@@@ -135,17 -135,17 -137,18 +137,18 @@@@ static int restore_iwmmxt_context(char 
   
   static int preserve_vfp_context(struct vfp_sigframe __user *frame)
   {
--      const unsigned long magic = VFP_MAGIC;
--      const unsigned long size = VFP_STORAGE_SIZE;
++      struct vfp_sigframe kframe;
        int err = 0;
   
--      __put_user_error(magic, &frame->magic, err);
--      __put_user_error(size, &frame->size, err);
++      memset(&kframe, 0, sizeof(kframe));
++      kframe.magic = VFP_MAGIC;
++      kframe.size = VFP_STORAGE_SIZE;
   
++      err = vfp_preserve_user_clear_hwstate(&kframe.ufp, &kframe.ufp_exc);
        if (err)
--              return -EFAULT;
++              return err;
   
--      return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc);
++      return __copy_to_user(frame, &kframe, sizeof(kframe));
   }
   
   static int restore_vfp_context(char __user **auxp)
@@@@ -288,30 -288,30 -291,35 +291,35 @@@@ static in
   setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
   {
        struct aux_sigframe __user *aux;
++      struct sigcontext context;
        int err = 0;
   
--      __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
--      __put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
--      __put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
--      __put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
--      __put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
--      __put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
--      __put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
--      __put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
--      __put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
--      __put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
--      __put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
--      __put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
--      __put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
--      __put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
--      __put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
--      __put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
--      __put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
-- 
--      __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err);
--      __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err);
--      __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err);
--      __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
++      context = (struct sigcontext) {
++              .arm_r0        = regs->ARM_r0,
++              .arm_r1        = regs->ARM_r1,
++              .arm_r2        = regs->ARM_r2,
++              .arm_r3        = regs->ARM_r3,
++              .arm_r4        = regs->ARM_r4,
++              .arm_r5        = regs->ARM_r5,
++              .arm_r6        = regs->ARM_r6,
++              .arm_r7        = regs->ARM_r7,
++              .arm_r8        = regs->ARM_r8,
++              .arm_r9        = regs->ARM_r9,
++              .arm_r10       = regs->ARM_r10,
++              .arm_fp        = regs->ARM_fp,
++              .arm_ip        = regs->ARM_ip,
++              .arm_sp        = regs->ARM_sp,
++              .arm_lr        = regs->ARM_lr,
++              .arm_pc        = regs->ARM_pc,
++              .arm_cpsr      = regs->ARM_cpsr,
++ 
++              .trap_no       = current->thread.trap_no,
++              .error_code    = current->thread.error_code,
++              .fault_address = current->thread.address,
++              .oldmask       = set->sig[0],
++      };
++ 
++      err |= __copy_to_user(&sf->uc.uc_mcontext, &context, sizeof(context));
   
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
   
        if (err == 0)
                err |= preserve_vfp_context(&aux->vfp);
   #endif
--      __put_user_error(0, &aux->end_magic, err);
++      err |= __put_user(0, &aux->end_magic);
   
        return err;
   }
@@@@ -491,7 -491,7 -499,7 +499,7 @@@@ setup_frame(struct ksignal *ksig, sigse
        /*
         * Set uc.uc_flags to a value which sc.trap_no would never have.
         */
--      __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err);
++      err = __put_user(0x5ac3c35a, &frame->uc.uc_flags);
   
        err |= setup_sigframe(frame, regs, set);
        if (err == 0)
@@@@ -511,8 -511,8 -519,8 +519,8 @@@@ setup_rt_frame(struct ksignal *ksig, si
   
        err |= copy_siginfo_to_user(&frame->info, &ksig->info);
   
--      __put_user_error(0, &frame->sig.uc.uc_flags, err);
--      __put_user_error(NULL, &frame->sig.uc.uc_link, err);
++      err |= __put_user(0, &frame->sig.uc.uc_flags);
++      err |= __put_user(NULL, &frame->sig.uc.uc_link);
   
        err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp);
        err |= setup_sigframe(&frame->sig, regs, set);
@@@@ -540,12 -540,12 -548,6 +548,12 @@@@ static void handle_signal(struct ksigna
        sigset_t *oldset = sigmask_to_save();
        int ret;
   
  +     /*
  +      * Increment event counter and perform fixup for the pre-signal
  +      * frame.
  +      */
  +     rseq_signal_deliver(ksig, regs);
  +
        /*
         * Set up the stack frame
         */
@@@@ -666,7 -666,7 -668,6 +674,7 @@@@ do_work_pending(struct pt_regs *regs, u
                        } else {
                                clear_thread_flag(TIF_NOTIFY_RESUME);
                                tracehook_notify_resume(regs);
  +                             rseq_handle_notify_resume(NULL, regs);
                        }
                }
                local_irq_disable();
@@@@ -710,10 -710,10 -711,3 +718,10 @@@@ asmlinkage void addr_limit_check_failed
   {
        addr_limit_user_check();
   }
  +
  +#ifdef CONFIG_DEBUG_RSEQ
  +asmlinkage void do_rseq_syscall(struct pt_regs *regs)
  +{
  +     rseq_syscall(regs);
  +}
  +#endif
index f0dd4b6ebb6330e5007e883d2ba2d099a4e1df94,f0dd4b6ebb6330e5007e883d2ba2d099a4e1df94,a87684532327b2959899cf618cd7d72ca480d790..40da0872170fca836d734b12257c63906d1e6b8f
@@@@ -277,6 -277,6 -277,7 +277,7 @@@@ asmlinkage long sys_oabi_epoll_wait(in
                                    int maxevents, int timeout)
   {
        struct epoll_event *kbuf;
++      struct oabi_epoll_event e;
        mm_segment_t fs;
        long ret, err, i;
   
                return -EINVAL;
        if (!access_ok(VERIFY_WRITE, events, sizeof(*events) * maxevents))
                return -EFAULT;
  -     kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL);
  +     kbuf = kmalloc_array(maxevents, sizeof(*kbuf), GFP_KERNEL);
        if (!kbuf)
                return -ENOMEM;
        fs = get_fs();
        set_fs(fs);
        err = 0;
        for (i = 0; i < ret; i++) {
--              __put_user_error(kbuf[i].events, &events->events, err);
--              __put_user_error(kbuf[i].data,   &events->data,   err);
++              e.events = kbuf[i].events;
++              e.data = kbuf[i].data;
++              err = __copy_to_user(events, &e, sizeof(e));
++              if (err)
++                      break;
                events++;
        }
        kfree(kbuf);
@@@@ -324,7 -324,7 -328,7 +328,7 @@@@ asmlinkage long sys_oabi_semtimedop(in
                return -EINVAL;
        if (!access_ok(VERIFY_READ, tsops, sizeof(*tsops) * nsops))
                return -EFAULT;
  -     sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL);
  +     sops = kmalloc_array(nsops, sizeof(*sops), GFP_KERNEL);
        if (!sops)
                return -ENOMEM;
        err = 0;
diff --combined arch/arm/vfp/vfpmodule.c
index dc7e6b50ef674839a21480c69e12bec144d19194,dc7e6b50ef674839a21480c69e12bec144d19194,3b75f1d8a491abb9e27b0c60e6b75cf2a3d30434..2b287d0d6bc2d82d36d83041bd2f4fb465f81351
@@@@ -218,7 -218,7 -218,8 +218,7 @@@@ static void vfp_raise_sigfpe(unsigned i
   {
        siginfo_t info;
   
  -     memset(&info, 0, sizeof(info));
  -
  +     clear_siginfo(&info);
        info.si_signo = SIGFPE;
        info.si_code = sicode;
        info.si_addr = (void __user *)(instruction_pointer(regs) - 4);
@@@@ -256,7 -256,7 -257,7 +256,7 @@@@ static void vfp_raise_exceptions(u32 ex
   
        if (exceptions == VFP_EXCEPTION_ERROR) {
                vfp_panic("unhandled bounce", inst);
  -             vfp_raise_sigfpe(FPE_FIXME, regs);
  +             vfp_raise_sigfpe(FPE_FLTINV, regs);
                return;
        }
   
@@@@ -553,12 -553,12 -554,11 +553,11 @@@@ void vfp_flush_hwstate(struct thread_in
    * Save the current VFP state into the provided structures and prepare
    * for entry into a new function (signal handler).
    */
-- int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
--                                  struct user_vfp_exc __user *ufp_exc)
++ int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp,
++                                  struct user_vfp_exc *ufp_exc)
   {
        struct thread_info *thread = current_thread_info();
        struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
--      int err = 0;
   
        /* Ensure that the saved hwstate is up-to-date. */
        vfp_sync_hwstate(thread);
         * Copy the floating point registers. There can be unused
         * registers see asm/hwcap.h for details.
         */
--      err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs,
--                            sizeof(hwstate->fpregs));
++      memcpy(&ufp->fpregs, &hwstate->fpregs, sizeof(hwstate->fpregs));
++ 
        /*
         * Copy the status and control register.
         */
--      __put_user_error(hwstate->fpscr, &ufp->fpscr, err);
++      ufp->fpscr = hwstate->fpscr;
   
        /*
         * Copy the exception registers.
         */
--      __put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err);
--      __put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
--      __put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);
-- 
--      if (err)
--              return -EFAULT;
++      ufp_exc->fpexc = hwstate->fpexc;
++      ufp_exc->fpinst = hwstate->fpinst;
++      ufp_exc->fpinst2 = ufp_exc->fpinst2;
   
        /* Ensure that VFP is disabled. */
        vfp_flush_hwstate(thread);