Skip to content

Commit de52872

Browse files
author
Christian Brauner
committed
tests: test CLONE_CLEAR_SIGHAND
Test that CLONE_CLEAR_SIGHAND resets signal handlers to SIG_DFL for the child process and that CLONE_CLEAR_SIGHAND and CLONE_SIGHAND are mutually exclusive. Cc: Florian Weimer <[email protected]> Cc: [email protected] Cc: [email protected] Signed-off-by: Christian Brauner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b612e5d commit de52872

File tree

5 files changed

+181
-0
lines changed

5 files changed

+181
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12826,6 +12826,7 @@ S: Maintained
1282612826
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git
1282712827
F: samples/pidfd/
1282812828
F: tools/testing/selftests/pidfd/
12829+
F: tools/testing/selftests/clone3/
1282912830
K: (?i)pidfd
1283012831
K: (?i)clone3
1283112832
K: \b(clone_args|kernel_clone_args)\b

tools/testing/selftests/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ TARGETS += bpf
44
TARGETS += breakpoints
55
TARGETS += capabilities
66
TARGETS += cgroup
7+
TARGETS += clone3
78
TARGETS += cpufreq
89
TARGETS += cpu-hotplug
910
TARGETS += drivers/dma-buf
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
clone3_clear_sighand
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
CFLAGS += -g -I../../../../usr/include/
3+
4+
TEST_GEN_PROGS := clone3_clear_sighand
5+
6+
include ../lib.mk
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
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+
18+
#ifndef CLONE_CLEAR_SIGHAND
19+
#define CLONE_CLEAR_SIGHAND 0x100000000ULL
20+
#endif
21+
22+
#ifndef __NR_clone3
23+
#define __NR_clone3 -1
24+
struct clone_args {
25+
__aligned_u64 flags;
26+
__aligned_u64 pidfd;
27+
__aligned_u64 child_tid;
28+
__aligned_u64 parent_tid;
29+
__aligned_u64 exit_signal;
30+
__aligned_u64 stack;
31+
__aligned_u64 stack_size;
32+
__aligned_u64 tls;
33+
};
34+
#endif
35+
36+
static pid_t sys_clone3(struct clone_args *args, size_t size)
37+
{
38+
return syscall(__NR_clone3, args, size);
39+
}
40+
41+
static void test_clone3_supported(void)
42+
{
43+
pid_t pid;
44+
struct clone_args args = {};
45+
46+
if (__NR_clone3 < 0)
47+
ksft_exit_skip("clone3() syscall is not supported\n");
48+
49+
/* Set to something that will always cause EINVAL. */
50+
args.exit_signal = -1;
51+
pid = sys_clone3(&args, sizeof(args));
52+
if (!pid)
53+
exit(EXIT_SUCCESS);
54+
55+
if (pid > 0) {
56+
wait(NULL);
57+
ksft_exit_fail_msg(
58+
"Managed to create child process with invalid exit_signal\n");
59+
}
60+
61+
if (errno == ENOSYS)
62+
ksft_exit_skip("clone3() syscall is not supported\n");
63+
64+
ksft_print_msg("clone3() syscall supported\n");
65+
}
66+
67+
static void nop_handler(int signo)
68+
{
69+
}
70+
71+
static int wait_for_pid(pid_t pid)
72+
{
73+
int status, ret;
74+
75+
again:
76+
ret = waitpid(pid, &status, 0);
77+
if (ret == -1) {
78+
if (errno == EINTR)
79+
goto again;
80+
81+
return -1;
82+
}
83+
84+
if (!WIFEXITED(status))
85+
return -1;
86+
87+
return WEXITSTATUS(status);
88+
}
89+
90+
static void test_clone3_clear_sighand(void)
91+
{
92+
int ret;
93+
pid_t pid;
94+
struct clone_args args = {};
95+
struct sigaction act;
96+
97+
/*
98+
* Check that CLONE_CLEAR_SIGHAND and CLONE_SIGHAND are mutually
99+
* exclusive.
100+
*/
101+
args.flags |= CLONE_CLEAR_SIGHAND | CLONE_SIGHAND;
102+
args.exit_signal = SIGCHLD;
103+
pid = sys_clone3(&args, sizeof(args));
104+
if (pid > 0)
105+
ksft_exit_fail_msg(
106+
"clone3(CLONE_CLEAR_SIGHAND | CLONE_SIGHAND) succeeded\n");
107+
108+
act.sa_handler = nop_handler;
109+
ret = sigemptyset(&act.sa_mask);
110+
if (ret < 0)
111+
ksft_exit_fail_msg("%s - sigemptyset() failed\n",
112+
strerror(errno));
113+
114+
act.sa_flags = 0;
115+
116+
/* Register signal handler for SIGUSR1 */
117+
ret = sigaction(SIGUSR1, &act, NULL);
118+
if (ret < 0)
119+
ksft_exit_fail_msg(
120+
"%s - sigaction(SIGUSR1, &act, NULL) failed\n",
121+
strerror(errno));
122+
123+
/* Register signal handler for SIGUSR2 */
124+
ret = sigaction(SIGUSR2, &act, NULL);
125+
if (ret < 0)
126+
ksft_exit_fail_msg(
127+
"%s - sigaction(SIGUSR2, &act, NULL) failed\n",
128+
strerror(errno));
129+
130+
/* Check that CLONE_CLEAR_SIGHAND works. */
131+
args.flags = CLONE_CLEAR_SIGHAND;
132+
pid = sys_clone3(&args, sizeof(args));
133+
if (pid < 0)
134+
ksft_exit_fail_msg("%s - clone3(CLONE_CLEAR_SIGHAND) failed\n",
135+
strerror(errno));
136+
137+
if (pid == 0) {
138+
ret = sigaction(SIGUSR1, NULL, &act);
139+
if (ret < 0)
140+
exit(EXIT_FAILURE);
141+
142+
if (act.sa_handler != SIG_DFL)
143+
exit(EXIT_FAILURE);
144+
145+
ret = sigaction(SIGUSR2, NULL, &act);
146+
if (ret < 0)
147+
exit(EXIT_FAILURE);
148+
149+
if (act.sa_handler != SIG_DFL)
150+
exit(EXIT_FAILURE);
151+
152+
exit(EXIT_SUCCESS);
153+
}
154+
155+
ret = wait_for_pid(pid);
156+
if (ret)
157+
ksft_exit_fail_msg(
158+
"Failed to clear signal handler for child process\n");
159+
160+
ksft_test_result_pass("Cleared signal handlers for child process\n");
161+
}
162+
163+
int main(int argc, char **argv)
164+
{
165+
ksft_print_header();
166+
ksft_set_plan(1);
167+
168+
test_clone3_supported();
169+
test_clone3_clear_sighand();
170+
171+
return ksft_exit_pass();
172+
}

0 commit comments

Comments
 (0)