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