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