* [PATCH 0/3] sparc: Add architecture support for clone3
@ 2026-01-16 15:30 Ludwig Rydberg
2026-01-16 15:30 ` [PATCH 1/3] sparc: Synchronize user stack on fork and clone Ludwig Rydberg
` (4 more replies)
0 siblings, 5 replies; 17+ messages in thread
From: Ludwig Rydberg @ 2026-01-16 15:30 UTC (permalink / raw)
To: davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, glaubitz, geert,
schuster.simon
Hi all,
This series adds support for the clone3 system call to the SPARC{32|64}
architectures and also adds a related patch for clone/fork/vfork that fix an
issue previously reported[1] that could result in -EFAULT for no good reason.
Without this patch, the clone3 system call would need the same mitigation as
introduced in glibc[2] for the clone system call.
About "sparc: Synchronize user stack on fork and clone"
---------------------------------------------------------
The clone3 implementation is developed on top of a fix for an issue reported
by Adrian Glaubitz[1], where a clone call could return -EFAULT. This problem
has since been mitigated in glibc[2] by synchronizing the user stack before
calling clone.
The root cause analysis of the kernel side when running the program in [1]
shows that the window spill handler routine on both SPARC{32|64} is unable to
flush a user window to the stack (due to MMU related faults) when flushing all
windows before handling the syscall. This then results in a -EFAULT when
copy_thread() fails to clone the uncommited stackframe of the parent.
For SPARC32:
Prior to calling the syscall wrappers for clone/fork/vork all windows are
flushed by a macro (FLUSH_ALL_KERNEL_WINDOWS).
In the window spill trap handler, MMU fault-handling is temporarily
disabled while storing the window. If the window can't be stored
(which normally would have triggered a fault trap) the routine
backups the user window and increments a thread counter (wsaved).
For SPARC64:
Prior to calling the syscall wrappers for clone/fork/vork all windows are
flushed by issuing the flushw instruction.
In the window spill trap handler, if an exception triggers, then the user
window is added to the thread's user window buffer (in kernel memory) and
a thread counter (wsaved) counter is incremented.
Both SPARC{32|64}:
Eventually copy_thread will be called, which then will fail to clone the parent
stackframe to the child as the user window has not been flushed to the stack.
Fixed by adding a call to synchronize_user_stack() prior to calling
kernel_clone(). The patch has been tested both with and without the mitigation
in glibc by running the program mentioned in [1].
SPARC32:
- Tested in QEMU emulating sun4m using Buildroot 2025.02
(qemu_sparc_ss10_defconfig).
- Tested on LEON using a GR-CPCI-GR740 development board from
Frontgrade Gaisler.
SPARC64:
- Tested in QEMU emulating sun4u using Buildroot 2025.02
(qemu_sparc64_sun4u_defconfig).
About the clone3 implementation:
--------------------------------
The implementation in the architectural port follows the same pattern as for the
original clone syscall. But instead of explicitly calling kernel_clone (as in
sparc_clone) the clone3 handler calls the generic sys_clone3 handler
(in kernel/fork). To get this to work without a user provided stack,
the copy_thread functions had to be updated to handle cl_args.stack == NULL.
In this case the stack of the parent is re-used.
When applying the patch series on top of v6.19-rc1 the relevant clone3 tests of
kselftest pass:
# /usr/lib/kselftests/run_kselftest.sh -c clone3 -s
kselftest: Running tests in clone3
TAP version 13
1..4
# selftests: clone3: clone3
ok 1 selftests: clone3: clone3
# selftests: clone3: clone3_clear_sighand
ok 2 selftests: clone3: clone3_clear_sighand
# selftests: clone3: clone3_set_tid
ok 3 selftests: clone3: clone3_set_tid
# selftests: clone3: clone3_cap_checkpoint_restore
ok 4 selftests: clone3: clone3_cap_checkpoint_restore
Note that the clone3_cap_checkpoint test failed in the same way as mentioned in
[3] (due to incompatibility with the libcap version on my system).
When applying the patch from [4] or by downgrading libcap to 2.59 the test pass.
SPARC32:
- Tested in QEMU emulating sun4m using Buildroot 2025.02
(qemu_sparc_ss10_defconfig).
- Tested on LEON using a GR-CPCI-GR740 development board from
Frontgrade Gaisler.
SPARC64:
- Tested in QEMU emulating sun4u using Buildroot 2025.02
(qemu_sparc64_sun4u_defconfig).
- Tested on UltraSparc T4
[1]: https://lore.kernel.org/sparclinux/3ae4130c-c5aa-428e-b819-44cf2daf2af1@mkarcher.dialup.fu-berlin.de/
[2]: https://sourceware.org/bugzilla/show_bug.cgi?id=31394
[3]: https://lore.kernel.org/all/20250901-nios2-implement-clone3-v2-0-53fcf5577d57@siemens-energy.com/
[4]: https://lore.kernel.org/all/20241105062948.1037011-1-zhouyuhang1010@163.com/
Andreas Larsson (1):
sparc: Synchronize user stack on fork and clone
Ludwig Rydberg (2):
sparc: Add architecture support for clone3
selftests/clone3: Add sys_clone3 wrapper for SPARC
arch/sparc/include/asm/syscalls.h | 1 +
arch/sparc/include/asm/unistd.h | 2 -
arch/sparc/kernel/entry.S | 15 ++++
arch/sparc/kernel/kernel.h | 1 +
arch/sparc/kernel/process.c | 63 ++++++++++++----
arch/sparc/kernel/process_32.c | 2 +-
arch/sparc/kernel/process_64.c | 2 +-
arch/sparc/kernel/syscalls.S | 6 ++
arch/sparc/kernel/syscalls/syscall.tbl | 2 +-
.../selftests/clone3/clone3_selftests.h | 75 +++++++++++++++++++
10 files changed, 150 insertions(+), 19 deletions(-)
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
--
2.35.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/3] sparc: Synchronize user stack on fork and clone
2026-01-16 15:30 [PATCH 0/3] sparc: Add architecture support for clone3 Ludwig Rydberg
@ 2026-01-16 15:30 ` Ludwig Rydberg
2026-01-16 17:17 ` John Paul Adrian Glaubitz
2026-01-17 6:57 ` John Paul Adrian Glaubitz
2026-01-16 15:30 ` [PATCH 2/3] sparc: Add architecture support for clone3 Ludwig Rydberg
` (3 subsequent siblings)
4 siblings, 2 replies; 17+ messages in thread
From: Ludwig Rydberg @ 2026-01-16 15:30 UTC (permalink / raw)
To: davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, glaubitz, geert,
schuster.simon, kernel
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 2/3] sparc: Add architecture support for clone3
2026-01-16 15:30 [PATCH 0/3] sparc: Add architecture support for clone3 Ludwig Rydberg
2026-01-16 15:30 ` [PATCH 1/3] sparc: Synchronize user stack on fork and clone Ludwig Rydberg
@ 2026-01-16 15:30 ` Ludwig Rydberg
2026-01-16 16:47 ` Jessica Clarke
2026-01-16 17:19 ` John Paul Adrian Glaubitz
2026-01-16 15:30 ` [PATCH 3/3] selftests/clone3: Add sys_clone3 wrapper for SPARC Ludwig Rydberg
` (2 subsequent siblings)
4 siblings, 2 replies; 17+ messages in thread
From: Ludwig Rydberg @ 2026-01-16 15:30 UTC (permalink / raw)
To: davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, glaubitz, geert,
schuster.simon
Add support for the clone3 system call to the SPARC architectures.
The implementation follows the pattern of the original clone syscall.
However, instead of explicitly calling kernel_clone, the clone3
handler calls the generic sys_clone3 handler in kernel/fork.
In case no stack is provided, the parents stack is reused.
The return call conventions for clone on SPARC are kept for clone3:
Parent --> %o0 == child's pid, %o1 == 0
Child --> %o0 == parent's pid, %o1 == 1
Closes: https://github.com/sparclinux/issues/issues/10
Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
---
arch/sparc/include/asm/syscalls.h | 1 +
arch/sparc/include/asm/unistd.h | 2 --
arch/sparc/kernel/entry.S | 15 +++++++++++++++
arch/sparc/kernel/kernel.h | 1 +
arch/sparc/kernel/process.c | 25 +++++++++++++++++++++++++
arch/sparc/kernel/process_32.c | 2 +-
arch/sparc/kernel/process_64.c | 2 +-
arch/sparc/kernel/syscalls.S | 6 ++++++
arch/sparc/kernel/syscalls/syscall.tbl | 2 +-
9 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/arch/sparc/include/asm/syscalls.h b/arch/sparc/include/asm/syscalls.h
index 35575fbfb9dc..282e62b66518 100644
--- a/arch/sparc/include/asm/syscalls.h
+++ b/arch/sparc/include/asm/syscalls.h
@@ -7,5 +7,6 @@ struct pt_regs;
asmlinkage long sparc_fork(struct pt_regs *regs);
asmlinkage long sparc_vfork(struct pt_regs *regs);
asmlinkage long sparc_clone(struct pt_regs *regs);
+asmlinkage long sparc_clone3(struct pt_regs *regs);
#endif /* _SPARC64_SYSCALLS_H */
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
index 3380411a4537..d6bc76706a7a 100644
--- a/arch/sparc/include/asm/unistd.h
+++ b/arch/sparc/include/asm/unistd.h
@@ -49,8 +49,6 @@
#define __ARCH_WANT_COMPAT_STAT
#endif
-#define __ARCH_BROKEN_SYS_CLONE3
-
#ifdef __32bit_syscall_numbers__
/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
* it never had the plain ones and there is no value to adding those
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index a3fdee4cd6fa..ea51ef52c952 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -907,6 +907,21 @@ flush_patch_four:
jmpl %l1 + %lo(sparc_vfork), %g0
add %sp, STACKFRAME_SZ, %o0
+ .globl __sys_clone3, flush_patch_five
+__sys_clone3:
+ mov %o7, %l5
+flush_patch_five:
+ FLUSH_ALL_KERNEL_WINDOWS;
+ ld [%curptr + TI_TASK], %o4
+ rd %psr, %g4
+ WRITE_PAUSE
+ rd %wim, %g5
+ WRITE_PAUSE
+ std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
+ add %sp, STACKFRAME_SZ, %o0
+ call sparc_clone3
+ mov %l5, %o7
+
.align 4
linux_sparc_ni_syscall:
sethi %hi(sys_ni_syscall), %l7
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 8328a3b78a44..4ee85051521a 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -18,6 +18,7 @@ extern int ncpus_probed;
asmlinkage long sparc_clone(struct pt_regs *regs);
asmlinkage long sparc_fork(struct pt_regs *regs);
asmlinkage long sparc_vfork(struct pt_regs *regs);
+asmlinkage long sparc_clone3(struct pt_regs *regs);
#ifdef CONFIG_SPARC64
/* setup_64.c */
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 7d69877511fa..b8e23295db69 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -12,6 +12,7 @@
#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/signal.h>
+#include <linux/syscalls.h>
#include "kernel.h"
@@ -118,3 +119,27 @@ asmlinkage long sparc_clone(struct pt_regs *regs)
return ret;
}
+
+asmlinkage long sparc_clone3(struct pt_regs *regs)
+{
+ unsigned long sz;
+ long ret;
+ struct clone_args __user *cl_args;
+
+ synchronize_user_stack();
+
+ cl_args = (struct clone_args __user *)regs->u_regs[UREG_I0];
+ sz = regs->u_regs[UREG_I1];
+
+ ret = sys_clone3(cl_args, sz);
+
+ /* If we get an error and potentially restart the system
+ * call, we're screwed because copy_thread() clobbered
+ * the parent's %o1. So detect that case and restore it
+ * here.
+ */
+ if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
+ regs->u_regs[UREG_I1] = sz;
+
+ return ret;
+}
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 5a28c0e91bf1..216c07971c81 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -261,11 +261,11 @@ extern void ret_from_kernel_thread(void);
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
u64 clone_flags = args->flags;
- unsigned long sp = args->stack;
unsigned long tls = args->tls;
struct thread_info *ti = task_thread_info(p);
struct pt_regs *childregs, *regs = current_pt_regs();
char *new_stack;
+ unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
#ifndef CONFIG_SMP
if(last_task_used_math == current) {
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index 25781923788a..885d617ba29d 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -568,13 +568,13 @@ void fault_in_user_windows(struct pt_regs *regs)
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
u64 clone_flags = args->flags;
- unsigned long sp = args->stack;
unsigned long tls = args->tls;
struct thread_info *t = task_thread_info(p);
struct pt_regs *regs = current_pt_regs();
struct sparc_stackf *parent_sf;
unsigned long child_stack_sz;
char *child_trap_frame;
+ unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
/* Calculate offset to stack_frame & pt_regs */
child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
index 0e8ab0602c36..c8d374a37f98 100644
--- a/arch/sparc/kernel/syscalls.S
+++ b/arch/sparc/kernel/syscalls.S
@@ -103,6 +103,12 @@ sys_clone:
ba,pt %xcc, sparc_clone
add %sp, PTREGS_OFF, %o0
+ .align 32
+__sys_clone3:
+ flushw
+ ba,pt %xcc, sparc_clone3
+ add %sp, PTREGS_OFF, %o0
+
.globl ret_from_fork
ret_from_fork:
/* Clear current_thread_info()->new_child. */
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
index 39aa26b6a50b..c0307bb09892 100644
--- a/arch/sparc/kernel/syscalls/syscall.tbl
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
@@ -480,7 +480,7 @@
432 common fsmount sys_fsmount
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
-# 435 reserved for clone3
+435 common clone3 __sys_clone3
436 common close_range sys_close_range
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
--
2.35.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 3/3] selftests/clone3: Add sys_clone3 wrapper for SPARC
2026-01-16 15:30 [PATCH 0/3] sparc: Add architecture support for clone3 Ludwig Rydberg
2026-01-16 15:30 ` [PATCH 1/3] sparc: Synchronize user stack on fork and clone Ludwig Rydberg
2026-01-16 15:30 ` [PATCH 2/3] sparc: Add architecture support for clone3 Ludwig Rydberg
@ 2026-01-16 15:30 ` Ludwig Rydberg
2026-01-16 15:44 ` [PATCH 0/3] sparc: Add architecture support for clone3 John Paul Adrian Glaubitz
2026-01-16 16:26 ` John Paul Adrian Glaubitz
4 siblings, 0 replies; 17+ messages in thread
From: Ludwig Rydberg @ 2026-01-16 15:30 UTC (permalink / raw)
To: davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, glaubitz, geert,
schuster.simon
Add a sys_clone3 wrapper (based on the INLINE_CLONE_SYSCALL macro
in glibc) for SPARC to handle its unique return call convention.
The needed handling is described in arch/sparc/kernel/process_{32|64}.c:
Parent --> %o0 == child's pid, %o1 == 0
Child --> %o0 == parent's pid, %o1 == 1
Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
---
.../selftests/clone3/clone3_selftests.h | 75 +++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/tools/testing/selftests/clone3/clone3_selftests.h b/tools/testing/selftests/clone3/clone3_selftests.h
index a0593e8950f0..5fa33294227d 100644
--- a/tools/testing/selftests/clone3/clone3_selftests.h
+++ b/tools/testing/selftests/clone3/clone3_selftests.h
@@ -33,12 +33,87 @@ struct __clone_args {
__aligned_u64 cgroup;
};
+#if defined(__sparc__)
+#include <errno.h>
+
+#if defined(__arch64__)
+#define __SYSCALL_STRING \
+ "mov %[scn], %%g1;" \
+ "ta 0x6d;" \
+ "bcc,pt %%xcc, 1f;" \
+ " nop;" \
+ "sub %%g0, %%o0, %%o0;" \
+ "1:"
+
+#define __SYSCALL_CLOBBERS \
+ "g1", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
+ "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", \
+ "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", \
+ "cc", "memory"
+#else
+#define __SYSCALL_STRING \
+ "mov %[scn], %%g1;" \
+ "ta 0x10;" \
+ "bcc 1f;" \
+ " nop;" \
+ "sub %%g0, %%o0, %%o0;" \
+ "1:"
+
+#define __SYSCALL_CLOBBERS \
+ "g1", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
+ "cc", "memory"
+#endif
+
+/* A special wrapper is required to handle the return call convention
+ * on SPARC and is based on the INLINE_CLONE_SYSCALL macro in glibc.
+ *
+ * Parent --> %o0 == child's pid, %o1 == 0
+ * Child --> %o0 == parent's pid, %o1 == 1
+ */
+static inline pid_t sparc_clone3(struct __clone_args *args, size_t size)
+{
+ long _cl_args = (long) (args);
+ long _size = (long) (size);
+ long _scn = __NR_clone3;
+
+ register long o0 __asm__ ("o0") = _cl_args;
+ register long o1 __asm__ ("o1") = _size;
+
+ asm volatile (__SYSCALL_STRING
+ : "=r" (o0), "=r" (o1)
+ : [scn] "r" (_scn), "0" (o0), "1" (o1)
+ : __SYSCALL_CLOBBERS);
+
+ if ((unsigned long) (o0) > -4096UL) {
+ errno = -o0;
+ o0 = -1L;
+ } else {
+ o0 &= (o1 - 1);
+ }
+
+ return o0;
+}
+
+static pid_t sys_clone3(struct __clone_args *args, size_t size)
+{
+ fflush(stdout);
+ fflush(stderr);
+ return sparc_clone3(args, size);
+}
+#else
static pid_t sys_clone3(struct __clone_args *args, size_t size)
{
fflush(stdout);
fflush(stderr);
return syscall(__NR_clone3, args, size);
}
+#endif
static inline void test_clone3_supported(void)
{
--
2.35.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] sparc: Add architecture support for clone3
2026-01-16 15:30 [PATCH 0/3] sparc: Add architecture support for clone3 Ludwig Rydberg
` (2 preceding siblings ...)
2026-01-16 15:30 ` [PATCH 3/3] selftests/clone3: Add sys_clone3 wrapper for SPARC Ludwig Rydberg
@ 2026-01-16 15:44 ` John Paul Adrian Glaubitz
2026-01-16 16:26 ` John Paul Adrian Glaubitz
4 siblings, 0 replies; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-16 15:44 UTC (permalink / raw)
To: Ludwig Rydberg, davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert, schuster.simon
Hi Ludwig,
On Fri, 2026-01-16 at 16:30 +0100, Ludwig Rydberg wrote:
> This series adds support for the clone3 system call to the SPARC{32|64}
> architectures and also adds a related patch for clone/fork/vfork that fix an
> issue previously reported[1] that could result in -EFAULT for no good reason.
> Without this patch, the clone3 system call would need the same mitigation as
> introduced in glibc[2] for the clone system call.
Woohoo, thanks a lot for working on this! I'll build a test kernel right away!
Adrian
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer
`. `' Physicist
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] sparc: Add architecture support for clone3
2026-01-16 15:30 [PATCH 0/3] sparc: Add architecture support for clone3 Ludwig Rydberg
` (3 preceding siblings ...)
2026-01-16 15:44 ` [PATCH 0/3] sparc: Add architecture support for clone3 John Paul Adrian Glaubitz
@ 2026-01-16 16:26 ` John Paul Adrian Glaubitz
4 siblings, 0 replies; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-16 16:26 UTC (permalink / raw)
To: Ludwig Rydberg, davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert, schuster.simon
Hi Ludwig,
On Fri, 2026-01-16 at 16:30 +0100, Ludwig Rydberg wrote:
> This series adds support for the clone3 system call to the SPARC{32|64}
> architectures and also adds a related patch for clone/fork/vfork that fix an
> issue previously reported[1] that could result in -EFAULT for no good reason.
> Without this patch, the clone3 system call would need the same mitigation as
> introduced in glibc[2] for the clone system call.
>
> About "sparc: Synchronize user stack on fork and clone"
> ---------------------------------------------------------
>
> The clone3 implementation is developed on top of a fix for an issue reported
> by Adrian Glaubitz[1], where a clone call could return -EFAULT. This problem
> has since been mitigated in glibc[2] by synchronizing the user stack before
> calling clone.
>
> The root cause analysis of the kernel side when running the program in [1]
> shows that the window spill handler routine on both SPARC{32|64} is unable to
> flush a user window to the stack (due to MMU related faults) when flushing all
> windows before handling the syscall. This then results in a -EFAULT when
> copy_thread() fails to clone the uncommited stackframe of the parent.
>
> For SPARC32:
> Prior to calling the syscall wrappers for clone/fork/vork all windows are
> flushed by a macro (FLUSH_ALL_KERNEL_WINDOWS).
> In the window spill trap handler, MMU fault-handling is temporarily
> disabled while storing the window. If the window can't be stored
> (which normally would have triggered a fault trap) the routine
> backups the user window and increments a thread counter (wsaved).
>
> For SPARC64:
> Prior to calling the syscall wrappers for clone/fork/vork all windows are
> flushed by issuing the flushw instruction.
> In the window spill trap handler, if an exception triggers, then the user
> window is added to the thread's user window buffer (in kernel memory) and
> a thread counter (wsaved) counter is incremented.
>
> Both SPARC{32|64}:
> Eventually copy_thread will be called, which then will fail to clone the parent
> stackframe to the child as the user window has not been flushed to the stack.
>
> Fixed by adding a call to synchronize_user_stack() prior to calling
> kernel_clone(). The patch has been tested both with and without the mitigation
> in glibc by running the program mentioned in [1].
>
> SPARC32:
> - Tested in QEMU emulating sun4m using Buildroot 2025.02
> (qemu_sparc_ss10_defconfig).
> - Tested on LEON using a GR-CPCI-GR740 development board from
> Frontgrade Gaisler.
>
> SPARC64:
> - Tested in QEMU emulating sun4u using Buildroot 2025.02
> (qemu_sparc64_sun4u_defconfig).
>
> About the clone3 implementation:
> --------------------------------
>
> The implementation in the architectural port follows the same pattern as for the
> original clone syscall. But instead of explicitly calling kernel_clone (as in
> sparc_clone) the clone3 handler calls the generic sys_clone3 handler
> (in kernel/fork). To get this to work without a user provided stack,
> the copy_thread functions had to be updated to handle cl_args.stack == NULL.
> In this case the stack of the parent is re-used.
>
> When applying the patch series on top of v6.19-rc1 the relevant clone3 tests of
> kselftest pass:
>
> # /usr/lib/kselftests/run_kselftest.sh -c clone3 -s
> kselftest: Running tests in clone3
> TAP version 13
> 1..4
> # selftests: clone3: clone3
> ok 1 selftests: clone3: clone3
> # selftests: clone3: clone3_clear_sighand
> ok 2 selftests: clone3: clone3_clear_sighand
> # selftests: clone3: clone3_set_tid
> ok 3 selftests: clone3: clone3_set_tid
> # selftests: clone3: clone3_cap_checkpoint_restore
> ok 4 selftests: clone3: clone3_cap_checkpoint_restore
>
> Note that the clone3_cap_checkpoint test failed in the same way as mentioned in
> [3] (due to incompatibility with the libcap version on my system).
> When applying the patch from [4] or by downgrading libcap to 2.59 the test pass.
>
> SPARC32:
> - Tested in QEMU emulating sun4m using Buildroot 2025.02
> (qemu_sparc_ss10_defconfig).
> - Tested on LEON using a GR-CPCI-GR740 development board from
> Frontgrade Gaisler.
>
> SPARC64:
> - Tested in QEMU emulating sun4u using Buildroot 2025.02
> (qemu_sparc64_sun4u_defconfig).
> - Tested on UltraSparc T4
>
> [1]: https://lore.kernel.org/sparclinux/3ae4130c-c5aa-428e-b819-44cf2daf2af1@mkarcher.dialup.fu-berlin.de/
> [2]: https://sourceware.org/bugzilla/show_bug.cgi?id=31394
> [3]: https://lore.kernel.org/all/20250901-nios2-implement-clone3-v2-0-53fcf5577d57@siemens-energy.com/
> [4]: https://lore.kernel.org/all/20241105062948.1037011-1-zhouyuhang1010@163.com/
>
> Andreas Larsson (1):
> sparc: Synchronize user stack on fork and clone
>
> Ludwig Rydberg (2):
> sparc: Add architecture support for clone3
> selftests/clone3: Add sys_clone3 wrapper for SPARC
>
> arch/sparc/include/asm/syscalls.h | 1 +
> arch/sparc/include/asm/unistd.h | 2 -
> arch/sparc/kernel/entry.S | 15 ++++
> arch/sparc/kernel/kernel.h | 1 +
> arch/sparc/kernel/process.c | 63 ++++++++++++----
> arch/sparc/kernel/process_32.c | 2 +-
> arch/sparc/kernel/process_64.c | 2 +-
> arch/sparc/kernel/syscalls.S | 6 ++
> arch/sparc/kernel/syscalls/syscall.tbl | 2 +-
> .../selftests/clone3/clone3_selftests.h | 75 +++++++++++++++++++
> 10 files changed, 150 insertions(+), 19 deletions(-)
Applied on top of 6.19-rc5, tested on a Sun Netra 240 (UltraSPARC IIIi).
Running the kernel selftest for clone3 works fine:
root@raverin:/usr/src/linux/tools/testing/selftests/clone3# uname -a
Linux raverin 6.19.0-rc5+ #18 Fri Jan 16 16:02:10 UTC 2026 sparc64 GNU/Linux
root@raverin:/usr/src/linux/tools/testing/selftests/clone3# make
CC clone3
CC clone3_clear_sighand
CC clone3_set_tid
CC clone3_cap_checkpoint_restore
root@raverin:/usr/src/linux/tools/testing/selftests/clone3# ./clone3
TAP version 13
1..19
# clone3() syscall supported
# Running test 'simple clone3()'
# [1385] Trying clone3() with flags 0 (size 0)
# I am the parent (1385). My child's pid is 1386
# I am the child, my PID is 1386
# [1385] clone3() with flags says: 0 expected 0
ok 1 simple clone3()
# Running test 'clone3() in a new PID_NS'
# [1385] Trying clone3() with flags 0x20000000 (size 0)
# I am the child, my PID is 1
# I am the parent (1385). My child's pid is 1387
# [1385] clone3() with flags says: 0 expected 0
ok 2 clone3() in a new PID_NS
# Running test 'CLONE_ARGS_SIZE_VER0'
# [1385] Trying clone3() with flags 0 (size 64)
# I am the parent (1385). My child's pid is 1388
# I am the child, my PID is 1388
# [1385] clone3() with flags says: 0 expected 0
ok 3 CLONE_ARGS_SIZE_VER0
# Running test 'CLONE_ARGS_SIZE_VER0 - 8'
# [1385] Trying clone3() with flags 0 (size 56)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 4 CLONE_ARGS_SIZE_VER0 - 8
# Running test 'sizeof(struct clone_args) + 8'
# [1385] Trying clone3() with flags 0 (size 96)
# I am the parent (1385). My child's pid is 1389
# I am the child, my PID is 1389
# [1385] clone3() with flags says: 0 expected 0
ok 5 sizeof(struct clone_args) + 8
# Running test 'exit_signal with highest 32 bits non-zero'
# [1385] Trying clone3() with flags 0 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 6 exit_signal with highest 32 bits non-zero
# Running test 'negative 32-bit exit_signal'
# [1385] Trying clone3() with flags 0 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 7 negative 32-bit exit_signal
# Running test 'exit_signal not fitting into CSIGNAL mask'
# [1385] Trying clone3() with flags 0 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 8 exit_signal not fitting into CSIGNAL mask
# Running test 'NSIG < exit_signal < CSIG'
# [1385] Trying clone3() with flags 0 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 9 NSIG < exit_signal < CSIG
# Running test 'Arguments sizeof(struct clone_args) + 8'
# [1385] Trying clone3() with flags 0 (size 96)
# I am the parent (1385). My child's pid is 1390
# I am the child, my PID is 1390
# [1385] clone3() with flags says: 0 expected 0
ok 10 Arguments sizeof(struct clone_args) + 8
# Running test 'Arguments sizeof(struct clone_args) + 16'
# [1385] Trying clone3() with flags 0 (size 104)
# Argument list too long - Failed to create new process
# [1385] clone3() with flags says: -7 expected -7
ok 11 Arguments sizeof(struct clone_args) + 16
# Running test 'Arguments sizeof(struct clone_arg) * 2'
# [1385] Trying clone3() with flags 0 (size 104)
# Argument list too long - Failed to create new process
# [1385] clone3() with flags says: -7 expected -7
ok 12 Arguments sizeof(struct clone_arg) * 2
# Running test 'Arguments > page size'
# [1385] Trying clone3() with flags 0 (size 8200)
# Argument list too long - Failed to create new process
# [1385] clone3() with flags says: -7 expected -7
ok 13 Arguments > page size
# Running test 'CLONE_ARGS_SIZE_VER0 in a new PID NS'
# [1385] Trying clone3() with flags 0x20000000 (size 64)
# I am the parent (1385). My child's pid is 1391
# I am the child, my PID is 1
# [1385] clone3() with flags says: 0 expected 0
ok 14 CLONE_ARGS_SIZE_VER0 in a new PID NS
# Running test 'CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS'
# [1385] Trying clone3() with flags 0x20000000 (size 56)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 15 CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS
# Running test 'sizeof(struct clone_args) + 8 in a new PID NS'
# [1385] Trying clone3() with flags 0x20000000 (size 96)
# I am the parent (1385). My child's pid is 1392
# I am the child, my PID is 1
# [1385] clone3() with flags says: 0 expected 0
ok 16 sizeof(struct clone_args) + 8 in a new PID NS
# Running test 'Arguments > page size in a new PID NS'
# [1385] Trying clone3() with flags 0x20000000 (size 8200)
# Argument list too long - Failed to create new process
# [1385] clone3() with flags says: -7 expected -7
ok 17 Arguments > page size in a new PID NS
# Time namespaces are not supported
ok 18 # SKIP New time NS
# Running test 'exit signal (SIGCHLD) in flags'
# [1385] Trying clone3() with flags 0x14 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 19 exit signal (SIGCHLD) in flags
# 1 skipped test(s) detected. Consider enabling relevant config options to improve coverage.
# Totals: pass:18 fail:0 xfail:0 xpass:0 skip:1 error:0
root@raverin:/usr/src/linux/tools/testing/selftests/clone3#
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] sparc: Add architecture support for clone3
2026-01-16 15:30 ` [PATCH 2/3] sparc: Add architecture support for clone3 Ludwig Rydberg
@ 2026-01-16 16:47 ` Jessica Clarke
2026-01-17 21:23 ` John Paul Adrian Glaubitz
2026-01-19 12:39 ` Ludwig Rydberg
2026-01-16 17:19 ` John Paul Adrian Glaubitz
1 sibling, 2 replies; 17+ messages in thread
From: Jessica Clarke @ 2026-01-16 16:47 UTC (permalink / raw)
To: Ludwig Rydberg
Cc: davem, andreas, brauner, shuah, sparclinux, linux-kselftest,
linux-kernel, arnd, glaubitz, geert, schuster.simon
On Fri, Jan 16, 2026 at 04:30:50PM +0100, Ludwig Rydberg wrote:
> Add support for the clone3 system call to the SPARC architectures.
>
> The implementation follows the pattern of the original clone syscall.
> However, instead of explicitly calling kernel_clone, the clone3
> handler calls the generic sys_clone3 handler in kernel/fork.
> In case no stack is provided, the parents stack is reused.
>
> The return call conventions for clone on SPARC are kept for clone3:
> Parent --> %o0 == child's pid, %o1 == 0
> Child --> %o0 == parent's pid, %o1 == 1
One of the benefits of having a new clone3 is that the interface can be
made the same across all architectures*, unlike clone, which both passes
the arguments in different orders for different architectures and, in
the case of SPARC, has this weird return convention inherited from the
SunOS syscall interface. Is there a good reason to deviate for clone3
too and keep this annoying oddity going, that requires special-casing
SPARC when other architectures can just syscall(__NR_clone3, ...)?
Jessica
* Even Itanium's clone2 could have been subsumed by it, as clone3 passes
the stack base and size rather than the desired stack pointer
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
2026-01-16 15:30 ` [PATCH 1/3] sparc: Synchronize user stack on fork and clone Ludwig Rydberg
@ 2026-01-16 17:17 ` John Paul Adrian Glaubitz
2026-01-17 6:57 ` John Paul Adrian Glaubitz
1 sibling, 0 replies; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-16 17:17 UTC (permalink / raw)
To: Ludwig Rydberg, davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert,
schuster.simon, kernel
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] sparc: Add architecture support for clone3
2026-01-16 15:30 ` [PATCH 2/3] sparc: Add architecture support for clone3 Ludwig Rydberg
2026-01-16 16:47 ` Jessica Clarke
@ 2026-01-16 17:19 ` John Paul Adrian Glaubitz
1 sibling, 0 replies; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-16 17:19 UTC (permalink / raw)
To: Ludwig Rydberg, davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert, schuster.simon
Hi Ludwig,
On Fri, 2026-01-16 at 16:30 +0100, Ludwig Rydberg wrote:
> Add support for the clone3 system call to the SPARC architectures.
>
> The implementation follows the pattern of the original clone syscall.
> However, instead of explicitly calling kernel_clone, the clone3
> handler calls the generic sys_clone3 handler in kernel/fork.
> In case no stack is provided, the parents stack is reused.
>
> The return call conventions for clone on SPARC are kept for clone3:
> Parent --> %o0 == child's pid, %o1 == 0
> Child --> %o0 == parent's pid, %o1 == 1
>
> Closes: https://github.com/sparclinux/issues/issues/10
> Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
> ---
> arch/sparc/include/asm/syscalls.h | 1 +
> arch/sparc/include/asm/unistd.h | 2 --
> arch/sparc/kernel/entry.S | 15 +++++++++++++++
> arch/sparc/kernel/kernel.h | 1 +
> arch/sparc/kernel/process.c | 25 +++++++++++++++++++++++++
> arch/sparc/kernel/process_32.c | 2 +-
> arch/sparc/kernel/process_64.c | 2 +-
> arch/sparc/kernel/syscalls.S | 6 ++++++
> arch/sparc/kernel/syscalls/syscall.tbl | 2 +-
> 9 files changed, 51 insertions(+), 5 deletions(-)
>
> diff --git a/arch/sparc/include/asm/syscalls.h b/arch/sparc/include/asm/syscalls.h
> index 35575fbfb9dc..282e62b66518 100644
> --- a/arch/sparc/include/asm/syscalls.h
> +++ b/arch/sparc/include/asm/syscalls.h
> @@ -7,5 +7,6 @@ struct pt_regs;
> asmlinkage long sparc_fork(struct pt_regs *regs);
> asmlinkage long sparc_vfork(struct pt_regs *regs);
> asmlinkage long sparc_clone(struct pt_regs *regs);
> +asmlinkage long sparc_clone3(struct pt_regs *regs);
>
> #endif /* _SPARC64_SYSCALLS_H */
> diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
> index 3380411a4537..d6bc76706a7a 100644
> --- a/arch/sparc/include/asm/unistd.h
> +++ b/arch/sparc/include/asm/unistd.h
> @@ -49,8 +49,6 @@
> #define __ARCH_WANT_COMPAT_STAT
> #endif
>
> -#define __ARCH_BROKEN_SYS_CLONE3
> -
> #ifdef __32bit_syscall_numbers__
> /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
> * it never had the plain ones and there is no value to adding those
> diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
> index a3fdee4cd6fa..ea51ef52c952 100644
> --- a/arch/sparc/kernel/entry.S
> +++ b/arch/sparc/kernel/entry.S
> @@ -907,6 +907,21 @@ flush_patch_four:
> jmpl %l1 + %lo(sparc_vfork), %g0
> add %sp, STACKFRAME_SZ, %o0
>
> + .globl __sys_clone3, flush_patch_five
> +__sys_clone3:
> + mov %o7, %l5
> +flush_patch_five:
> + FLUSH_ALL_KERNEL_WINDOWS;
> + ld [%curptr + TI_TASK], %o4
> + rd %psr, %g4
> + WRITE_PAUSE
> + rd %wim, %g5
> + WRITE_PAUSE
> + std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
> + add %sp, STACKFRAME_SZ, %o0
> + call sparc_clone3
> + mov %l5, %o7
> +
> .align 4
> linux_sparc_ni_syscall:
> sethi %hi(sys_ni_syscall), %l7
> diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
> index 8328a3b78a44..4ee85051521a 100644
> --- a/arch/sparc/kernel/kernel.h
> +++ b/arch/sparc/kernel/kernel.h
> @@ -18,6 +18,7 @@ extern int ncpus_probed;
> asmlinkage long sparc_clone(struct pt_regs *regs);
> asmlinkage long sparc_fork(struct pt_regs *regs);
> asmlinkage long sparc_vfork(struct pt_regs *regs);
> +asmlinkage long sparc_clone3(struct pt_regs *regs);
>
> #ifdef CONFIG_SPARC64
> /* setup_64.c */
> diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
> index 7d69877511fa..b8e23295db69 100644
> --- a/arch/sparc/kernel/process.c
> +++ b/arch/sparc/kernel/process.c
> @@ -12,6 +12,7 @@
> #include <linux/sched/task.h>
> #include <linux/sched/task_stack.h>
> #include <linux/signal.h>
> +#include <linux/syscalls.h>
>
> #include "kernel.h"
>
> @@ -118,3 +119,27 @@ asmlinkage long sparc_clone(struct pt_regs *regs)
>
> return ret;
> }
> +
> +asmlinkage long sparc_clone3(struct pt_regs *regs)
> +{
> + unsigned long sz;
> + long ret;
> + struct clone_args __user *cl_args;
> +
> + synchronize_user_stack();
> +
> + cl_args = (struct clone_args __user *)regs->u_regs[UREG_I0];
> + sz = regs->u_regs[UREG_I1];
> +
> + ret = sys_clone3(cl_args, sz);
> +
> + /* If we get an error and potentially restart the system
> + * call, we're screwed because copy_thread() clobbered
> + * the parent's %o1. So detect that case and restore it
> + * here.
> + */
> + if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
> + regs->u_regs[UREG_I1] = sz;
> +
> + return ret;
> +}
> diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
> index 5a28c0e91bf1..216c07971c81 100644
> --- a/arch/sparc/kernel/process_32.c
> +++ b/arch/sparc/kernel/process_32.c
> @@ -261,11 +261,11 @@ extern void ret_from_kernel_thread(void);
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> u64 clone_flags = args->flags;
> - unsigned long sp = args->stack;
> unsigned long tls = args->tls;
> struct thread_info *ti = task_thread_info(p);
> struct pt_regs *childregs, *regs = current_pt_regs();
> char *new_stack;
> + unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
>
> #ifndef CONFIG_SMP
> if(last_task_used_math == current) {
> diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
> index 25781923788a..885d617ba29d 100644
> --- a/arch/sparc/kernel/process_64.c
> +++ b/arch/sparc/kernel/process_64.c
> @@ -568,13 +568,13 @@ void fault_in_user_windows(struct pt_regs *regs)
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> u64 clone_flags = args->flags;
> - unsigned long sp = args->stack;
> unsigned long tls = args->tls;
> struct thread_info *t = task_thread_info(p);
> struct pt_regs *regs = current_pt_regs();
> struct sparc_stackf *parent_sf;
> unsigned long child_stack_sz;
> char *child_trap_frame;
> + unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
>
> /* Calculate offset to stack_frame & pt_regs */
> child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
> diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
> index 0e8ab0602c36..c8d374a37f98 100644
> --- a/arch/sparc/kernel/syscalls.S
> +++ b/arch/sparc/kernel/syscalls.S
> @@ -103,6 +103,12 @@ sys_clone:
> ba,pt %xcc, sparc_clone
> add %sp, PTREGS_OFF, %o0
>
> + .align 32
> +__sys_clone3:
> + flushw
> + ba,pt %xcc, sparc_clone3
> + add %sp, PTREGS_OFF, %o0
> +
> .globl ret_from_fork
> ret_from_fork:
> /* Clear current_thread_info()->new_child. */
> diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
> index 39aa26b6a50b..c0307bb09892 100644
> --- a/arch/sparc/kernel/syscalls/syscall.tbl
> +++ b/arch/sparc/kernel/syscalls/syscall.tbl
> @@ -480,7 +480,7 @@
> 432 common fsmount sys_fsmount
> 433 common fspick sys_fspick
> 434 common pidfd_open sys_pidfd_open
> -# 435 reserved for clone3
> +435 common clone3 __sys_clone3
> 436 common close_range sys_close_range
> 437 common openat2 sys_openat2
> 438 common pidfd_getfd sys_pidfd_getfd
Applied on top of 6.19-rc5, tested on a Sun Netra 240 (UltraSPARC IIIi).
Running the kernel selftest for clone3 works fine:
root@raverin:/usr/src/linux/tools/testing/selftests/clone3# uname -a
Linux raverin 6.19.0-rc5+ #18 Fri Jan 16 16:02:10 UTC 2026 sparc64 GNU/Linux
root@raverin:/usr/src/linux/tools/testing/selftests/clone3# make
CC clone3
CC clone3_clear_sighand
CC clone3_set_tid
CC clone3_cap_checkpoint_restore
root@raverin:/usr/src/linux/tools/testing/selftests/clone3# ./clone3
TAP version 13
1..19
# clone3() syscall supported
# Running test 'simple clone3()'
# [1385] Trying clone3() with flags 0 (size 0)
# I am the parent (1385). My child's pid is 1386
# I am the child, my PID is 1386
# [1385] clone3() with flags says: 0 expected 0
ok 1 simple clone3()
# Running test 'clone3() in a new PID_NS'
# [1385] Trying clone3() with flags 0x20000000 (size 0)
# I am the child, my PID is 1
# I am the parent (1385). My child's pid is 1387
# [1385] clone3() with flags says: 0 expected 0
ok 2 clone3() in a new PID_NS
# Running test 'CLONE_ARGS_SIZE_VER0'
# [1385] Trying clone3() with flags 0 (size 64)
# I am the parent (1385). My child's pid is 1388
# I am the child, my PID is 1388
# [1385] clone3() with flags says: 0 expected 0
ok 3 CLONE_ARGS_SIZE_VER0
# Running test 'CLONE_ARGS_SIZE_VER0 - 8'
# [1385] Trying clone3() with flags 0 (size 56)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 4 CLONE_ARGS_SIZE_VER0 - 8
# Running test 'sizeof(struct clone_args) + 8'
# [1385] Trying clone3() with flags 0 (size 96)
# I am the parent (1385). My child's pid is 1389
# I am the child, my PID is 1389
# [1385] clone3() with flags says: 0 expected 0
ok 5 sizeof(struct clone_args) + 8
# Running test 'exit_signal with highest 32 bits non-zero'
# [1385] Trying clone3() with flags 0 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 6 exit_signal with highest 32 bits non-zero
# Running test 'negative 32-bit exit_signal'
# [1385] Trying clone3() with flags 0 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 7 negative 32-bit exit_signal
# Running test 'exit_signal not fitting into CSIGNAL mask'
# [1385] Trying clone3() with flags 0 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 8 exit_signal not fitting into CSIGNAL mask
# Running test 'NSIG < exit_signal < CSIG'
# [1385] Trying clone3() with flags 0 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 9 NSIG < exit_signal < CSIG
# Running test 'Arguments sizeof(struct clone_args) + 8'
# [1385] Trying clone3() with flags 0 (size 96)
# I am the parent (1385). My child's pid is 1390
# I am the child, my PID is 1390
# [1385] clone3() with flags says: 0 expected 0
ok 10 Arguments sizeof(struct clone_args) + 8
# Running test 'Arguments sizeof(struct clone_args) + 16'
# [1385] Trying clone3() with flags 0 (size 104)
# Argument list too long - Failed to create new process
# [1385] clone3() with flags says: -7 expected -7
ok 11 Arguments sizeof(struct clone_args) + 16
# Running test 'Arguments sizeof(struct clone_arg) * 2'
# [1385] Trying clone3() with flags 0 (size 104)
# Argument list too long - Failed to create new process
# [1385] clone3() with flags says: -7 expected -7
ok 12 Arguments sizeof(struct clone_arg) * 2
# Running test 'Arguments > page size'
# [1385] Trying clone3() with flags 0 (size 8200)
# Argument list too long - Failed to create new process
# [1385] clone3() with flags says: -7 expected -7
ok 13 Arguments > page size
# Running test 'CLONE_ARGS_SIZE_VER0 in a new PID NS'
# [1385] Trying clone3() with flags 0x20000000 (size 64)
# I am the parent (1385). My child's pid is 1391
# I am the child, my PID is 1
# [1385] clone3() with flags says: 0 expected 0
ok 14 CLONE_ARGS_SIZE_VER0 in a new PID NS
# Running test 'CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS'
# [1385] Trying clone3() with flags 0x20000000 (size 56)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 15 CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS
# Running test 'sizeof(struct clone_args) + 8 in a new PID NS'
# [1385] Trying clone3() with flags 0x20000000 (size 96)
# I am the parent (1385). My child's pid is 1392
# I am the child, my PID is 1
# [1385] clone3() with flags says: 0 expected 0
ok 16 sizeof(struct clone_args) + 8 in a new PID NS
# Running test 'Arguments > page size in a new PID NS'
# [1385] Trying clone3() with flags 0x20000000 (size 8200)
# Argument list too long - Failed to create new process
# [1385] clone3() with flags says: -7 expected -7
ok 17 Arguments > page size in a new PID NS
# Time namespaces are not supported
ok 18 # SKIP New time NS
# Running test 'exit signal (SIGCHLD) in flags'
# [1385] Trying clone3() with flags 0x14 (size 0)
# Invalid argument - Failed to create new process
# [1385] clone3() with flags says: -22 expected -22
ok 19 exit signal (SIGCHLD) in flags
# 1 skipped test(s) detected. Consider enabling relevant config options to improve coverage.
# Totals: pass:18 fail:0 xfail:0 xpass:0 skip:1 error:0
root@raverin:/usr/src/linux/tools/testing/selftests/clone3#
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
2026-01-16 15:30 ` [PATCH 1/3] sparc: Synchronize user stack on fork and clone Ludwig Rydberg
2026-01-16 17:17 ` John Paul Adrian Glaubitz
@ 2026-01-17 6:57 ` John Paul Adrian Glaubitz
2026-01-17 7:00 ` John Paul Adrian Glaubitz
2026-01-17 12:18 ` Michael Karcher
1 sibling, 2 replies; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-17 6:57 UTC (permalink / raw)
To: Ludwig Rydberg, davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert,
schuster.simon, kernel
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
2026-01-17 6:57 ` John Paul Adrian Glaubitz
@ 2026-01-17 7:00 ` John Paul Adrian Glaubitz
2026-01-19 13:05 ` Ludwig Rydberg
2026-01-17 12:18 ` Michael Karcher
1 sibling, 1 reply; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-17 7:00 UTC (permalink / raw)
To: Ludwig Rydberg, davem, andreas, brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert,
schuster.simon, kernel
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
2026-01-17 6:57 ` John Paul Adrian Glaubitz
2026-01-17 7:00 ` John Paul Adrian Glaubitz
@ 2026-01-17 12:18 ` Michael Karcher
1 sibling, 0 replies; 17+ messages in thread
From: Michael Karcher @ 2026-01-17 12:18 UTC (permalink / raw)
To: John Paul Adrian Glaubitz, Ludwig Rydberg, davem, andreas,
brauner, shuah
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert, schuster.simon
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] sparc: Add architecture support for clone3
2026-01-16 16:47 ` Jessica Clarke
@ 2026-01-17 21:23 ` John Paul Adrian Glaubitz
2026-01-18 14:39 ` John Paul Adrian Glaubitz
2026-01-19 12:39 ` Ludwig Rydberg
1 sibling, 1 reply; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-17 21:23 UTC (permalink / raw)
To: Jessica Clarke, Ludwig Rydberg
Cc: davem, andreas, brauner, shuah, sparclinux, linux-kselftest,
linux-kernel, arnd, geert, schuster.simon
Hi,
On Fri, 2026-01-16 at 16:47 +0000, Jessica Clarke wrote:
> On Fri, Jan 16, 2026 at 04:30:50PM +0100, Ludwig Rydberg wrote:
> > Add support for the clone3 system call to the SPARC architectures.
> >
> > The implementation follows the pattern of the original clone syscall.
> > However, instead of explicitly calling kernel_clone, the clone3
> > handler calls the generic sys_clone3 handler in kernel/fork.
> > In case no stack is provided, the parents stack is reused.
> >
> > The return call conventions for clone on SPARC are kept for clone3:
> > Parent --> %o0 == child's pid, %o1 == 0
> > Child --> %o0 == parent's pid, %o1 == 1
>
> One of the benefits of having a new clone3 is that the interface can be
> made the same across all architectures*, unlike clone, which both passes
> the arguments in different orders for different architectures and, in
> the case of SPARC, has this weird return convention inherited from the
> SunOS syscall interface. Is there a good reason to deviate for clone3
> too and keep this annoying oddity going, that requires special-casing
> SPARC when other architectures can just syscall(__NR_clone3, ...)?
Very good point. Since clone3() is a new syscall, I think it would make more
sense to use the same interface as all the other architectures.
The weird syscall interface was already the reason why we had to write custom
code for systemd on SPARC in order to use the raw clone() syscall.
I think the proposed implementation of clone3() for SPARC would actually break
the libcamera build which calls clone3() using the syscall handler [1]:
FAILED: [code=1] src/libcamera/libcamera.so.0.6.0.p/process.cpp.o
c++ -Isrc/libcamera/libcamera.so.0.6.0.p -Isrc/libcamera -I../src/libcamera -Iinclude -I../include -Iinclude/libcamera -Iinclude/libcamera/ipa -Iinclude/libcamera/internal -Isrc/libcamera/proxy -
I/usr/include/p11-kit-1 -I/usr/include/sparc64-linux-gnu -fdiagnostics-color=always -D_GLIBCXX_ASSERTIONS=1 -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Werror -std=c++17 -Wnon-virtual-dtor -
Wno-redundant-move -Wmissing-declarations -Wshadow -include /build/reproducible-path/libcamera-0.6.0/obj-sparc64-linux-gnu/config.h -g -O2 -ffile-prefix-map=/build/reproducible-path/libcamera-0.6.0=.
-fstack-protector-strong -Wformat -Werror=format-security -Wno-error -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DLIBCAMERA_BASE_PRIVATE -MD -MQ src/libcamera/libcamera.so.0.6.0.p/process.cpp.o -MF
src/libcamera/libcamera.so.0.6.0.p/process.cpp.o.d -o src/libcamera/libcamera.so.0.6.0.p/process.cpp.o -c ../src/libcamera/process.cpp
../src/libcamera/process.cpp: In member function ‘int libcamera::Process::start(const std::string&, libcamera::Span<const std::__cxx11::basic_string<char> >, libcamera::Span<const int>)’:
../src/libcamera/process.cpp:160:33: error: ‘SYS_clone3’ was not declared in this scope; did you mean ‘SYS_clone’?
160 | long childPid = syscall(SYS_clone3, &cargs, sizeof(cargs));
| ^~~~~~~~~~
| SYS_clone
I'll verify that and report back.
Adrian
> [1] https://buildd.debian.org/status/fetch.php?pkg=libcamera&arch=sparc64&ver=0.6.0-2&stamp=1766489678&raw=0
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer
`. `' Physicist
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] sparc: Add architecture support for clone3
2026-01-17 21:23 ` John Paul Adrian Glaubitz
@ 2026-01-18 14:39 ` John Paul Adrian Glaubitz
0 siblings, 0 replies; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-18 14:39 UTC (permalink / raw)
To: Jessica Clarke, Ludwig Rydberg
Cc: davem, andreas, brauner, shuah, sparclinux, linux-kselftest,
linux-kernel, arnd, geert, schuster.simon
Hi,
On Sat, 2026-01-17 at 22:23 +0100, John Paul Adrian Glaubitz wrote:
> Hi,
>
> On Fri, 2026-01-16 at 16:47 +0000, Jessica Clarke wrote:
> > On Fri, Jan 16, 2026 at 04:30:50PM +0100, Ludwig Rydberg wrote:
> > > Add support for the clone3 system call to the SPARC architectures.
> > >
> > > The implementation follows the pattern of the original clone syscall.
> > > However, instead of explicitly calling kernel_clone, the clone3
> > > handler calls the generic sys_clone3 handler in kernel/fork.
> > > In case no stack is provided, the parents stack is reused.
> > >
> > > The return call conventions for clone on SPARC are kept for clone3:
> > > Parent --> %o0 == child's pid, %o1 == 0
> > > Child --> %o0 == parent's pid, %o1 == 1
> >
> > One of the benefits of having a new clone3 is that the interface can be
> > made the same across all architectures*, unlike clone, which both passes
> > the arguments in different orders for different architectures and, in
> > the case of SPARC, has this weird return convention inherited from the
> > SunOS syscall interface. Is there a good reason to deviate for clone3
> > too and keep this annoying oddity going, that requires special-casing
> > SPARC when other architectures can just syscall(__NR_clone3, ...)?
>
> Very good point. Since clone3() is a new syscall, I think it would make more
> sense to use the same interface as all the other architectures.
>
> The weird syscall interface was already the reason why we had to write custom
> code for systemd on SPARC in order to use the raw clone() syscall.
>
> I think the proposed implementation of clone3() for SPARC would actually break
> the libcamera build which calls clone3() using the syscall handler [1]:
>
> FAILED: [code=1] src/libcamera/libcamera.so.0.6.0.p/process.cpp.o
> c++ -Isrc/libcamera/libcamera.so.0.6.0.p -Isrc/libcamera -I../src/libcamera -Iinclude -I../include -Iinclude/libcamera -Iinclude/libcamera/ipa -Iinclude/libcamera/internal -Isrc/libcamera/proxy -
> I/usr/include/p11-kit-1 -I/usr/include/sparc64-linux-gnu -fdiagnostics-color=always -D_GLIBCXX_ASSERTIONS=1 -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Werror -std=c++17 -Wnon-virtual-dtor -
> Wno-redundant-move -Wmissing-declarations -Wshadow -include /build/reproducible-path/libcamera-0.6.0/obj-sparc64-linux-gnu/config.h -g -O2 -ffile-prefix-map=/build/reproducible-path/libcamera-0.6.0=.
> -fstack-protector-strong -Wformat -Werror=format-security -Wno-error -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DLIBCAMERA_BASE_PRIVATE -MD -MQ src/libcamera/libcamera.so.0.6.0.p/process.cpp.o -MF
> src/libcamera/libcamera.so.0.6.0.p/process.cpp.o.d -o src/libcamera/libcamera.so.0.6.0.p/process.cpp.o -c ../src/libcamera/process.cpp
> ../src/libcamera/process.cpp: In member function ‘int libcamera::Process::start(const std::string&, libcamera::Span<const std::__cxx11::basic_string<char> >, libcamera::Span<const int>)’:
> ../src/libcamera/process.cpp:160:33: error: ‘SYS_clone3’ was not declared in this scope; did you mean ‘SYS_clone’?
> 160 | long childPid = syscall(SYS_clone3, &cargs, sizeof(cargs));
> | ^~~~~~~~~~
> | SYS_clone
>
> I'll verify that and report back.
I can confirm that libcamera builds fine and passes its testsuite with a patched kernel:
Ok: 38
Expected Fail: 1
Fail: 0
Skipped: 31
Full log written to /home/glaubitz/libcamera/libcamera-0.6.0/obj-sparc64-linux-gnu/meson-logs/testlog.txt
make[1]: Leaving directory '/home/glaubitz/libcamera/libcamera-0.6.0'
Whether the currently chosen interface is the right one, is another question though.
Adrian
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer
`. `' Physicist
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] sparc: Add architecture support for clone3
2026-01-16 16:47 ` Jessica Clarke
2026-01-17 21:23 ` John Paul Adrian Glaubitz
@ 2026-01-19 12:39 ` Ludwig Rydberg
1 sibling, 0 replies; 17+ messages in thread
From: Ludwig Rydberg @ 2026-01-19 12:39 UTC (permalink / raw)
To: Jessica Clarke
Cc: davem, andreas, brauner, shuah, sparclinux, linux-kselftest,
linux-kernel, arnd, glaubitz, geert, schuster.simon
Hi Jessica,
> One of the benefits of having a new clone3 is that the interface can be
> made the same across all architectures*, unlike clone, which both passes
> the arguments in different orders for different architectures and, in
> the case of SPARC, has this weird return convention inherited from the
> SunOS syscall interface. Is there a good reason to deviate for clone3
> too and keep this annoying oddity going, that requires special-casing
> SPARC when other architectures can just syscall(__NR_clone3, ...)?
>
Thanks for commenting on this. No, you're right (there is no good reason).
The original implementation just followed how things were but I have a v2
coming up which will follow the regular kernel return value conventions.
This will ensure that syscall(__NR_clone3, ...) works on SPARC exactly
as it does on other architectures (i.e I'll drop the third patch in the
series).
Best regards,
// Ludwig
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
2026-01-17 7:00 ` John Paul Adrian Glaubitz
@ 2026-01-19 13:05 ` Ludwig Rydberg
2026-01-20 7:57 ` John Paul Adrian Glaubitz
0 siblings, 1 reply; 17+ messages in thread
From: Ludwig Rydberg @ 2026-01-19 13:05 UTC (permalink / raw)
To: John Paul Adrian Glaubitz, kernel
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert,
schuster.simon, davem, andreas, brauner, shuah
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] sparc: Synchronize user stack on fork and clone
2026-01-19 13:05 ` Ludwig Rydberg
@ 2026-01-20 7:57 ` John Paul Adrian Glaubitz
0 siblings, 0 replies; 17+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-01-20 7:57 UTC (permalink / raw)
To: Ludwig Rydberg, kernel
Cc: sparclinux, linux-kselftest, linux-kernel, arnd, geert,
schuster.simon, davem, andreas, brauner, shuah
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
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-01-20 7:57 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-16 15:30 [PATCH 0/3] sparc: Add architecture support for clone3 Ludwig Rydberg
2026-01-16 15:30 ` [PATCH 1/3] sparc: Synchronize user stack on fork and clone Ludwig Rydberg
2026-01-16 17:17 ` John Paul Adrian Glaubitz
2026-01-17 6:57 ` John Paul Adrian Glaubitz
2026-01-17 7:00 ` John Paul Adrian Glaubitz
2026-01-19 13:05 ` Ludwig Rydberg
2026-01-20 7:57 ` John Paul Adrian Glaubitz
2026-01-17 12:18 ` Michael Karcher
2026-01-16 15:30 ` [PATCH 2/3] sparc: Add architecture support for clone3 Ludwig Rydberg
2026-01-16 16:47 ` Jessica Clarke
2026-01-17 21:23 ` John Paul Adrian Glaubitz
2026-01-18 14:39 ` John Paul Adrian Glaubitz
2026-01-19 12:39 ` Ludwig Rydberg
2026-01-16 17:19 ` John Paul Adrian Glaubitz
2026-01-16 15:30 ` [PATCH 3/3] selftests/clone3: Add sys_clone3 wrapper for SPARC Ludwig Rydberg
2026-01-16 15:44 ` [PATCH 0/3] sparc: Add architecture support for clone3 John Paul Adrian Glaubitz
2026-01-16 16:26 ` John Paul Adrian Glaubitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®