Merge x86/urgent into x86/fpu
authorBorislav Petkov <bp@suse.de>
Wed, 23 Jun 2021 15:42:12 +0000 (17:42 +0200)
committerBorislav Petkov <bp@suse.de>
Wed, 23 Jun 2021 15:43:38 +0000 (17:43 +0200)
Pick up dependent changes which either went mainline (x86/urgent is
based on -rc7 and that contains them) as urgent fixes and the current
x86/urgent branch which contains two more urgent fixes, so that the
bigger FPU rework can base off ontop.

Signed-off-by: Borislav Petkov <bp@suse.de>
1  2 
arch/x86/kernel/fpu/signal.c
arch/x86/kernel/fpu/xstate.c
include/linux/sched/signal.h

@@@ -221,28 -221,18 +221,18 @@@ sanitize_restored_user_xstate(union fpr
  
        if (use_xsave()) {
                /*
-                * Note: we don't need to zero the reserved bits in the
-                * xstate_header here because we either didn't copy them at all,
-                * or we checked earlier that they aren't set.
+                * Clear all feature bits which are not set in
+                * user_xfeatures and clear all extended features
+                * for fx_only mode.
                 */
+               u64 mask = fx_only ? XFEATURE_MASK_FPSSE : user_xfeatures;
  
                /*
-                * 'user_xfeatures' might have bits clear which are
-                * set in header->xfeatures. This represents features that
-                * were in init state prior to a signal delivery, and need
-                * to be reset back to the init state.  Clear any user
-                * feature bits which are set in the kernel buffer to get
-                * them back to the init state.
-                *
-                * Supervisor state is unchanged by input from userspace.
-                * Ensure supervisor state bits stay set and supervisor
-                * state is not modified.
+                * Supervisor state has to be preserved. The sigframe
+                * restore can only modify user features, i.e. @mask
+                * cannot contain them.
                 */
-               if (fx_only)
-                       header->xfeatures = XFEATURE_MASK_FPSSE;
-               else
-                       header->xfeatures &= user_xfeatures |
-                                            xfeatures_mask_supervisor();
+               header->xfeatures &= mask | xfeatures_mask_supervisor();
        }
  
        if (use_fxsr()) {
@@@ -307,13 -297,17 +297,17 @@@ static int __fpu__restore_sig(void __us
                return 0;
        }
  
-       if (!access_ok(buf, size))
-               return -EACCES;
+       if (!access_ok(buf, size)) {
+               ret = -EACCES;
+               goto out;
+       }
  
-       if (!static_cpu_has(X86_FEATURE_FPU))
-               return fpregs_soft_set(current, NULL,
-                                      0, sizeof(struct user_i387_ia32_struct),
-                                      NULL, buf) != 0;
+       if (!static_cpu_has(X86_FEATURE_FPU)) {
+               ret = fpregs_soft_set(current, NULL, 0,
+                                     sizeof(struct user_i387_ia32_struct),
+                                     NULL, buf);
+               goto out;
+       }
  
        if (use_xsave()) {
                struct _fpx_sw_bytes fx_sw_user;
                        fpregs_unlock();
                        return 0;
                }
+               /*
+                * The above did an FPU restore operation, restricted to
+                * the user portion of the registers, and failed, but the
+                * microcode might have modified the FPU registers
+                * nevertheless.
+                *
+                * If the FPU registers do not belong to current, then
+                * invalidate the FPU register state otherwise the task might
+                * preempt current and return to user space with corrupted
+                * FPU registers.
+                *
+                * In case current owns the FPU registers then no further
+                * action is required. The fixup below will handle it
+                * correctly.
+                */
+               if (test_thread_flag(TIF_NEED_FPU_LOAD))
+                       __cpu_invalidate_fpregs_state();
                fpregs_unlock();
        } else {
                /*
                 */
                ret = __copy_from_user(&env, buf, sizeof(env));
                if (ret)
-                       goto err_out;
+                       goto out;
                envp = &env;
        }
  
        if (use_xsave() && !fx_only) {
                u64 init_bv = xfeatures_mask_user() & ~user_xfeatures;
  
-               if (using_compacted_format()) {
-                       ret = copy_user_to_xstate(&fpu->state.xsave, buf_fx);
-               } else {
-                       ret = __copy_from_user(&fpu->state.xsave, buf_fx, state_size);
-                       if (!ret && state_size > offsetof(struct xregs_state, header))
-                               ret = validate_user_xstate_header(&fpu->state.xsave.header);
-               }
+               ret = copy_user_to_xstate(&fpu->state.xsave, buf_fx);
                if (ret)
-                       goto err_out;
+                       goto out;
  
                sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures,
                                              fx_only);
                ret = __copy_from_user(&fpu->state.fxsave, buf_fx, state_size);
                if (ret) {
                        ret = -EFAULT;
-                       goto err_out;
+                       goto out;
                }
  
                sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures,
        } else {
                ret = __copy_from_user(&fpu->state.fsave, buf_fx, state_size);
                if (ret)
-                       goto err_out;
+                       goto out;
  
                fpregs_lock();
                ret = copy_kernel_to_fregs_err(&fpu->state.fsave);
                fpregs_deactivate(fpu);
        fpregs_unlock();
  
err_out:
+ out:
        if (ret)
                fpu__clear_user_states(fpu);
        return ret;
@@@ -507,25 -513,6 +513,25 @@@ fpu__alloc_mathframe(unsigned long sp, 
  
        return sp;
  }
 +
 +unsigned long fpu__get_fpstate_size(void)
 +{
 +      unsigned long ret = xstate_sigframe_size();
 +
 +      /*
 +       * This space is needed on (most) 32-bit kernels, or when a 32-bit
 +       * app is running on a 64-bit kernel. To keep things simple, just
 +       * assume the worst case and always include space for 'freg_state',
 +       * even for 64-bit apps on 64-bit kernels. This wastes a bit of
 +       * space, but keeps the code simple.
 +       */
 +      if ((IS_ENABLED(CONFIG_IA32_EMULATION) ||
 +           IS_ENABLED(CONFIG_X86_32)) && use_fxsr())
 +              ret += sizeof(struct fregs_state);
 +
 +      return ret;
 +}
 +
  /*
   * Prepare the SW reserved portion of the fxsave memory layout, indicating
   * the presence of the extended state information in the memory layout
@@@ -440,6 -440,25 +440,25 @@@ static void __init print_xstate_offset_
        }
  }
  
+ /*
+  * All supported features have either init state all zeros or are
+  * handled in setup_init_fpu() individually. This is an explicit
+  * feature list and does not use XFEATURE_MASK*SUPPORTED to catch
+  * newly added supported features at build time and make people
+  * actually look at the init state for the new feature.
+  */
+ #define XFEATURES_INIT_FPSTATE_HANDLED                \
+       (XFEATURE_MASK_FP |                     \
+        XFEATURE_MASK_SSE |                    \
+        XFEATURE_MASK_YMM |                    \
+        XFEATURE_MASK_OPMASK |                 \
+        XFEATURE_MASK_ZMM_Hi256 |              \
+        XFEATURE_MASK_Hi16_ZMM  |              \
+        XFEATURE_MASK_PKRU |                   \
+        XFEATURE_MASK_BNDREGS |                \
+        XFEATURE_MASK_BNDCSR |                 \
+        XFEATURE_MASK_PASID)
  /*
   * setup the xstate image representing the init state
   */
@@@ -447,6 -466,10 +466,10 @@@ static void __init setup_init_fpu_buf(v
  {
        static int on_boot_cpu __initdata = 1;
  
+       BUILD_BUG_ON((XFEATURE_MASK_USER_SUPPORTED |
+                     XFEATURE_MASK_SUPERVISOR_SUPPORTED) !=
+                    XFEATURES_INIT_FPSTATE_HANDLED);
        WARN_ON_FPU(!on_boot_cpu);
        on_boot_cpu = 0;
  
        copy_kernel_to_xregs_booting(&init_fpstate.xsave);
  
        /*
-        * Dump the init state again. This is to identify the init state
-        * of any feature which is not represented by all zero's.
+        * All components are now in init state. Read the state back so
+        * that init_fpstate contains all non-zero init state. This only
+        * works with XSAVE, but not with XSAVEOPT and XSAVES because
+        * those use the init optimization which skips writing data for
+        * components in init state.
+        *
+        * XSAVE could be used, but that would require to reshuffle the
+        * data when XSAVES is available because XSAVES uses xstate
+        * compaction. But doing so is a pointless exercise because most
+        * components have an all zeros init state except for the legacy
+        * ones (FP and SSE). Those can be saved with FXSAVE into the
+        * legacy area. Adding new features requires to ensure that init
+        * state is all zeroes or if not to add the necessary handling
+        * here.
         */
-       copy_xregs_to_kernel_booting(&init_fpstate.xsave);
+       fxsave(&init_fpstate.fxsave);
  }
  
  static int xfeature_uncompacted_offset(int xfeature_nr)
@@@ -1190,7 -1225,7 +1225,7 @@@ int copy_user_to_xstate(struct xregs_st
        offset = offsetof(struct xregs_state, header);
        size = sizeof(hdr);
  
 -      if (__copy_from_user(&hdr, ubuf + offset, size))
 +      if (copy_from_user(&hdr, ubuf + offset, size))
                return -EFAULT;
  
        if (validate_user_xstate_header(&hdr))
                        offset = xstate_offsets[i];
                        size = xstate_sizes[i];
  
 -                      if (__copy_from_user(dst, ubuf + offset, size))
 +                      if (copy_from_user(dst, ubuf + offset, size))
                                return -EFAULT;
                }
        }
        if (xfeatures_mxcsr_quirk(hdr.xfeatures)) {
                offset = offsetof(struct fxregs_state, mxcsr);
                size = MXCSR_AND_FLAGS_SIZE;
 -              if (__copy_from_user(&xsave->i387.mxcsr, ubuf + offset, size))
 +              if (copy_from_user(&xsave->i387.mxcsr, ubuf + offset, size))
                        return -EFAULT;
        }
  
@@@ -1402,60 -1437,3 +1437,3 @@@ int proc_pid_arch_status(struct seq_fil
        return 0;
  }
  #endif /* CONFIG_PROC_PID_ARCH_STATUS */
- #ifdef CONFIG_IOMMU_SUPPORT
- void update_pasid(void)
- {
-       u64 pasid_state;
-       u32 pasid;
-       if (!cpu_feature_enabled(X86_FEATURE_ENQCMD))
-               return;
-       if (!current->mm)
-               return;
-       pasid = READ_ONCE(current->mm->pasid);
-       /* Set the valid bit in the PASID MSR/state only for valid pasid. */
-       pasid_state = pasid == PASID_DISABLED ?
-                     pasid : pasid | MSR_IA32_PASID_VALID;
-       /*
-        * No need to hold fregs_lock() since the task's fpstate won't
-        * be changed by others (e.g. ptrace) while the task is being
-        * switched to or is in IPI.
-        */
-       if (!test_thread_flag(TIF_NEED_FPU_LOAD)) {
-               /* The MSR is active and can be directly updated. */
-               wrmsrl(MSR_IA32_PASID, pasid_state);
-       } else {
-               struct fpu *fpu = &current->thread.fpu;
-               struct ia32_pasid_state *ppasid_state;
-               struct xregs_state *xsave;
-               /*
-                * The CPU's xstate registers are not currently active. Just
-                * update the PASID state in the memory buffer here. The
-                * PASID MSR will be loaded when returning to user mode.
-                */
-               xsave = &fpu->state.xsave;
-               xsave->header.xfeatures |= XFEATURE_MASK_PASID;
-               ppasid_state = get_xsave_addr(xsave, XFEATURE_PASID);
-               /*
-                * Since XFEATURE_MASK_PASID is set in xfeatures, ppasid_state
-                * won't be NULL and no need to check its value.
-                *
-                * Only update the task's PASID state when it's different
-                * from the mm's pasid.
-                */
-               if (ppasid_state->pasid != pasid_state) {
-                       /*
-                        * Invalid fpregs so that state restoring will pick up
-                        * the PASID state.
-                        */
-                       __fpu_invalidate_fpregs_state(fpu);
-                       ppasid_state->pasid = pasid_state;
-               }
-       }
- }
- #endif /* CONFIG_IOMMU_SUPPORT */
@@@ -326,6 -326,7 +326,7 @@@ int send_sig_mceerr(int code, void __us
  
  int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper);
  int force_sig_pkuerr(void __user *addr, u32 pkey);
+ int force_sig_perf(void __user *addr, u32 type, u64 sig_data);
  
  int force_sig_ptrace_errno_trap(int errno, void __user *addr);
  
@@@ -537,17 -538,6 +538,17 @@@ static inline int kill_cad_pid(int sig
  #define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0)
  #define SEND_SIG_PRIV ((struct kernel_siginfo *) 1)
  
 +static inline int __on_sig_stack(unsigned long sp)
 +{
 +#ifdef CONFIG_STACK_GROWSUP
 +      return sp >= current->sas_ss_sp &&
 +              sp - current->sas_ss_sp < current->sas_ss_size;
 +#else
 +      return sp > current->sas_ss_sp &&
 +              sp - current->sas_ss_sp <= current->sas_ss_size;
 +#endif
 +}
 +
  /*
   * True if we are on the alternate signal stack.
   */
@@@ -565,7 -555,13 +566,7 @@@ static inline int on_sig_stack(unsigne
        if (current->sas_ss_flags & SS_AUTODISARM)
                return 0;
  
 -#ifdef CONFIG_STACK_GROWSUP
 -      return sp >= current->sas_ss_sp &&
 -              sp - current->sas_ss_sp < current->sas_ss_size;
 -#else
 -      return sp > current->sas_ss_sp &&
 -              sp - current->sas_ss_sp <= current->sas_ss_size;
 -#endif
 +      return __on_sig_stack(sp);
  }
  
  static inline int sas_ss_flags(unsigned long sp)