kselftest/arm64: Add a test for vfork() with GCS

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>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20250703-arm64-gcs-vfork-exit-v3-3-1e9a9d2ddbbe@kernel.org
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
This commit is contained in:
Mark Brown 2025-07-03 17:00:17 +01:00 committed by Thomas Weißschuh
parent 696bf15792
commit 1536aa0fb1

View file

@ -298,6 +298,68 @@ out:
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 = EXIT_FAILURE;
}
_exit(ret);
}
/*
* In parent, check we can still do function calls then check
* on 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)