]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
x86/fpu: Reset state for all signal restore failures
authorThomas Gleixner <tglx@linutronix.de>
Wed, 9 Jun 2021 19:18:00 +0000 (21:18 +0200)
committerSasha Levin <sashal@kernel.org>
Wed, 30 Jun 2021 12:48:28 +0000 (08:48 -0400)
commit efa165504943f2128d50f63de0c02faf6dcceb0d upstream.

If access_ok() or fpregs_soft_set() fails in __fpu__restore_sig() then the
function just returns but does not clear the FPU state as it does for all
other fatal failures.

Clear the FPU state for these failures as well.

Fixes: 72a671ced66d ("x86, fpu: Unify signal handling code paths for x86 and x86_64 kernels")
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/87mtryyhhz.ffs@nanos.tec.linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kernel/fpu/signal.c

index d99a8ee9e185e00be294bace7596bddd1dcc02d1..86a231338bbfe571fc938b2ecddd02b1cbfb9c4b 100644 (file)
@@ -272,6 +272,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
        int state_size = fpu_kernel_xstate_size;
        u64 xfeatures = 0;
        int fx_only = 0;
+       int ret = 0;
 
        ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
                         IS_ENABLED(CONFIG_IA32_EMULATION));
@@ -281,15 +282,21 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
                return 0;
        }
 
-       if (!access_ok(VERIFY_READ, buf, size))
-               return -EACCES;
+       if (!access_ok(VERIFY_READ, buf, size)) {
+               ret = -EACCES;
+               goto out_err;
+       }
 
        fpu__initialize(fpu);
 
-       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) != 0;
+               if (ret)
+                       goto out_err;
+               return 0;
+       }
 
        if (use_xsave()) {
                struct _fpx_sw_bytes fx_sw_user;
@@ -349,6 +356,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
                fpu__restore(fpu);
                local_bh_enable();
 
+               /* Failure is already handled */
                return err;
        } else {
                /*
@@ -356,13 +364,14 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
                 * state to the registers directly (with exceptions handled).
                 */
                user_fpu_begin();
-               if (copy_user_to_fpregs_zeroing(buf_fx, xfeatures, fx_only)) {
-                       fpu__clear(fpu);
-                       return -1;
-               }
+               if (!copy_user_to_fpregs_zeroing(buf_fx, xfeatures, fx_only))
+                       return 0;
+               ret = -1;
        }
 
-       return 0;
+out_err:
+       fpu__clear(fpu);
+       return ret;
 }
 
 static inline int xstate_sigframe_size(void)