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 */
cg_check_frozen(const char * cgroup,bool frozen)27 static 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 */
cg_freeze_nowait(const char * cgroup,bool freeze)50 static 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 */
cg_enter_and_wait_for_frozen(const char * cgroup,int pid,bool frozen)59 static 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
83 out:
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 */
cg_freeze_wait(const char * cgroup,bool freeze)93 static 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);
112 out:
113 close(fd);
114 return ret;
115 }
116
117 /*
118 * A simple process running in a sleep loop until being
119 * re-parented.
120 */
child_fn(const char * cgroup,void * arg)121 static 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 */
test_cgfreezer_simple(const char * root)136 static 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
166 cleanup:
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 */
test_cgfreezer_tree(const char * root)188 static 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
328 cleanup:
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 */
forkbomb_fn(const char * cgroup,void * arg)340 static 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 */
test_cgfreezer_forkbomb(const char * root)360 static 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
387 cleanup:
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 */
test_cgfreezer_mkdir(const char * root)399 static 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
437 cleanup:
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 */
test_cgfreezer_rmdir(const char * root)453 static 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
489 cleanup:
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 */
test_cgfreezer_migrate(const char * root)508 static 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
570 cleanup:
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 */
test_cgfreezer_ptrace(const char * root)583 static 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
633 cleanup:
634 if (cgroup)
635 cg_destroy(cgroup);
636 free(cgroup);
637 return ret;
638 }
639
640 /*
641 * Check if the process is stopped.
642 */
proc_check_stopped(int pid)643 static 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 */
test_cgfreezer_stopped(const char * root)665 static 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
699 cleanup:
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 */
test_cgfreezer_ptraced(const char * root)709 static 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 in 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
756 cleanup:
757 if (cgroup)
758 cg_destroy(cgroup);
759 free(cgroup);
760 return ret;
761 }
762
vfork_fn(const char * cgroup,void * arg)763 static 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 */
test_cgfreezer_vfork(const char * root)778 static 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
800 cleanup:
801 if (cgroup)
802 cg_destroy(cgroup);
803 free(cgroup);
804 return ret;
805 }
806
807 #define T(x) { x, #x }
808 struct 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
main(int argc,char * argv[])825 int 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), NULL))
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