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-44cf2daf2...@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-53fcf5577...@siemens-energy.com/
> [4]: 
> https://lore.kernel.org/all/[email protected]/
> 
> 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 <[email protected]>

Thanks,
Adrian

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

Reply via email to