]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
x86/fpu/signal: Move xstate clearing out of copy_fpregs_to_sigframe()
authorThomas Gleixner <tglx@linutronix.de>
Wed, 8 Sep 2021 13:29:30 +0000 (15:29 +0200)
committerStefan Bader <stefan.bader@canonical.com>
Wed, 27 Apr 2022 09:55:49 +0000 (11:55 +0200)
BugLink: https://bugs.launchpad.net/bugs/1967750
When the direct saving of the FPU registers to the user space sigframe
fails, copy_fpregs_to_sigframe() attempts to clear the user buffer.

The most likely reason for such a fail is a page fault. As
copy_fpregs_to_sigframe() is invoked with pagefaults disabled the chance
that __clear_user() succeeds is minuscule.

Move the clearing out into the caller which replaces the
fault_in_pages_writeable() in that error handling path.

The return value confusion will be cleaned up separately.

Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20210908132525.679356300@linutronix.de
(cherry picked from commit fcfb7163329ce832aafef31f26345ef5e8642a17)
Acked-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
arch/x86/kernel/fpu/signal.c

index 91c1e68e5fca59528415c8761af1530298ec8fd5..d5d610ab7739230558442c1249f54448af70693d 100644 (file)
@@ -136,18 +136,12 @@ static inline int save_xstate_epilog(void __user *buf, int ia32_frame)
 
 static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
 {
-       int err;
-
        if (use_xsave())
-               err = xsave_to_user_sigframe(buf);
-       else if (use_fxsr())
-               err = fxsave_to_user_sigframe((struct fxregs_state __user *) buf);
+               return xsave_to_user_sigframe(buf);
+       if (use_fxsr())
+               return fxsave_to_user_sigframe((struct fxregs_state __user *) buf);
        else
-               err = fnsave_to_user_sigframe((struct fregs_state __user *) buf);
-
-       if (unlikely(err) && __clear_user(buf, fpu_user_xstate_size))
-               err = -EFAULT;
-       return err;
+               return fnsave_to_user_sigframe((struct fregs_state __user *) buf);
 }
 
 /*
@@ -218,9 +212,9 @@ retry:
        fpregs_unlock();
 
        if (ret) {
-               if (!fault_in_pages_writeable(buf_fx, fpu_user_xstate_size))
+               if (!__clear_user(buf_fx, fpu_user_xstate_size))
                        goto retry;
-               return -EFAULT;
+               return -1;
        }
 
        /* Save the fsave header for the 32-bit frames. */