1/* SPDX-License-Identifier: GPL-2.0 */
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <sched.h>
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11#include <linux/sched.h>
12#include <linux/types.h>
13#include <sys/syscall.h>
14#include <sys/wait.h>
15
16#include "../kselftest.h"
17#include "clone3_selftests.h"
18
19static void nop_handler(int signo)
20{
21}
22
23static int wait_for_pid(pid_t pid)
24{
25	int status, ret;
26
27again:
28	ret = waitpid(pid, &status, 0);
29	if (ret == -1) {
30		if (errno == EINTR)
31			goto again;
32
33		return -1;
34	}
35
36	if (!WIFEXITED(status))
37		return -1;
38
39	return WEXITSTATUS(status);
40}
41
42static void test_clone3_clear_sighand(void)
43{
44	int ret;
45	pid_t pid;
46	struct __clone_args args = {};
47	struct sigaction act;
48
49	/*
50	 * Check that CLONE_CLEAR_SIGHAND and CLONE_SIGHAND are mutually
51	 * exclusive.
52	 */
53	args.flags |= CLONE_CLEAR_SIGHAND | CLONE_SIGHAND;
54	args.exit_signal = SIGCHLD;
55	pid = sys_clone3(&args, sizeof(args));
56	if (pid > 0)
57		ksft_exit_fail_msg(
58			"clone3(CLONE_CLEAR_SIGHAND | CLONE_SIGHAND) succeeded\n");
59
60	act.sa_handler = nop_handler;
61	ret = sigemptyset(&act.sa_mask);
62	if (ret < 0)
63		ksft_exit_fail_msg("%s - sigemptyset() failed\n",
64				   strerror(errno));
65
66	act.sa_flags = 0;
67
68	/* Register signal handler for SIGUSR1 */
69	ret = sigaction(SIGUSR1, &act, NULL);
70	if (ret < 0)
71		ksft_exit_fail_msg(
72			"%s - sigaction(SIGUSR1, &act, NULL) failed\n",
73			strerror(errno));
74
75	/* Register signal handler for SIGUSR2 */
76	ret = sigaction(SIGUSR2, &act, NULL);
77	if (ret < 0)
78		ksft_exit_fail_msg(
79			"%s - sigaction(SIGUSR2, &act, NULL) failed\n",
80			strerror(errno));
81
82	/* Check that CLONE_CLEAR_SIGHAND works. */
83	args.flags = CLONE_CLEAR_SIGHAND;
84	pid = sys_clone3(&args, sizeof(args));
85	if (pid < 0)
86		ksft_exit_fail_msg("%s - clone3(CLONE_CLEAR_SIGHAND) failed\n",
87				   strerror(errno));
88
89	if (pid == 0) {
90		ret = sigaction(SIGUSR1, NULL, &act);
91		if (ret < 0)
92			exit(EXIT_FAILURE);
93
94		if (act.sa_handler != SIG_DFL)
95			exit(EXIT_FAILURE);
96
97		ret = sigaction(SIGUSR2, NULL, &act);
98		if (ret < 0)
99			exit(EXIT_FAILURE);
100
101		if (act.sa_handler != SIG_DFL)
102			exit(EXIT_FAILURE);
103
104		exit(EXIT_SUCCESS);
105	}
106
107	ret = wait_for_pid(pid);
108	if (ret)
109		ksft_exit_fail_msg(
110			"Failed to clear signal handler for child process\n");
111
112	ksft_test_result_pass("Cleared signal handlers for child process\n");
113}
114
115int main(int argc, char **argv)
116{
117	ksft_print_header();
118	ksft_set_plan(1);
119	test_clone3_supported();
120
121	test_clone3_clear_sighand();
122
123	return ksft_exit_pass();
124}
125