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