* [PATCH 0/2] kselftest/arm64: Add coverage for the interaction of vfork() and GCS
@ 2025-06-09 15:08 Mark Brown
2025-06-09 15:08 ` [PATCH 1/2] tools/nolibc: Provide vfork() Mark Brown
2025-06-09 15:08 ` [PATCH 2/2] kselftest/arm64: Add a test for vfork() with GCS Mark Brown
0 siblings, 2 replies; 7+ messages in thread
From: Mark Brown @ 2025-06-09 15:08 UTC (permalink / raw)
To: Willy Tarreau, Thomas Weißschuh, Christian Brauner,
Catalin Marinas, Will Deacon, Shuah Khan
Cc: linux-kernel, linux-arm-kernel, linux-kselftest, Mark Brown
I had cause to look at the vfork() support for GCS and realised that we
don't have any direct test coverage, this series does so by adding
vfork() to nolibc and then using that in basic-gcs to provide some
simple vfork() coverage.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Mark Brown (2):
tools/nolibc: Provide vfork()
kselftest/arm64: Add a test for vfork() with GCS
tools/include/nolibc/sys.h | 29 ++++++++++++
tools/testing/selftests/arm64/gcs/basic-gcs.c | 63 +++++++++++++++++++++++++++
2 files changed, 92 insertions(+)
---
base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
change-id: 20250528-arm64-gcs-vfork-exit-4a7daf7652ee
Best regards,
--
Mark Brown <broonie@kernel.org>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] tools/nolibc: Provide vfork()
2025-06-09 15:08 [PATCH 0/2] kselftest/arm64: Add coverage for the interaction of vfork() and GCS Mark Brown
@ 2025-06-09 15:08 ` Mark Brown
2025-06-09 15:25 ` Thomas Weißschuh
2025-06-09 15:34 ` Thomas Weißschuh
2025-06-09 15:08 ` [PATCH 2/2] kselftest/arm64: Add a test for vfork() with GCS Mark Brown
1 sibling, 2 replies; 7+ messages in thread
From: Mark Brown @ 2025-06-09 15:08 UTC (permalink / raw)
To: Willy Tarreau, Thomas Weißschuh, Christian Brauner,
Catalin Marinas, Will Deacon, Shuah Khan
Cc: linux-kernel, linux-arm-kernel, linux-kselftest, Mark Brown
To allow testing of vfork() support in the arm64 basic-gcs test provide an
implementation for nolibc, using the vfork() syscall if one is available
and otherwise clone3(). We implement in terms of clone3() since the order
of the arguments for clone() varies between architectures.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/include/nolibc/sys.h | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 9556c69a6ae1..e056da010f64 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -22,6 +22,7 @@
#include <linux/time.h>
#include <linux/auxvec.h>
#include <linux/fcntl.h> /* for O_* and AT_* */
+#include <linux/sched.h> /* for clone_args */
#include <linux/stat.h> /* for statx() */
#include "errno.h"
@@ -340,6 +341,34 @@ pid_t fork(void)
return __sysret(sys_fork());
}
+#ifndef sys_vfork
+static __attribute__((unused))
+pid_t sys_vfork(void)
+{
+#ifdef __NR_vfork
+ return my_syscall0(__NR_vfork);
+#elif defined(__NR_clone3)
+ /*
+ * clone() could be used but has different argument orders per
+ * architecture.
+ */
+ struct clone_args args = {
+ .flags = CLONE_VM | CLONE_VFORK,
+ .exit_signal = SIGCHLD,
+ };
+
+ return my_syscall2(__NR_clone3, &args, sizeof(args));
+#else
+ return __nolibc_enosys(__func__);
+#endif
+}
+#endif
+
+static __attribute__((unused))
+pid_t vfork(void)
+{
+ return __sysret(sys_vfork());
+}
/*
* int fsync(int fd);
--
2.39.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] kselftest/arm64: Add a test for vfork() with GCS
2025-06-09 15:08 [PATCH 0/2] kselftest/arm64: Add coverage for the interaction of vfork() and GCS Mark Brown
2025-06-09 15:08 ` [PATCH 1/2] tools/nolibc: Provide vfork() Mark Brown
@ 2025-06-09 15:08 ` Mark Brown
1 sibling, 0 replies; 7+ messages in thread
From: Mark Brown @ 2025-06-09 15:08 UTC (permalink / raw)
To: Willy Tarreau, Thomas Weißschuh, Christian Brauner,
Catalin Marinas, Will Deacon, Shuah Khan
Cc: linux-kernel, linux-arm-kernel, linux-kselftest, Mark Brown
Ensure that we've got at least some coverage of the special cases around
vfork() by adding a test case in basic-gcs doing the same thing as the
plain fork() one - vfork(), do a few checks and then return to the parent.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/arm64/gcs/basic-gcs.c | 63 +++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/tools/testing/selftests/arm64/gcs/basic-gcs.c b/tools/testing/selftests/arm64/gcs/basic-gcs.c
index 3fb9742342a3..96ea51cf7163 100644
--- a/tools/testing/selftests/arm64/gcs/basic-gcs.c
+++ b/tools/testing/selftests/arm64/gcs/basic-gcs.c
@@ -298,6 +298,68 @@ static bool test_fork(void)
return pass;
}
+/* A vfork()ed process can run and exit */
+static bool test_vfork(void)
+{
+ unsigned long child_mode;
+ int ret, status;
+ pid_t pid;
+ bool pass = true;
+
+ pid = vfork();
+ if (pid == -1) {
+ ksft_print_msg("vfork() failed: %d\n", errno);
+ pass = false;
+ goto out;
+ }
+ if (pid == 0) {
+ /* In child, make sure we can call a function, read
+ * the GCS pointer and status and then exit */
+ valid_gcs_function();
+ get_gcspr();
+
+ ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
+ &child_mode, 0, 0, 0);
+ if (ret == 0 && !(child_mode & PR_SHADOW_STACK_ENABLE)) {
+ ksft_print_msg("GCS not enabled in child\n");
+ ret = -EINVAL;
+ }
+
+ exit(ret);
+ }
+
+ /*
+ * In parent, check we can still do function calls then block
+ * for the child.
+ */
+ valid_gcs_function();
+
+ ksft_print_msg("Waiting for child %d\n", pid);
+
+ ret = waitpid(pid, &status, 0);
+ if (ret == -1) {
+ ksft_print_msg("Failed to wait for child: %d\n",
+ errno);
+ return false;
+ }
+
+ if (!WIFEXITED(status)) {
+ ksft_print_msg("Child exited due to signal %d\n",
+ WTERMSIG(status));
+ pass = false;
+ } else {
+ if (WEXITSTATUS(status)) {
+ ksft_print_msg("Child exited with status %d\n",
+ WEXITSTATUS(status));
+ pass = false;
+ }
+ }
+
+out:
+
+ return pass;
+}
+
typedef bool (*gcs_test)(void);
static struct {
@@ -314,6 +376,7 @@ static struct {
{ "enable_invalid", enable_invalid, true },
{ "map_guarded_stack", map_guarded_stack },
{ "fork", test_fork },
+ { "vfork", test_vfork },
};
int main(void)
--
2.39.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] tools/nolibc: Provide vfork()
2025-06-09 15:08 ` [PATCH 1/2] tools/nolibc: Provide vfork() Mark Brown
@ 2025-06-09 15:25 ` Thomas Weißschuh
2025-06-09 15:34 ` Thomas Weißschuh
1 sibling, 0 replies; 7+ messages in thread
From: Thomas Weißschuh @ 2025-06-09 15:25 UTC (permalink / raw)
To: Mark Brown
Cc: Willy Tarreau, Christian Brauner, Catalin Marinas, Will Deacon,
Shuah Khan, linux-kernel, linux-arm-kernel, linux-kselftest
Hi Mark,
On 2025-06-09 16:08:56+0100, Mark Brown wrote:
> To allow testing of vfork() support in the arm64 basic-gcs test provide an
> implementation for nolibc, using the vfork() syscall if one is available
> and otherwise clone3(). We implement in terms of clone3() since the order
> of the arguments for clone() varies between architectures.
Thanks for the patch!
Do you want to take this series through your tree?
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
> tools/include/nolibc/sys.h | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
> index 9556c69a6ae1..e056da010f64 100644
> --- a/tools/include/nolibc/sys.h
> +++ b/tools/include/nolibc/sys.h
> @@ -22,6 +22,7 @@
> #include <linux/time.h>
> #include <linux/auxvec.h>
> #include <linux/fcntl.h> /* for O_* and AT_* */
> +#include <linux/sched.h> /* for clone_args */
> #include <linux/stat.h> /* for statx() */
>
> #include "errno.h"
> @@ -340,6 +341,34 @@ pid_t fork(void)
> return __sysret(sys_fork());
> }
>
> +#ifndef sys_vfork
> +static __attribute__((unused))
> +pid_t sys_vfork(void)
> +{
> +#ifdef __NR_vfork
> + return my_syscall0(__NR_vfork);
> +#elif defined(__NR_clone3)
> + /*
> + * clone() could be used but has different argument orders per
> + * architecture.
> + */
> + struct clone_args args = {
> + .flags = CLONE_VM | CLONE_VFORK,
> + .exit_signal = SIGCHLD,
> + };
> +
> + return my_syscall2(__NR_clone3, &args, sizeof(args));
> +#else
> + return __nolibc_enosys(__func__);
> +#endif
> +}
> +#endif
> +
> +static __attribute__((unused))
> +pid_t vfork(void)
> +{
> + return __sysret(sys_vfork());
> +}
Could you also add a test to nolibc-test.c?
Maybe extend test_fork() with a flag to use either fork() or vfork().
And maybe change the exit() in the test to _exit(); not that it would
make a difference for nolibc (yet).
>
> /*
> * int fsync(int fd);
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] tools/nolibc: Provide vfork()
2025-06-09 15:08 ` [PATCH 1/2] tools/nolibc: Provide vfork() Mark Brown
2025-06-09 15:25 ` Thomas Weißschuh
@ 2025-06-09 15:34 ` Thomas Weißschuh
2025-06-09 15:43 ` Mark Brown
1 sibling, 1 reply; 7+ messages in thread
From: Thomas Weißschuh @ 2025-06-09 15:34 UTC (permalink / raw)
To: Mark Brown
Cc: Willy Tarreau, Christian Brauner, Catalin Marinas, Will Deacon,
Shuah Khan, linux-kernel, linux-arm-kernel, linux-kselftest
Small followup review, sorry for the noise.
On 2025-06-09 16:08:56+0100, Mark Brown wrote:
<snip>
> +#ifndef sys_vfork
This ifndef is not necessary here.
No architecture has a special version.
> +static __attribute__((unused))
> +pid_t sys_vfork(void)
> +{
> +#ifdef __NR_vfork
For consistency:
#if defined(__NR_vfork)
> + return my_syscall0(__NR_vfork);
> +#elif defined(__NR_clone3)
> + /*
> + * clone() could be used but has different argument orders per
> + * architecture.
> + */
> + struct clone_args args = {
> + .flags = CLONE_VM | CLONE_VFORK,
> + .exit_signal = SIGCHLD,
> + };
> +
> + return my_syscall2(__NR_clone3, &args, sizeof(args));
> +#else
> + return __nolibc_enosys(__func__);
> +#endif
> +}
> +#endif
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] tools/nolibc: Provide vfork()
2025-06-09 15:34 ` Thomas Weißschuh
@ 2025-06-09 15:43 ` Mark Brown
2025-06-09 15:51 ` Thomas Weißschuh
0 siblings, 1 reply; 7+ messages in thread
From: Mark Brown @ 2025-06-09 15:43 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Willy Tarreau, Christian Brauner, Catalin Marinas, Will Deacon,
Shuah Khan, linux-kernel, linux-arm-kernel, linux-kselftest
[-- Attachment #1: Type: text/plain, Size: 642 bytes --]
On Mon, Jun 09, 2025 at 05:34:33PM +0200, Thomas Weißschuh wrote:
> On 2025-06-09 16:08:56+0100, Mark Brown wrote:
> > +#ifndef sys_vfork
> This ifndef is not necessary here.
> No architecture has a special version.
Ah, I was adding it defensively in case it was needed in future.
> > +static __attribute__((unused))
> > +pid_t sys_vfork(void)
> > +{
> > +#ifdef __NR_vfork
> For consistency:
> #if defined(__NR_vfork)
Are you sure? I'm seeing an awful lot of #ifdef __NR_foo instances in
sys.h - it looks like the idiom is to use that unless it either needs an
additional condition (with || or &&) or is an elif.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] tools/nolibc: Provide vfork()
2025-06-09 15:43 ` Mark Brown
@ 2025-06-09 15:51 ` Thomas Weißschuh
0 siblings, 0 replies; 7+ messages in thread
From: Thomas Weißschuh @ 2025-06-09 15:51 UTC (permalink / raw)
To: Mark Brown
Cc: Willy Tarreau, Christian Brauner, Catalin Marinas, Will Deacon,
Shuah Khan, linux-kernel, linux-arm-kernel, linux-kselftest
On 2025-06-09 16:43:55+0100, Mark Brown wrote:
> On Mon, Jun 09, 2025 at 05:34:33PM +0200, Thomas Weißschuh wrote:
> > On 2025-06-09 16:08:56+0100, Mark Brown wrote:
<snip>
> > > +static __attribute__((unused))
> > > +pid_t sys_vfork(void)
> > > +{
> > > +#ifdef __NR_vfork
>
> > For consistency:
> > #if defined(__NR_vfork)
>
> Are you sure? I'm seeing an awful lot of #ifdef __NR_foo instances in
> sys.h - it looks like the idiom is to use that unless it either needs an
> additional condition (with || or &&) or is an elif.
In sys.h, indeed. These have mostly grown historically, newer ones use
#if defined() together with #elif defined().
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-06-09 17:15 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-09 15:08 [PATCH 0/2] kselftest/arm64: Add coverage for the interaction of vfork() and GCS Mark Brown
2025-06-09 15:08 ` [PATCH 1/2] tools/nolibc: Provide vfork() Mark Brown
2025-06-09 15:25 ` Thomas Weißschuh
2025-06-09 15:34 ` Thomas Weißschuh
2025-06-09 15:43 ` Mark Brown
2025-06-09 15:51 ` Thomas Weißschuh
2025-06-09 15:08 ` [PATCH 2/2] kselftest/arm64: Add a test for vfork() with GCS Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox