[PATCH 1/3] sparc: Synchronize user stack on fork and clone

Ludwig Rydberg posted 3 patches 3 weeks, 3 days ago
There is a newer version of this series
[PATCH 1/3] sparc: Synchronize user stack on fork and clone
Posted by Ludwig Rydberg 3 weeks, 3 days ago
From: Andreas Larsson <andreas@gaisler.com>

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>
---
 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
Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
Posted by John Paul Adrian Glaubitz 3 weeks, 2 days ago
Hi Ludwig,

On Fri, 2026-01-16 at 16:30 +0100, Ludwig Rydberg wrote:
> From: Andreas Larsson <andreas@gaisler.com>
> 
> 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>
> ---
>  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)) {

I have tested the patch with the following test program written by Michael Karcher
on a Sun Netra 240 running kernel version 6.19-rc5 by applying the patch on top:

glaubitz@raverin:~$ cat attack_on_the_clone.c
// SPARC64 clone problem demonstration
//
// the sparc64 Linux kernel fails to execute clone if %sp points into uncommitted memory (e.g. due to lazy
// stack committing). This program uses a variable length array on the stack to position the stack pointer when
// invoking the library function clone just at a page boundary. The library function clone allocates a stack frame
// that is completely in uncommitted memory before entering the kernel call clone.

// to probe for the correct size of the VLA, a test function is called first. This function records the %fp value it
// receives (which will be the %fp value in the library function clone, too, if the VLA size is equal)

// (c) Michael Karcher (kernel@mkarcher.dialup.fu-berlin.de) , 2024, GPLv2 or later

#define _GNU_SOURCE

#include <sys/mman.h>
#include <sys/wait.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define SPARC64_STACK_BIAS 0x7FF

typedef int fn_t(void*);
typedef pid_t clone_t(fn_t* entry, void* stack, int flags, void* arg, ...);


// very simple function invoked using clone
int nop(void* bar)
{
        return 0;
}


// clone substitute that records %fp
uint64_t call_clone_sp;

pid_t dummy_clone(fn_t* entry, void* stack, int flags, void* arg, ...)
{
        register uint64_t frameptr asm("fp");
        call_clone_sp = frameptr + SPARC64_STACK_BIAS;  // sp in call_clone is fp in dummy_clone / clone
        return -1;
}


// function to invoke clone with (im)properly aligned stack
void* child_stack;

int call_clone(int waste_qwords, clone_t* clonefn)
{
        void* volatile waste[waste_qwords+2];  // volatile to not optimize the array away
        waste[waste_qwords+1] = NULL;

        pid_t child_pid = clonefn(nop,
                       child_stack,
                       CLONE_VM | SIGCHLD,
                       0);
        if (child_pid > 0)
        {
                pid_t waitresult = waitpid(child_pid, NULL, 0);
                // before fork-bombing anything if this doesn't go to plan, exit
                if (waitresult != child_pid) abort();
                return 0;
        }
        else
        {
                return -1;
        }
}

int main(void)
{
        int wasteamount;
        child_stack = mmap(NULL, 16384, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
        call_clone(0, dummy_clone);
        printf("effective FP in clone() with waste 0 = %llx\n", call_clone_sp);
        wasteamount = 1024 + (call_clone_sp & 0xFFF) / 8;
        printf("this is %d 64-bit words above the page boundary at least 8K away\n", wasteamount);
        child_stack = (void*)((char*)child_stack + 16000);
        clone(NULL, NULL, 0, 0); // fails, but resolves "clone"
        // failes for wasteamount-22 to wasteamount+22 (only even values tested)
        if (call_clone(wasteamount, clone) < 0)
        {
                perror("clone");
        }
        else
        {
                puts("Congratulations, clone succeeded\n");
        }
}

glaubitz@raverin:~$ gcc -o attack_on_the_clone attack_on_the_clone.c
glaubitz@raverin:~$

Without the patch:

glaubitz@raverin:~$ uname -a
Linux raverin 6.19.0-rc5 #19 Sat Jan 17 06:32:58 UTC 2026 sparc64 GNU/Linux
glaubitz@raverin:~$ ./attack_on_the_clone 
effective FP in clone() with waste 0 = 7feffe60de0
this is 1468 64-bit words above the page boundary at least 8K away
clone: Bad address
glaubitz@raverin:~$

With the patch:

glaubitz@raverin:~$ uname -a
Linux raverin 6.19.0-rc5+ #20 Sat Jan 17 06:40:52 UTC 2026 sparc64 GNU/Linux
glaubitz@raverin:~$ ./attack_on_the_clone 
effective FP in clone() with waste 0 = 7fefffaede0
this is 1468 64-bit words above the page boundary at least 8K away
Congratulations, clone succeeded

glaubitz@raverin:~$

I can therefore confirm that this patch fixes the bug.

Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>

Thanks,
Adrian

-- 
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer
`. `'   Physicist
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913
Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
Posted by Michael Karcher 3 weeks, 2 days ago
Am 17.01.2026 um 07:57 schrieb John Paul Adrian Glaubitz:
> On Fri, 2026-01-16 at 16:30 +0100, Ludwig Rydberg wrote:
>> From: Andreas Larsson <andreas@gaisler.com>
>>
>> Flush all uncommitted user windows before calling the generic syscall
>> handlers for clone, fork, and vfork.
>>
>> [...]
>>
>> Signed-off-by: Andreas Larsson<andreas@gaisler.com>
>> Signed-off-by: Ludwig Rydberg<ludwig.rydberg@gaisler.com>
> I have tested the patch with the following test program written by Michael Karcher
> on a Sun Netra 240 running kernel version 6.19-rc5 by applying the patch on top:
>
> [...]
>
> I can therefore confirm that this patch fixes the bug.
>
> Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>

Thanks to both Andreas Larsson and Ludwig Rydberg for fixing this long-standing
issue, and thanks to Adrian Glaubitz for verifying that the fix works as intended!

It is great to see that there still are people around that improve SPARC support
in the Linux kernel. Keep up the good work.

Kind regards,
   Michael Karcher
Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
Posted by John Paul Adrian Glaubitz 3 weeks, 2 days ago
Hi,

On Sat, 2026-01-17 at 07:57 +0100, John Paul Adrian Glaubitz wrote:
> Hi Ludwig,
> 
> On Fri, 2026-01-16 at 16:30 +0100, Ludwig Rydberg wrote:
> > From: Andreas Larsson <andreas@gaisler.com>
> > 
> > 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>
> > ---
> >  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)) {
> 
> I have tested the patch with the following test program written by Michael Karcher
> on a Sun Netra 240 running kernel version 6.19-rc5 by applying the patch on top:
> 
> glaubitz@raverin:~$ cat attack_on_the_clone.c
> // SPARC64 clone problem demonstration
> //
> // the sparc64 Linux kernel fails to execute clone if %sp points into uncommitted memory (e.g. due to lazy
> // stack committing). This program uses a variable length array on the stack to position the stack pointer when
> // invoking the library function clone just at a page boundary. The library function clone allocates a stack frame
> // that is completely in uncommitted memory before entering the kernel call clone.
> 
> // to probe for the correct size of the VLA, a test function is called first. This function records the %fp value it
> // receives (which will be the %fp value in the library function clone, too, if the VLA size is equal)
> 
> // (c) Michael Karcher (kernel@mkarcher.dialup.fu-berlin.de) , 2024, GPLv2 or later
> 
> #define _GNU_SOURCE
> 
> #include <sys/mman.h>
> #include <sys/wait.h>
> #include <sched.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <stdint.h>
> 
> #define SPARC64_STACK_BIAS 0x7FF
> 
> typedef int fn_t(void*);
> typedef pid_t clone_t(fn_t* entry, void* stack, int flags, void* arg, ...);
> 
> 
> // very simple function invoked using clone
> int nop(void* bar)
> {
>         return 0;
> }
> 
> 
> // clone substitute that records %fp
> uint64_t call_clone_sp;
> 
> pid_t dummy_clone(fn_t* entry, void* stack, int flags, void* arg, ...)
> {
>         register uint64_t frameptr asm("fp");
>         call_clone_sp = frameptr + SPARC64_STACK_BIAS;  // sp in call_clone is fp in dummy_clone / clone
>         return -1;
> }
> 
> 
> // function to invoke clone with (im)properly aligned stack
> void* child_stack;
> 
> int call_clone(int waste_qwords, clone_t* clonefn)
> {
>         void* volatile waste[waste_qwords+2];  // volatile to not optimize the array away
>         waste[waste_qwords+1] = NULL;
> 
>         pid_t child_pid = clonefn(nop,
>                        child_stack,
>                        CLONE_VM | SIGCHLD,
>                        0);
>         if (child_pid > 0)
>         {
>                 pid_t waitresult = waitpid(child_pid, NULL, 0);
>                 // before fork-bombing anything if this doesn't go to plan, exit
>                 if (waitresult != child_pid) abort();
>                 return 0;
>         }
>         else
>         {
>                 return -1;
>         }
> }
> 
> int main(void)
> {
>         int wasteamount;
>         child_stack = mmap(NULL, 16384, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
>         call_clone(0, dummy_clone);
>         printf("effective FP in clone() with waste 0 = %llx\n", call_clone_sp);
>         wasteamount = 1024 + (call_clone_sp & 0xFFF) / 8;
>         printf("this is %d 64-bit words above the page boundary at least 8K away\n", wasteamount);
>         child_stack = (void*)((char*)child_stack + 16000);
>         clone(NULL, NULL, 0, 0); // fails, but resolves "clone"
>         // failes for wasteamount-22 to wasteamount+22 (only even values tested)
>         if (call_clone(wasteamount, clone) < 0)
>         {
>                 perror("clone");
>         }
>         else
>         {
>                 puts("Congratulations, clone succeeded\n");
>         }
> }
> 
> glaubitz@raverin:~$ gcc -o attack_on_the_clone attack_on_the_clone.c
> glaubitz@raverin:~$
> 
> Without the patch:
> 
> glaubitz@raverin:~$ uname -a
> Linux raverin 6.19.0-rc5 #19 Sat Jan 17 06:32:58 UTC 2026 sparc64 GNU/Linux
> glaubitz@raverin:~$ ./attack_on_the_clone 
> effective FP in clone() with waste 0 = 7feffe60de0
> this is 1468 64-bit words above the page boundary at least 8K away
> clone: Bad address
> glaubitz@raverin:~$
> 
> With the patch:
> 
> glaubitz@raverin:~$ uname -a
> Linux raverin 6.19.0-rc5+ #20 Sat Jan 17 06:40:52 UTC 2026 sparc64 GNU/Linux
> glaubitz@raverin:~$ ./attack_on_the_clone 
> effective FP in clone() with waste 0 = 7fefffaede0
> this is 1468 64-bit words above the page boundary at least 8K away
> Congratulations, clone succeeded
> 
> glaubitz@raverin:~$
> 
> I can therefore confirm that this patch fixes the bug.
> 
> Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>

Forgot to mention: I reverted the workaround in glibc [1] for testing.

Adrian

> [1] https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=234458024300f0b4b430785999f33eddf059af6a

-- 
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer
`. `'   Physicist
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913
Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
Posted by Ludwig Rydberg 3 weeks ago
Hi Adrian,

>>
>> I can therefore confirm that this patch fixes the bug.
>>
>> Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
> 

Thank you for testing the patches. Appreciate it!

The test program from Michael was of great help when
I analyzed the root cause. Thanks for sharing it on the list.

I'll send a new version of the series (this patch will however
remain unchanged, so I'll pick up your test tag).
If you have the possibility to re-run the clone3-tests on it
would be great. Thanks!

Best regards,
// Ludwig
Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
Posted by John Paul Adrian Glaubitz 2 weeks, 6 days ago
Hi Ludwig,

On Mon, 2026-01-19 at 14:05 +0100, Ludwig Rydberg wrote:
> > > 
> > > I can therefore confirm that this patch fixes the bug.
> > > 
> > > Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
> > 
> 
> Thank you for testing the patches. Appreciate it!
> 
> The test program from Michael was of great help when
> I analyzed the root cause. Thanks for sharing it on the list.

Credits go to Michael for digging the problem up during our last FOSDEM trip ;-).

> I'll send a new version of the series (this patch will however
> remain unchanged, so I'll pick up your test tag).
> If you have the possibility to re-run the clone3-tests on it
> would be great. Thanks!

Absolutely. Will report back later today!

Adrian

-- 
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer
`. `'   Physicist
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913
Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
Posted by John Paul Adrian Glaubitz 3 weeks, 3 days ago
Hi Ludwig

On Fri, 2026-01-16 at 16:30 +0100, Ludwig Rydberg wrote:
> From: Andreas Larsson <andreas@gaisler.com>
> 
> 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.

I have only seen now that your series fixes two bugs, one is the previously
reported clone() bug and the other one is adding clone3(). I have only tested
the latter so far, so I will add my Tested-by to the second patch.

Adrian

-- 
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer
`. `'   Physicist
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913