xref: /linux/tools/testing/selftests/cgroup/test_kill.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #include <errno.h>
4 #include <linux/limits.h>
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/wait.h>
11 #include <unistd.h>
12 
13 #include "kselftest.h"
14 #include "../pidfd/pidfd.h"
15 #include "cgroup_util.h"
16 
17 /*
18  * Kill the given cgroup and wait for the inotify signal.
19  * If there are no events in 10 seconds, treat this as an error.
20  * Then check that the cgroup is in the desired state.
21  */
22 static int cg_kill_wait(const char *cgroup)
23 {
24 	int fd, ret = -1;
25 
26 	fd = cg_prepare_for_wait(cgroup);
27 	if (fd < 0)
28 		return fd;
29 
30 	ret = cg_write(cgroup, "cgroup.kill", "1");
31 	if (ret)
32 		goto out;
33 
34 	ret = cg_wait_for(fd);
35 	if (ret)
36 		goto out;
37 
38 out:
39 	close(fd);
40 	return ret;
41 }
42 
43 /*
44  * A simple process running in a sleep loop until being
45  * re-parented.
46  */
47 static int child_fn(const char *cgroup, void *arg)
48 {
49 	int ppid = getppid();
50 
51 	while (getppid() == ppid)
52 		usleep(1000);
53 
54 	return getppid() == ppid;
55 }
56 
57 static int test_cgkill_simple(const char *root)
58 {
59 	pid_t pids[100];
60 	int ret = KSFT_FAIL;
61 	char *cgroup = NULL;
62 	int i;
63 
64 	cgroup = cg_name(root, "cg_test_simple");
65 	if (!cgroup)
66 		goto cleanup;
67 
68 	if (cg_create(cgroup))
69 		goto cleanup;
70 
71 	for (i = 0; i < 100; i++)
72 		pids[i] = cg_run_nowait(cgroup, child_fn, NULL);
73 
74 	if (cg_wait_for_proc_count(cgroup, 100))
75 		goto cleanup;
76 
77 	if (cg_read_strcmp(cgroup, "cgroup.events", "populated 1\n"))
78 		goto cleanup;
79 
80 	if (cg_kill_wait(cgroup))
81 		goto cleanup;
82 
83 	ret = KSFT_PASS;
84 
85 cleanup:
86 	for (i = 0; i < 100; i++)
87 		wait_for_pid(pids[i]);
88 
89 	if (ret == KSFT_PASS &&
90 	    cg_read_strcmp_wait(cgroup, "cgroup.events", "populated 0\n"))
91 		ret = KSFT_FAIL;
92 
93 	if (cgroup)
94 		cg_destroy(cgroup);
95 	free(cgroup);
96 	return ret;
97 }
98 
99 /*
100  * The test creates the following hierarchy:
101  *       A
102  *    / / \ \
103  *   B  E  I K
104  *  /\  |
105  * C  D F
106  *      |
107  *      G
108  *      |
109  *      H
110  *
111  * with a process in C, H and 3 processes in K.
112  * Then it tries to kill the whole tree.
113  */
114 static int test_cgkill_tree(const char *root)
115 {
116 	pid_t pids[5];
117 	char *cgroup[10] = {0};
118 	int ret = KSFT_FAIL;
119 	int i;
120 
121 	cgroup[0] = cg_name(root, "cg_test_tree_A");
122 	if (!cgroup[0])
123 		goto cleanup;
124 
125 	cgroup[1] = cg_name(cgroup[0], "B");
126 	if (!cgroup[1])
127 		goto cleanup;
128 
129 	cgroup[2] = cg_name(cgroup[1], "C");
130 	if (!cgroup[2])
131 		goto cleanup;
132 
133 	cgroup[3] = cg_name(cgroup[1], "D");
134 	if (!cgroup[3])
135 		goto cleanup;
136 
137 	cgroup[4] = cg_name(cgroup[0], "E");
138 	if (!cgroup[4])
139 		goto cleanup;
140 
141 	cgroup[5] = cg_name(cgroup[4], "F");
142 	if (!cgroup[5])
143 		goto cleanup;
144 
145 	cgroup[6] = cg_name(cgroup[5], "G");
146 	if (!cgroup[6])
147 		goto cleanup;
148 
149 	cgroup[7] = cg_name(cgroup[6], "H");
150 	if (!cgroup[7])
151 		goto cleanup;
152 
153 	cgroup[8] = cg_name(cgroup[0], "I");
154 	if (!cgroup[8])
155 		goto cleanup;
156 
157 	cgroup[9] = cg_name(cgroup[0], "K");
158 	if (!cgroup[9])
159 		goto cleanup;
160 
161 	for (i = 0; i < 10; i++)
162 		if (cg_create(cgroup[i]))
163 			goto cleanup;
164 
165 	pids[0] = cg_run_nowait(cgroup[2], child_fn, NULL);
166 	pids[1] = cg_run_nowait(cgroup[7], child_fn, NULL);
167 	pids[2] = cg_run_nowait(cgroup[9], child_fn, NULL);
168 	pids[3] = cg_run_nowait(cgroup[9], child_fn, NULL);
169 	pids[4] = cg_run_nowait(cgroup[9], child_fn, NULL);
170 
171 	/*
172 	 * Wait until all child processes will enter
173 	 * corresponding cgroups.
174 	 */
175 
176 	if (cg_wait_for_proc_count(cgroup[2], 1) ||
177 	    cg_wait_for_proc_count(cgroup[7], 1) ||
178 	    cg_wait_for_proc_count(cgroup[9], 3))
179 		goto cleanup;
180 
181 	/*
182 	 * Kill A and check that we get an empty notification.
183 	 */
184 	if (cg_kill_wait(cgroup[0]))
185 		goto cleanup;
186 
187 	ret = KSFT_PASS;
188 
189 cleanup:
190 	for (i = 0; i < 5; i++)
191 		wait_for_pid(pids[i]);
192 
193 	if (ret == KSFT_PASS &&
194 	    cg_read_strcmp_wait(cgroup[0], "cgroup.events",
195 				   "populated 0\n"))
196 		ret = KSFT_FAIL;
197 
198 	for (i = 9; i >= 0 && cgroup[i]; i--) {
199 		cg_destroy(cgroup[i]);
200 		free(cgroup[i]);
201 	}
202 
203 	return ret;
204 }
205 
206 static int forkbomb_fn(const char *cgroup, void *arg)
207 {
208 	int ppid;
209 
210 	fork();
211 	fork();
212 
213 	ppid = getppid();
214 
215 	while (getppid() == ppid)
216 		usleep(1000);
217 
218 	return getppid() == ppid;
219 }
220 
221 /*
222  * The test runs a fork bomb in a cgroup and tries to kill it.
223  */
224 static int test_cgkill_forkbomb(const char *root)
225 {
226 	int ret = KSFT_FAIL;
227 	char *cgroup = NULL;
228 	pid_t pid = -ESRCH;
229 
230 	cgroup = cg_name(root, "cg_forkbomb_test");
231 	if (!cgroup)
232 		goto cleanup;
233 
234 	if (cg_create(cgroup))
235 		goto cleanup;
236 
237 	pid = cg_run_nowait(cgroup, forkbomb_fn, NULL);
238 	if (pid < 0)
239 		goto cleanup;
240 
241 	usleep(100000);
242 
243 	if (cg_kill_wait(cgroup))
244 		goto cleanup;
245 
246 	if (cg_wait_for_proc_count(cgroup, 0))
247 		goto cleanup;
248 
249 	ret = KSFT_PASS;
250 
251 cleanup:
252 	if (pid > 0)
253 		wait_for_pid(pid);
254 
255 	if (ret == KSFT_PASS &&
256 	    cg_read_strcmp_wait(cgroup, "cgroup.events", "populated 0\n"))
257 		ret = KSFT_FAIL;
258 
259 	if (cgroup)
260 		cg_destroy(cgroup);
261 	free(cgroup);
262 	return ret;
263 }
264 
265 /*
266  * Test that a cgroup that was killed in the past can still be the target
267  * of clone3(CLONE_INTO_CGROUP): writing cgroup.kill must only kill the
268  * tasks in the cgroup at the time of the write, not tasks cloned into
269  * it afterwards.
270  */
271 static int test_cgkill_clone_into_killed(const char *root)
272 {
273 	pid_t pid;
274 	int cgroup_fd = -EBADF;
275 	int ret = KSFT_FAIL;
276 	char *cgroup = NULL;
277 
278 	cgroup = cg_name(root, "cg_test_clone_into_killed");
279 	if (!cgroup)
280 		goto cleanup;
281 
282 	if (cg_create(cgroup))
283 		goto cleanup;
284 
285 	/* Kill the cgroup while it is still empty. */
286 	if (cg_write(cgroup, "cgroup.kill", "1"))
287 		goto cleanup;
288 
289 	cgroup_fd = dirfd_open_opath(cgroup);
290 	if (cgroup_fd < 0)
291 		goto cleanup;
292 
293 	pid = clone_into_cgroup(cgroup_fd);
294 	if (pid < 0) {
295 		if (errno == ENOSYS)
296 			ret = KSFT_SKIP;
297 		goto cleanup;
298 	}
299 
300 	if (pid == 0)
301 		exit(EXIT_SUCCESS);
302 
303 	/* The child must not be SIGKILLed; it has to exit cleanly. */
304 	if (clone_reap(pid, WEXITED) != EXIT_SUCCESS)
305 		goto cleanup;
306 
307 	ret = KSFT_PASS;
308 
309 cleanup:
310 	if (cgroup_fd >= 0)
311 		close(cgroup_fd);
312 	if (cgroup)
313 		cg_destroy(cgroup);
314 	free(cgroup);
315 	return ret;
316 }
317 
318 #define T(x) { x, #x }
319 struct cgkill_test {
320 	int (*fn)(const char *root);
321 	const char *name;
322 } tests[] = {
323 	T(test_cgkill_simple),
324 	T(test_cgkill_tree),
325 	T(test_cgkill_forkbomb),
326 	T(test_cgkill_clone_into_killed),
327 };
328 #undef T
329 
330 int main(int argc, char *argv[])
331 {
332 	char root[PATH_MAX];
333 	int i;
334 
335 	ksft_print_header();
336 	if (cg_find_unified_root(root, sizeof(root), NULL))
337 		ksft_exit_skip("cgroup v2 isn't mounted\n");
338 	ksft_set_plan(ARRAY_SIZE(tests));
339 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
340 		switch (tests[i].fn(root)) {
341 		case KSFT_PASS:
342 			ksft_test_result_pass("%s\n", tests[i].name);
343 			break;
344 		case KSFT_SKIP:
345 			ksft_test_result_skip("%s\n", tests[i].name);
346 			break;
347 		default:
348 			ksft_test_result_fail("%s\n", tests[i].name);
349 			break;
350 		}
351 	}
352 
353 	ksft_finished();
354 }
355