1/* SPDX-License-Identifier: GPL-2.0 */
2#include <stdbool.h>
3#include <linux/limits.h>
4#include <sys/ptrace.h>
5#include <sys/types.h>
6#include <sys/mman.h>
7#include <unistd.h>
8#include <stdio.h>
9#include <errno.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/wait.h>
13
14#include "../kselftest.h"
15#include "cgroup_util.h"
16
17#define DEBUG
18#ifdef DEBUG
19#define debug(args...) fprintf(stderr, args)
20#else
21#define debug(args...)
22#endif
23
24/*
25 * Check if the cgroup is frozen by looking at the cgroup.events::frozen value.
26 */
27static int cg_check_frozen(const char *cgroup, bool frozen)
28{
29	if (frozen) {
30		if (cg_read_strstr(cgroup, "cgroup.events", "frozen 1") != 0) {
31			debug("Cgroup %s isn't frozen\n", cgroup);
32			return -1;
33		}
34	} else {
35		/*
36		 * Check the cgroup.events::frozen value.
37		 */
38		if (cg_read_strstr(cgroup, "cgroup.events", "frozen 0") != 0) {
39			debug("Cgroup %s is frozen\n", cgroup);
40			return -1;
41		}
42	}
43
44	return 0;
45}
46
47/*
48 * Freeze the given cgroup.
49 */
50static int cg_freeze_nowait(const char *cgroup, bool freeze)
51{
52	return cg_write(cgroup, "cgroup.freeze", freeze ? "1" : "0");
53}
54
55/*
56 * Attach a task to the given cgroup and wait for a cgroup frozen event.
57 * All transient events (e.g. populated) are ignored.
58 */
59static int cg_enter_and_wait_for_frozen(const char *cgroup, int pid,
60					bool frozen)
61{
62	int fd, ret = -1;
63	int attempts;
64
65	fd = cg_prepare_for_wait(cgroup);
66	if (fd < 0)
67		return fd;
68
69	ret = cg_enter(cgroup, pid);
70	if (ret)
71		goto out;
72
73	for (attempts = 0; attempts < 10; attempts++) {
74		ret = cg_wait_for(fd);
75		if (ret)
76			break;
77
78		ret = cg_check_frozen(cgroup, frozen);
79		if (ret)
80			continue;
81	}
82
83out:
84	close(fd);
85	return ret;
86}
87
88/*
89 * Freeze the given cgroup and wait for the inotify signal.
90 * If there are no events in 10 seconds, treat this as an error.
91 * Then check that the cgroup is in the desired state.
92 */
93static int cg_freeze_wait(const char *cgroup, bool freeze)
94{
95	int fd, ret = -1;
96
97	fd = cg_prepare_for_wait(cgroup);
98	if (fd < 0)
99		return fd;
100
101	ret = cg_freeze_nowait(cgroup, freeze);
102	if (ret) {
103		debug("Error: cg_freeze_nowait() failed\n");
104		goto out;
105	}
106
107	ret = cg_wait_for(fd);
108	if (ret)
109		goto out;
110
111	ret = cg_check_frozen(cgroup, freeze);
112out:
113	close(fd);
114	return ret;
115}
116
117/*
118 * A simple process running in a sleep loop until being
119 * re-parented.
120 */
121static int child_fn(const char *cgroup, void *arg)
122{
123	int ppid = getppid();
124
125	while (getppid() == ppid)
126		usleep(1000);
127
128	return getppid() == ppid;
129}
130
131/*
132 * A simple test for the cgroup freezer: populated the cgroup with 100
133 * running processes and freeze it. Then unfreeze it. Then it kills all
134 * processes and destroys the cgroup.
135 */
136static int test_cgfreezer_simple(const char *root)
137{
138	int ret = KSFT_FAIL;
139	char *cgroup = NULL;
140	int i;
141
142	cgroup = cg_name(root, "cg_test_simple");
143	if (!cgroup)
144		goto cleanup;
145
146	if (cg_create(cgroup))
147		goto cleanup;
148
149	for (i = 0; i < 100; i++)
150		cg_run_nowait(cgroup, child_fn, NULL);
151
152	if (cg_wait_for_proc_count(cgroup, 100))
153		goto cleanup;
154
155	if (cg_check_frozen(cgroup, false))
156		goto cleanup;
157
158	if (cg_freeze_wait(cgroup, true))
159		goto cleanup;
160
161	if (cg_freeze_wait(cgroup, false))
162		goto cleanup;
163
164	ret = KSFT_PASS;
165
166cleanup:
167	if (cgroup)
168		cg_destroy(cgroup);
169	free(cgroup);
170	return ret;
171}
172
173/*
174 * The test creates the following hierarchy:
175 *       A
176 *    / / \ \
177 *   B  E  I K
178 *  /\  |
179 * C  D F
180 *      |
181 *      G
182 *      |
183 *      H
184 *
185 * with a process in C, H and 3 processes in K.
186 * Then it tries to freeze and unfreeze the whole tree.
187 */
188static int test_cgfreezer_tree(const char *root)
189{
190	char *cgroup[10] = {0};
191	int ret = KSFT_FAIL;
192	int i;
193
194	cgroup[0] = cg_name(root, "cg_test_tree_A");
195	if (!cgroup[0])
196		goto cleanup;
197
198	cgroup[1] = cg_name(cgroup[0], "B");
199	if (!cgroup[1])
200		goto cleanup;
201
202	cgroup[2] = cg_name(cgroup[1], "C");
203	if (!cgroup[2])
204		goto cleanup;
205
206	cgroup[3] = cg_name(cgroup[1], "D");
207	if (!cgroup[3])
208		goto cleanup;
209
210	cgroup[4] = cg_name(cgroup[0], "E");
211	if (!cgroup[4])
212		goto cleanup;
213
214	cgroup[5] = cg_name(cgroup[4], "F");
215	if (!cgroup[5])
216		goto cleanup;
217
218	cgroup[6] = cg_name(cgroup[5], "G");
219	if (!cgroup[6])
220		goto cleanup;
221
222	cgroup[7] = cg_name(cgroup[6], "H");
223	if (!cgroup[7])
224		goto cleanup;
225
226	cgroup[8] = cg_name(cgroup[0], "I");
227	if (!cgroup[8])
228		goto cleanup;
229
230	cgroup[9] = cg_name(cgroup[0], "K");
231	if (!cgroup[9])
232		goto cleanup;
233
234	for (i = 0; i < 10; i++)
235		if (cg_create(cgroup[i]))
236			goto cleanup;
237
238	cg_run_nowait(cgroup[2], child_fn, NULL);
239	cg_run_nowait(cgroup[7], child_fn, NULL);
240	cg_run_nowait(cgroup[9], child_fn, NULL);
241	cg_run_nowait(cgroup[9], child_fn, NULL);
242	cg_run_nowait(cgroup[9], child_fn, NULL);
243
244	/*
245	 * Wait until all child processes will enter
246	 * corresponding cgroups.
247	 */
248
249	if (cg_wait_for_proc_count(cgroup[2], 1) ||
250	    cg_wait_for_proc_count(cgroup[7], 1) ||
251	    cg_wait_for_proc_count(cgroup[9], 3))
252		goto cleanup;
253
254	/*
255	 * Freeze B.
256	 */
257	if (cg_freeze_wait(cgroup[1], true))
258		goto cleanup;
259
260	/*
261	 * Freeze F.
262	 */
263	if (cg_freeze_wait(cgroup[5], true))
264		goto cleanup;
265
266	/*
267	 * Freeze G.
268	 */
269	if (cg_freeze_wait(cgroup[6], true))
270		goto cleanup;
271
272	/*
273	 * Check that A and E are not frozen.
274	 */
275	if (cg_check_frozen(cgroup[0], false))
276		goto cleanup;
277
278	if (cg_check_frozen(cgroup[4], false))
279		goto cleanup;
280
281	/*
282	 * Freeze A. Check that A, B and E are frozen.
283	 */
284	if (cg_freeze_wait(cgroup[0], true))
285		goto cleanup;
286
287	if (cg_check_frozen(cgroup[1], true))
288		goto cleanup;
289
290	if (cg_check_frozen(cgroup[4], true))
291		goto cleanup;
292
293	/*
294	 * Unfreeze B, F and G
295	 */
296	if (cg_freeze_nowait(cgroup[1], false))
297		goto cleanup;
298
299	if (cg_freeze_nowait(cgroup[5], false))
300		goto cleanup;
301
302	if (cg_freeze_nowait(cgroup[6], false))
303		goto cleanup;
304
305	/*
306	 * Check that C and H are still frozen.
307	 */
308	if (cg_check_frozen(cgroup[2], true))
309		goto cleanup;
310
311	if (cg_check_frozen(cgroup[7], true))
312		goto cleanup;
313
314	/*
315	 * Unfreeze A. Check that A, C and K are not frozen.
316	 */
317	if (cg_freeze_wait(cgroup[0], false))
318		goto cleanup;
319
320	if (cg_check_frozen(cgroup[2], false))
321		goto cleanup;
322
323	if (cg_check_frozen(cgroup[9], false))
324		goto cleanup;
325
326	ret = KSFT_PASS;
327
328cleanup:
329	for (i = 9; i >= 0 && cgroup[i]; i--) {
330		cg_destroy(cgroup[i]);
331		free(cgroup[i]);
332	}
333
334	return ret;
335}
336
337/*
338 * A fork bomb emulator.
339 */
340static int forkbomb_fn(const char *cgroup, void *arg)
341{
342	int ppid;
343
344	fork();
345	fork();
346
347	ppid = getppid();
348
349	while (getppid() == ppid)
350		usleep(1000);
351
352	return getppid() == ppid;
353}
354
355/*
356 * The test runs a fork bomb in a cgroup and tries to freeze it.
357 * Then it kills all processes and checks that cgroup isn't populated
358 * anymore.
359 */
360static int test_cgfreezer_forkbomb(const char *root)
361{
362	int ret = KSFT_FAIL;
363	char *cgroup = NULL;
364
365	cgroup = cg_name(root, "cg_forkbomb_test");
366	if (!cgroup)
367		goto cleanup;
368
369	if (cg_create(cgroup))
370		goto cleanup;
371
372	cg_run_nowait(cgroup, forkbomb_fn, NULL);
373
374	usleep(100000);
375
376	if (cg_freeze_wait(cgroup, true))
377		goto cleanup;
378
379	if (cg_killall(cgroup))
380		goto cleanup;
381
382	if (cg_wait_for_proc_count(cgroup, 0))
383		goto cleanup;
384
385	ret = KSFT_PASS;
386
387cleanup:
388	if (cgroup)
389		cg_destroy(cgroup);
390	free(cgroup);
391	return ret;
392}
393
394/*
395 * The test creates a cgroups and freezes it. Then it creates a child cgroup
396 * and populates it with a task. After that it checks that the child cgroup
397 * is frozen and the parent cgroup remains frozen too.
398 */
399static int test_cgfreezer_mkdir(const char *root)
400{
401	int ret = KSFT_FAIL;
402	char *parent, *child = NULL;
403	int pid;
404
405	parent = cg_name(root, "cg_test_mkdir_A");
406	if (!parent)
407		goto cleanup;
408
409	child = cg_name(parent, "cg_test_mkdir_B");
410	if (!child)
411		goto cleanup;
412
413	if (cg_create(parent))
414		goto cleanup;
415
416	if (cg_freeze_wait(parent, true))
417		goto cleanup;
418
419	if (cg_create(child))
420		goto cleanup;
421
422	pid = cg_run_nowait(child, child_fn, NULL);
423	if (pid < 0)
424		goto cleanup;
425
426	if (cg_wait_for_proc_count(child, 1))
427		goto cleanup;
428
429	if (cg_check_frozen(child, true))
430		goto cleanup;
431
432	if (cg_check_frozen(parent, true))
433		goto cleanup;
434
435	ret = KSFT_PASS;
436
437cleanup:
438	if (child)
439		cg_destroy(child);
440	free(child);
441	if (parent)
442		cg_destroy(parent);
443	free(parent);
444	return ret;
445}
446
447/*
448 * The test creates two nested cgroups, freezes the parent
449 * and removes the child. Then it checks that the parent cgroup
450 * remains frozen and it's possible to create a new child
451 * without unfreezing. The new child is frozen too.
452 */
453static int test_cgfreezer_rmdir(const char *root)
454{
455	int ret = KSFT_FAIL;
456	char *parent, *child = NULL;
457
458	parent = cg_name(root, "cg_test_rmdir_A");
459	if (!parent)
460		goto cleanup;
461
462	child = cg_name(parent, "cg_test_rmdir_B");
463	if (!child)
464		goto cleanup;
465
466	if (cg_create(parent))
467		goto cleanup;
468
469	if (cg_create(child))
470		goto cleanup;
471
472	if (cg_freeze_wait(parent, true))
473		goto cleanup;
474
475	if (cg_destroy(child))
476		goto cleanup;
477
478	if (cg_check_frozen(parent, true))
479		goto cleanup;
480
481	if (cg_create(child))
482		goto cleanup;
483
484	if (cg_check_frozen(child, true))
485		goto cleanup;
486
487	ret = KSFT_PASS;
488
489cleanup:
490	if (child)
491		cg_destroy(child);
492	free(child);
493	if (parent)
494		cg_destroy(parent);
495	free(parent);
496	return ret;
497}
498
499/*
500 * The test creates two cgroups: A and B, runs a process in A
501 * and performs several migrations:
502 * 1) A (running) -> B (frozen)
503 * 2) B (frozen) -> A (running)
504 * 3) A (frozen) -> B (frozen)
505 *
506 * On each step it checks the actual state of both cgroups.
507 */
508static int test_cgfreezer_migrate(const char *root)
509{
510	int ret = KSFT_FAIL;
511	char *cgroup[2] = {0};
512	int pid;
513
514	cgroup[0] = cg_name(root, "cg_test_migrate_A");
515	if (!cgroup[0])
516		goto cleanup;
517
518	cgroup[1] = cg_name(root, "cg_test_migrate_B");
519	if (!cgroup[1])
520		goto cleanup;
521
522	if (cg_create(cgroup[0]))
523		goto cleanup;
524
525	if (cg_create(cgroup[1]))
526		goto cleanup;
527
528	pid = cg_run_nowait(cgroup[0], child_fn, NULL);
529	if (pid < 0)
530		goto cleanup;
531
532	if (cg_wait_for_proc_count(cgroup[0], 1))
533		goto cleanup;
534
535	/*
536	 * Migrate from A (running) to B (frozen)
537	 */
538	if (cg_freeze_wait(cgroup[1], true))
539		goto cleanup;
540
541	if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
542		goto cleanup;
543
544	if (cg_check_frozen(cgroup[0], false))
545		goto cleanup;
546
547	/*
548	 * Migrate from B (frozen) to A (running)
549	 */
550	if (cg_enter_and_wait_for_frozen(cgroup[0], pid, false))
551		goto cleanup;
552
553	if (cg_check_frozen(cgroup[1], true))
554		goto cleanup;
555
556	/*
557	 * Migrate from A (frozen) to B (frozen)
558	 */
559	if (cg_freeze_wait(cgroup[0], true))
560		goto cleanup;
561
562	if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
563		goto cleanup;
564
565	if (cg_check_frozen(cgroup[0], true))
566		goto cleanup;
567
568	ret = KSFT_PASS;
569
570cleanup:
571	if (cgroup[0])
572		cg_destroy(cgroup[0]);
573	free(cgroup[0]);
574	if (cgroup[1])
575		cg_destroy(cgroup[1]);
576	free(cgroup[1]);
577	return ret;
578}
579
580/*
581 * The test checks that ptrace works with a tracing process in a frozen cgroup.
582 */
583static int test_cgfreezer_ptrace(const char *root)
584{
585	int ret = KSFT_FAIL;
586	char *cgroup = NULL;
587	siginfo_t siginfo;
588	int pid;
589
590	cgroup = cg_name(root, "cg_test_ptrace");
591	if (!cgroup)
592		goto cleanup;
593
594	if (cg_create(cgroup))
595		goto cleanup;
596
597	pid = cg_run_nowait(cgroup, child_fn, NULL);
598	if (pid < 0)
599		goto cleanup;
600
601	if (cg_wait_for_proc_count(cgroup, 1))
602		goto cleanup;
603
604	if (cg_freeze_wait(cgroup, true))
605		goto cleanup;
606
607	if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
608		goto cleanup;
609
610	if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
611		goto cleanup;
612
613	waitpid(pid, NULL, 0);
614
615	/*
616	 * Cgroup has to remain frozen, however the test task
617	 * is in traced state.
618	 */
619	if (cg_check_frozen(cgroup, true))
620		goto cleanup;
621
622	if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
623		goto cleanup;
624
625	if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
626		goto cleanup;
627
628	if (cg_check_frozen(cgroup, true))
629		goto cleanup;
630
631	ret = KSFT_PASS;
632
633cleanup:
634	if (cgroup)
635		cg_destroy(cgroup);
636	free(cgroup);
637	return ret;
638}
639
640/*
641 * Check if the process is stopped.
642 */
643static int proc_check_stopped(int pid)
644{
645	char buf[PAGE_SIZE];
646	int len;
647
648	len = proc_read_text(pid, 0, "stat", buf, sizeof(buf));
649	if (len == -1) {
650		debug("Can't get %d stat\n", pid);
651		return -1;
652	}
653
654	if (strstr(buf, "(test_freezer) T ") == NULL) {
655		debug("Process %d in the unexpected state: %s\n", pid, buf);
656		return -1;
657	}
658
659	return 0;
660}
661
662/*
663 * Test that it's possible to freeze a cgroup with a stopped process.
664 */
665static int test_cgfreezer_stopped(const char *root)
666{
667	int pid, ret = KSFT_FAIL;
668	char *cgroup = NULL;
669
670	cgroup = cg_name(root, "cg_test_stopped");
671	if (!cgroup)
672		goto cleanup;
673
674	if (cg_create(cgroup))
675		goto cleanup;
676
677	pid = cg_run_nowait(cgroup, child_fn, NULL);
678
679	if (cg_wait_for_proc_count(cgroup, 1))
680		goto cleanup;
681
682	if (kill(pid, SIGSTOP))
683		goto cleanup;
684
685	if (cg_check_frozen(cgroup, false))
686		goto cleanup;
687
688	if (cg_freeze_wait(cgroup, true))
689		goto cleanup;
690
691	if (cg_freeze_wait(cgroup, false))
692		goto cleanup;
693
694	if (proc_check_stopped(pid))
695		goto cleanup;
696
697	ret = KSFT_PASS;
698
699cleanup:
700	if (cgroup)
701		cg_destroy(cgroup);
702	free(cgroup);
703	return ret;
704}
705
706/*
707 * Test that it's possible to freeze a cgroup with a ptraced process.
708 */
709static int test_cgfreezer_ptraced(const char *root)
710{
711	int pid, ret = KSFT_FAIL;
712	char *cgroup = NULL;
713	siginfo_t siginfo;
714
715	cgroup = cg_name(root, "cg_test_ptraced");
716	if (!cgroup)
717		goto cleanup;
718
719	if (cg_create(cgroup))
720		goto cleanup;
721
722	pid = cg_run_nowait(cgroup, child_fn, NULL);
723
724	if (cg_wait_for_proc_count(cgroup, 1))
725		goto cleanup;
726
727	if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
728		goto cleanup;
729
730	if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
731		goto cleanup;
732
733	waitpid(pid, NULL, 0);
734
735	if (cg_check_frozen(cgroup, false))
736		goto cleanup;
737
738	if (cg_freeze_wait(cgroup, true))
739		goto cleanup;
740
741	/*
742	 * cg_check_frozen(cgroup, true) will fail here,
743	 * because the task is in the TRACEd state.
744	 */
745	if (cg_freeze_wait(cgroup, false))
746		goto cleanup;
747
748	if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
749		goto cleanup;
750
751	if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
752		goto cleanup;
753
754	ret = KSFT_PASS;
755
756cleanup:
757	if (cgroup)
758		cg_destroy(cgroup);
759	free(cgroup);
760	return ret;
761}
762
763static int vfork_fn(const char *cgroup, void *arg)
764{
765	int pid = vfork();
766
767	if (pid == 0)
768		while (true)
769			sleep(1);
770
771	return pid;
772}
773
774/*
775 * Test that it's possible to freeze a cgroup with a process,
776 * which called vfork() and is waiting for a child.
777 */
778static int test_cgfreezer_vfork(const char *root)
779{
780	int ret = KSFT_FAIL;
781	char *cgroup = NULL;
782
783	cgroup = cg_name(root, "cg_test_vfork");
784	if (!cgroup)
785		goto cleanup;
786
787	if (cg_create(cgroup))
788		goto cleanup;
789
790	cg_run_nowait(cgroup, vfork_fn, NULL);
791
792	if (cg_wait_for_proc_count(cgroup, 2))
793		goto cleanup;
794
795	if (cg_freeze_wait(cgroup, true))
796		goto cleanup;
797
798	ret = KSFT_PASS;
799
800cleanup:
801	if (cgroup)
802		cg_destroy(cgroup);
803	free(cgroup);
804	return ret;
805}
806
807#define T(x) { x, #x }
808struct cgfreezer_test {
809	int (*fn)(const char *root);
810	const char *name;
811} tests[] = {
812	T(test_cgfreezer_simple),
813	T(test_cgfreezer_tree),
814	T(test_cgfreezer_forkbomb),
815	T(test_cgfreezer_mkdir),
816	T(test_cgfreezer_rmdir),
817	T(test_cgfreezer_migrate),
818	T(test_cgfreezer_ptrace),
819	T(test_cgfreezer_stopped),
820	T(test_cgfreezer_ptraced),
821	T(test_cgfreezer_vfork),
822};
823#undef T
824
825int main(int argc, char *argv[])
826{
827	char root[PATH_MAX];
828	int i, ret = EXIT_SUCCESS;
829
830	if (cg_find_unified_root(root, sizeof(root)))
831		ksft_exit_skip("cgroup v2 isn't mounted\n");
832	for (i = 0; i < ARRAY_SIZE(tests); i++) {
833		switch (tests[i].fn(root)) {
834		case KSFT_PASS:
835			ksft_test_result_pass("%s\n", tests[i].name);
836			break;
837		case KSFT_SKIP:
838			ksft_test_result_skip("%s\n", tests[i].name);
839			break;
840		default:
841			ret = EXIT_FAILURE;
842			ksft_test_result_fail("%s\n", tests[i].name);
843			break;
844		}
845	}
846
847	return ret;
848}
849