From: Andreas Larsson <[email protected]>

Flush all uncommitted user windows before calling the generic syscall
handlers for clone, fork, and vfork.

Prior to entering the arch common handlers sparc_{clone|fork|vfork}, the
arch-specific syscall wrappers for these syscalls will attempt to flush
all windows (including user windows).

In the window overflow trap handlers on both SPARC{32|64},
if the window can't be stored (i.e due to MMU related faults) the routine
backups the user window and increments a thread counter (wsaved).

By adding a synchronization point after the flush attempt, when fault
handling is enabled, any uncommitted user windows will be flushed.

Link: https://sourceware.org/bugzilla/show_bug.cgi?id=31394
Closes: 
https://lore.kernel.org/sparclinux/fe5cc47167430007560501aabb28ba154985b661.ca...@physik.fu-berlin.de/
Signed-off-by: Andreas Larsson <[email protected]>
Signed-off-by: Ludwig Rydberg <[email protected]>
---
 arch/sparc/kernel/process.c | 38 +++++++++++++++++++++++--------------
 1 file changed, 24 insertions(+), 14 deletions(-)

diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 0442ab00518d..7d69877511fa 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -17,14 +17,18 @@
 
 asmlinkage long sparc_fork(struct pt_regs *regs)
 {
-       unsigned long orig_i1 = regs->u_regs[UREG_I1];
+       unsigned long orig_i1;
        long ret;
        struct kernel_clone_args args = {
                .exit_signal    = SIGCHLD,
-               /* Reuse the parent's stack for the child. */
-               .stack          = regs->u_regs[UREG_FP],
        };
 
+       synchronize_user_stack();
+
+       orig_i1 = regs->u_regs[UREG_I1];
+       /* Reuse the parent's stack for the child. */
+       args.stack = regs->u_regs[UREG_FP];
+
        ret = kernel_clone(&args);
 
        /* If we get an error and potentially restart the system
@@ -40,16 +44,19 @@ asmlinkage long sparc_fork(struct pt_regs *regs)
 
 asmlinkage long sparc_vfork(struct pt_regs *regs)
 {
-       unsigned long orig_i1 = regs->u_regs[UREG_I1];
+       unsigned long orig_i1;
        long ret;
-
        struct kernel_clone_args args = {
                .flags          = CLONE_VFORK | CLONE_VM,
                .exit_signal    = SIGCHLD,
-               /* Reuse the parent's stack for the child. */
-               .stack          = regs->u_regs[UREG_FP],
        };
 
+       synchronize_user_stack();
+
+       orig_i1 = regs->u_regs[UREG_I1];
+       /* Reuse the parent's stack for the child. */
+       args.stack = regs->u_regs[UREG_FP];
+
        ret = kernel_clone(&args);
 
        /* If we get an error and potentially restart the system
@@ -65,15 +72,18 @@ asmlinkage long sparc_vfork(struct pt_regs *regs)
 
 asmlinkage long sparc_clone(struct pt_regs *regs)
 {
-       unsigned long orig_i1 = regs->u_regs[UREG_I1];
-       unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
+       unsigned long orig_i1;
+       unsigned int flags;
        long ret;
+       struct kernel_clone_args args = {0};
 
-       struct kernel_clone_args args = {
-               .flags          = (flags & ~CSIGNAL),
-               .exit_signal    = (flags & CSIGNAL),
-               .tls            = regs->u_regs[UREG_I3],
-       };
+       synchronize_user_stack();
+
+       orig_i1 = regs->u_regs[UREG_I1];
+       flags = lower_32_bits(regs->u_regs[UREG_I0]);
+       args.flags              = (flags & ~CSIGNAL);
+       args.exit_signal        = (flags & CSIGNAL);
+       args.tls                = regs->u_regs[UREG_I3];
 
 #ifdef CONFIG_COMPAT
        if (test_thread_flag(TIF_32BIT)) {
-- 
2.35.3


Reply via email to