OSDN Git Service

Merge tag 'x86_shstk_for_6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[tomoyo/tomoyo-test1.git] / arch / x86 / kernel / fpu / core.c
index 98e507c..a86d370 100644 (file)
@@ -552,8 +552,36 @@ static inline void fpu_inherit_perms(struct fpu *dst_fpu)
        }
 }
 
+/* A passed ssp of zero will not cause any update */
+static int update_fpu_shstk(struct task_struct *dst, unsigned long ssp)
+{
+#ifdef CONFIG_X86_USER_SHADOW_STACK
+       struct cet_user_state *xstate;
+
+       /* If ssp update is not needed. */
+       if (!ssp)
+               return 0;
+
+       xstate = get_xsave_addr(&dst->thread.fpu.fpstate->regs.xsave,
+                               XFEATURE_CET_USER);
+
+       /*
+        * If there is a non-zero ssp, then 'dst' must be configured with a shadow
+        * stack and the fpu state should be up to date since it was just copied
+        * from the parent in fpu_clone(). So there must be a valid non-init CET
+        * state location in the buffer.
+        */
+       if (WARN_ON_ONCE(!xstate))
+               return 1;
+
+       xstate->user_ssp = (u64)ssp;
+#endif
+       return 0;
+}
+
 /* Clone current's FPU state on fork */
-int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal)
+int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal,
+             unsigned long ssp)
 {
        struct fpu *src_fpu = &current->thread.fpu;
        struct fpu *dst_fpu = &dst->thread.fpu;
@@ -613,6 +641,12 @@ int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal)
        if (use_xsave())
                dst_fpu->fpstate->regs.xsave.header.xfeatures &= ~XFEATURE_MASK_PASID;
 
+       /*
+        * Update shadow stack pointer, in case it changed during clone.
+        */
+       if (update_fpu_shstk(dst, ssp))
+               return 1;
+
        trace_x86_fpu_copy_src(src_fpu);
        trace_x86_fpu_copy_dst(dst_fpu);
 
@@ -753,6 +787,24 @@ void switch_fpu_return(void)
 }
 EXPORT_SYMBOL_GPL(switch_fpu_return);
 
+void fpregs_lock_and_load(void)
+{
+       /*
+        * fpregs_lock() only disables preemption (mostly). So modifying state
+        * in an interrupt could screw up some in progress fpregs operation.
+        * Warn about it.
+        */
+       WARN_ON_ONCE(!irq_fpu_usable());
+       WARN_ON_ONCE(current->flags & PF_KTHREAD);
+
+       fpregs_lock();
+
+       fpregs_assert_state_consistent();
+
+       if (test_thread_flag(TIF_NEED_FPU_LOAD))
+               fpregs_restore_userregs();
+}
+
 #ifdef CONFIG_X86_DEBUG_FPU
 /*
  * If current FPU state according to its tracking (loaded FPU context on this