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 */
cg_kill_wait(const char * cgroup)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 */
child_fn(const char * cgroup,void * arg)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
test_cgkill_simple(const char * root)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 */
test_cgkill_tree(const char * root)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
forkbomb_fn(const char * cgroup,void * arg)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 */
test_cgkill_forkbomb(const char * root)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 */
test_cgkill_clone_into_killed(const char * root)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
main(int argc,char * argv[])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