• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org>
4  *
5  * Basic clone3() test.
6  */
7 #define _GNU_SOURCE
8 
9 #include <stdlib.h>
10 #include <sys/wait.h>
11 
12 #include "tst_test.h"
13 #include "lapi/clone.h"
14 #include "lapi/pidfd_send_signal.h"
15 
16 #define CHILD_SIGNAL	SIGUSR1
17 #define DATA	777
18 
19 static int pidfd, child_tid, parent_tid, parent_received_signal;
20 static volatile int child_received_signal, child_data;
21 static struct clone_args *args;
22 
23 static struct tcase {
24 	uint64_t flags;
25 	int exit_signal;
26 } tcases[] = {
27 	{0, SIGCHLD},
28 	{0, SIGUSR2},
29 	{CLONE_FS, SIGCHLD},
30 	{CLONE_NEWPID, SIGCHLD},
31 	{CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD, SIGCHLD},
32 };
33 
parent_rx_signal(int sig)34 static void parent_rx_signal(int sig)
35 {
36 	parent_received_signal = sig;
37 }
38 
child_rx_signal(int sig,siginfo_t * info,void * ucontext)39 static void child_rx_signal(int sig, siginfo_t *info, void *ucontext)
40 {
41 	(void) ucontext;
42 
43 	child_received_signal = sig;
44 	child_data = info->si_value.sival_int;
45 }
46 
47 static struct sigaction psig_action = {
48 	.sa_handler = parent_rx_signal,
49 };
50 
51 static struct sigaction csig_action = {
52 	.sa_sigaction = child_rx_signal,
53 	.sa_flags = SA_SIGINFO,
54 };
55 
56 static siginfo_t uinfo = {
57 	.si_signo = CHILD_SIGNAL,
58 	.si_code = SI_QUEUE,
59 	.si_value.sival_int = DATA,
60 };
61 
62 
do_child(int clone_pidfd)63 static void do_child(int clone_pidfd)
64 {
65 	int count = 1000;
66 
67 	if (clone_pidfd) {
68 		child_received_signal = 0;
69 		child_data = 0;
70 
71 		SAFE_SIGACTION(CHILD_SIGNAL, &csig_action, NULL);
72 
73 		TST_CHECKPOINT_WAKE(0);
74 
75 		while (child_received_signal != CHILD_SIGNAL && --count)
76 			usleep(100);
77 
78 		if (!child_received_signal) {
79 			tst_res(TFAIL, "Child haven't got signal");
80 			exit(0);
81 		}
82 
83 		if (child_received_signal != CHILD_SIGNAL) {
84 			tst_res(TFAIL, "Child got %s (%i) signal expected %s",
85 				tst_strsig(child_received_signal),
86 				child_received_signal,
87 				tst_strsig(CHILD_SIGNAL));
88 			exit(0);
89 		}
90 
91 		tst_res(TPASS, "Child got correct signal %s",
92 			tst_strsig(CHILD_SIGNAL));
93 
94 		if (child_data != DATA) {
95 			tst_res(TFAIL, "Child got wrong si_value=%i expected %i",
96 				child_data, DATA);
97 		} else {
98 			tst_res(TPASS, "Child got correct si_value");
99 		}
100 	}
101 
102 	exit(0);
103 }
104 
run(unsigned int n)105 static void run(unsigned int n)
106 {
107 	struct tcase *tc = &tcases[n];
108 	int status, clone_pidfd = tc->flags & CLONE_PIDFD;
109 	pid_t pid;
110 
111 	args->flags = tc->flags;
112 	args->pidfd = (uint64_t)(&pidfd);
113 	args->child_tid = (uint64_t)(&child_tid);
114 	args->parent_tid = (uint64_t)(&parent_tid);
115 	args->exit_signal = tc->exit_signal;
116 	args->stack = 0;
117 	args->stack_size = 0;
118 	args->tls = 0;
119 
120 	parent_received_signal = 0;
121 	SAFE_SIGACTION(tc->exit_signal, &psig_action, NULL);
122 
123 	TEST(pid = clone3(args, sizeof(*args)));
124 	if (pid < 0) {
125 		tst_res(TFAIL | TTERRNO, "clone3() failed (%d)", n);
126 		return;
127 	}
128 
129 	if (!pid)
130 		do_child(clone_pidfd);
131 
132 	/* Need to send signal to child process */
133 	if (clone_pidfd) {
134 		TST_CHECKPOINT_WAIT(0);
135 
136 		TEST(pidfd_send_signal(pidfd, CHILD_SIGNAL, &uinfo, 0));
137 		if (TST_RET != 0) {
138 			tst_res(TFAIL | TTERRNO, "pidfd_send_signal() failed");
139 			return;
140 		}
141 	}
142 
143 	SAFE_WAITPID(pid, &status, __WALL);
144 
145 	if (!parent_received_signal) {
146 		tst_res(TFAIL, "Parent haven't got signal");
147 		return;
148 	}
149 
150 	if (parent_received_signal != tc->exit_signal) {
151 		tst_res(TFAIL, "Parent got %s (%i) signal expected %s",
152 			tst_strsig(parent_received_signal),
153 			parent_received_signal,
154 			tst_strsig(tc->exit_signal));
155 		return;
156 	}
157 
158 	tst_res(TPASS, "Parent got correct signal %s",
159 		tst_strsig(parent_received_signal));
160 }
161 
setup(void)162 static void setup(void)
163 {
164 	clone3_supported_by_kernel();
165 
166 	uinfo.si_pid = getpid();
167 	uinfo.si_uid = getuid();
168 }
169 
170 static struct tst_test test = {
171 	.tcnt = ARRAY_SIZE(tcases),
172 	.test = run,
173 	.setup = setup,
174 	.needs_root = 1,
175 	.needs_tmpdir = 1,
176 	.needs_checkpoints = 1,
177 	.bufs = (struct tst_buffers []) {
178 		{&args, .size = sizeof(*args)},
179 		{},
180 	}
181 };
182