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)
arch/arm/include/asm/assembler.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/uaccess.h
arch/arm/kernel/signal.c
arch/arm/kernel/sys_oabi-compat.c
arch/arm/lib/copy_from_user.S
arch/arm/lib/copy_to_user.S
arch/arm/lib/uaccess_with_memcpy.c
arch/arm/mm/ioremap.c
arch/arm/tools/syscall.tbl
arch/arm/vfp/vfpmodule.c

index b17ee03d280b6ff9ff706f04ab4d3be57f20bfe8..88286dd483ff901bd1d215fb5450db32add47bd2 100644 (file)
@@ -467,6 +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
        /*
index 9b37b6ab27fe052eb8225c811688700c6ae99bb3..8f55dc520a3e5512cd1474f4a5c3c2d7e72698e8 100644 (file)
@@ -121,8 +121,8 @@ extern void vfp_flush_hwstate(struct thread_info *);
 struct user_vfp;
 struct user_vfp_exc;
 
-extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *,
-                                          struct user_vfp_exc __user *);
+extern int vfp_preserve_user_clear_hwstate(struct user_vfp *,
+                                          struct user_vfp_exc *);
 extern int vfp_restore_user_hwstate(struct user_vfp *,
                                    struct user_vfp_exc *);
 #endif
index 5451e1f05a193c002f3b30af921975a28c232833..c136eef8f690be60bba14f6a871dff286a5942f0 100644 (file)
@@ -69,6 +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);
 }
 
@@ -91,6 +99,32 @@ static inline void set_fs(mm_segment_t fs)
 #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
@@ -362,6 +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;                                              \
@@ -369,12 +411,6 @@ do {                                                                       \
        __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;      \
@@ -454,6 +490,7 @@ do {                                                                        \
        : "r" (x), "i" (-EFAULT)                                \
        : "cc")
 
+#endif /* !CONFIG_CPU_SPECTRE */
 
 #ifdef CONFIG_MMU
 extern unsigned long __must_check
index b8f766cf3a905d5c226f8caa2f0cc367b73671f6..b908382b69ff55a4036fc03208e327df6bc3fbd0 100644 (file)
@@ -77,8 +77,6 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe __user *frame)
                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
@@ -86,10 +84,14 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe __user *frame)
                 * 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 +137,18 @@ static int restore_iwmmxt_context(char __user **auxp)
 
 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 +291,35 @@ static int
 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));
 
@@ -328,7 +336,7 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *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 +499,7 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
        /*
         * 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 +519,8 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
 
        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);
index f0dd4b6ebb6330e5007e883d2ba2d099a4e1df94..40da0872170fca836d734b12257c63906d1e6b8f 100644 (file)
@@ -277,6 +277,7 @@ asmlinkage long sys_oabi_epoll_wait(int epfd,
                                    int maxevents, int timeout)
 {
        struct epoll_event *kbuf;
+       struct oabi_epoll_event e;
        mm_segment_t fs;
        long ret, err, i;
 
@@ -295,8 +296,11 @@ asmlinkage long sys_oabi_epoll_wait(int epfd,
        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);
index a826df3d3814bfef44d6e6f71b38c8131d9fe25b..6709a8d33963b679b0a0f6ec683e3291a7f07a71 100644 (file)
@@ -93,11 +93,7 @@ ENTRY(arm_copy_from_user)
 #ifdef CONFIG_CPU_SPECTRE
        get_thread_info r3
        ldr     r3, [r3, #TI_ADDR_LIMIT]
-       adds    ip, r1, r2      @ ip=addr+size
-       sub     r3, r3, #1      @ addr_limit - 1
-       cmpcc   ip, r3          @ if (addr+size > addr_limit - 1)
-       movcs   r1, #0          @ addr = NULL
-       csdb
+       uaccess_mask_range_ptr r1, r2, r3, ip
 #endif
 
 #include "copy_template.S"
index caf5019d8161e2f1914a797a4c6800844a27d570..970abe521197fa1881473c2f7b1423bcea77227c 100644 (file)
 
 ENTRY(__copy_to_user_std)
 WEAK(arm_copy_to_user)
+#ifdef CONFIG_CPU_SPECTRE
+       get_thread_info r3
+       ldr     r3, [r3, #TI_ADDR_LIMIT]
+       uaccess_mask_range_ptr r0, r2, r3, ip
+#endif
 
 #include "copy_template.S"
 
@@ -108,4 +113,3 @@ ENDPROC(__copy_to_user_std)
        rsb     r0, r0, r2
        copy_abort_end
        .popsection
-
index 9b4ed172861615fa94f628fb3eea067176ef3bae..73dc7360cbdd58c76e7e230417e83d902d3a2a3b 100644 (file)
@@ -152,7 +152,8 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n)
                n = __copy_to_user_std(to, from, n);
                uaccess_restore(ua_flags);
        } else {
-               n = __copy_to_user_memcpy(to, from, n);
+               n = __copy_to_user_memcpy(uaccess_mask_range_ptr(to, n),
+                                         from, n);
        }
        return n;
 }
index fc91205ff46cebd2218940214c12e6ab84355b21..5bf9443cfbaa63108f8bc11f4356774591e3e29c 100644 (file)
@@ -473,7 +473,7 @@ void pci_ioremap_set_mem_type(int mem_type)
 
 int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
 {
-       BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT);
+       BUG_ON(offset + SZ_64K - 1 > IO_SPACE_LIMIT);
 
        return ioremap_page_range(PCI_IO_VIRT_BASE + offset,
                                  PCI_IO_VIRT_BASE + offset + SZ_64K,
index fbc74b5fa3ed26a4bc56657afb3691372aea431e..8edf93b4490fad24e4ef0c4195b6a535b4a87a94 100644 (file)
 396    common  pkey_free               sys_pkey_free
 397    common  statx                   sys_statx
 398    common  rseq                    sys_rseq
+399    common  io_pgetevents           sys_io_pgetevents
index dc7e6b50ef674839a21480c69e12bec144d19194..2b287d0d6bc2d82d36d83041bd2f4fb465f81351 100644 (file)
@@ -553,12 +553,11 @@ void vfp_flush_hwstate(struct thread_info *thread)
  * 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);
@@ -567,22 +566,19 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
         * 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);