]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
sparc: Synchronize user stack on fork and clone
authorAndreas Larsson <andreas@gaisler.com>
Mon, 19 Jan 2026 14:47:52 +0000 (15:47 +0100)
committerAndreas Larsson <andreas@gaisler.com>
Fri, 6 Feb 2026 14:00:47 +0000 (15:00 +0100)
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.camel@physik.fu-berlin.de/
Signed-off-by: Andreas Larsson <andreas@gaisler.com>
Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Link: https://lore.kernel.org/r/20260119144753.27945-2-ludwig.rydberg@gaisler.com
Signed-off-by: Andreas Larsson <andreas@gaisler.com>
arch/sparc/kernel/process.c

index 0442ab00518d3ce333f60e8a00dfa43fa1e5b7a1..7d69877511fac96a41b1699ebeb9eca8f4a4e120 100644 (file)
 
 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)) {