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