Skip to content

Commit e38eba3

Browse files
sparc: Synchronize user stack on fork and clone
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>
1 parent dc2f4d4 commit e38eba3

1 file changed

Lines changed: 24 additions & 14 deletions

File tree

arch/sparc/kernel/process.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,18 @@
1717

1818
asmlinkage long sparc_fork(struct pt_regs *regs)
1919
{
20-
unsigned long orig_i1 = regs->u_regs[UREG_I1];
20+
unsigned long orig_i1;
2121
long ret;
2222
struct kernel_clone_args args = {
2323
.exit_signal = SIGCHLD,
24-
/* Reuse the parent's stack for the child. */
25-
.stack = regs->u_regs[UREG_FP],
2624
};
2725

26+
synchronize_user_stack();
27+
28+
orig_i1 = regs->u_regs[UREG_I1];
29+
/* Reuse the parent's stack for the child. */
30+
args.stack = regs->u_regs[UREG_FP];
31+
2832
ret = kernel_clone(&args);
2933

3034
/* If we get an error and potentially restart the system
@@ -40,16 +44,19 @@ asmlinkage long sparc_fork(struct pt_regs *regs)
4044

4145
asmlinkage long sparc_vfork(struct pt_regs *regs)
4246
{
43-
unsigned long orig_i1 = regs->u_regs[UREG_I1];
47+
unsigned long orig_i1;
4448
long ret;
45-
4649
struct kernel_clone_args args = {
4750
.flags = CLONE_VFORK | CLONE_VM,
4851
.exit_signal = SIGCHLD,
49-
/* Reuse the parent's stack for the child. */
50-
.stack = regs->u_regs[UREG_FP],
5152
};
5253

54+
synchronize_user_stack();
55+
56+
orig_i1 = regs->u_regs[UREG_I1];
57+
/* Reuse the parent's stack for the child. */
58+
args.stack = regs->u_regs[UREG_FP];
59+
5360
ret = kernel_clone(&args);
5461

5562
/* If we get an error and potentially restart the system
@@ -65,15 +72,18 @@ asmlinkage long sparc_vfork(struct pt_regs *regs)
6572

6673
asmlinkage long sparc_clone(struct pt_regs *regs)
6774
{
68-
unsigned long orig_i1 = regs->u_regs[UREG_I1];
69-
unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
75+
unsigned long orig_i1;
76+
unsigned int flags;
7077
long ret;
78+
struct kernel_clone_args args = {0};
7179

72-
struct kernel_clone_args args = {
73-
.flags = (flags & ~CSIGNAL),
74-
.exit_signal = (flags & CSIGNAL),
75-
.tls = regs->u_regs[UREG_I3],
76-
};
80+
synchronize_user_stack();
81+
82+
orig_i1 = regs->u_regs[UREG_I1];
83+
flags = lower_32_bits(regs->u_regs[UREG_I0]);
84+
args.flags = (flags & ~CSIGNAL);
85+
args.exit_signal = (flags & CSIGNAL);
86+
args.tls = regs->u_regs[UREG_I3];
7787

7888
#ifdef CONFIG_COMPAT
7989
if (test_thread_flag(TIF_32BIT)) {

0 commit comments

Comments
 (0)