diff options
author | Michał Cłapiński <mclapinski@google.com> | 2019-07-12 19:14:41 +0300 |
---|---|---|
committer | Andrei Vagin <avagin@gmail.com> | 2019-09-07 15:59:54 +0300 |
commit | 6606f246c21a8e1ff40b56087a360c1ff6fbe6bd (patch) | |
tree | d690775daaa6d3115e5aede5d4082842e89c567b | |
parent | db2777e73c3cf44ddb75aa4ab9f6e5bb88705571 (diff) |
Add ZDTM tests for child subreaper property
1. Basic check if property is migrated
2. Check that property is restored for existing children
3. Check that child subreaper does not affect reparenting
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Signed-off-by: Michał Cłapiński <mclapinski@google.com>
Reviewed-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
-rw-r--r-- | test/zdtm/static/Makefile | 3 | ||||
-rw-r--r-- | test/zdtm/static/child_subreaper.c | 36 | ||||
-rw-r--r-- | test/zdtm/static/child_subreaper_and_reparent.c | 142 | ||||
-rw-r--r-- | test/zdtm/static/child_subreaper_and_reparent.desc | 1 | ||||
-rw-r--r-- | test/zdtm/static/child_subreaper_existing_child.c | 138 |
5 files changed, 320 insertions, 0 deletions
diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 7799c0b0a..52bd00602 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -214,6 +214,9 @@ TST_NOFILE := \ selinux00 \ selinux01 \ selinux02 \ + child_subreaper \ + child_subreaper_existing_child \ + child_subreaper_and_reparent \ # jobctl00 \ ifneq ($(SRCARCH),arm) diff --git a/test/zdtm/static/child_subreaper.c b/test/zdtm/static/child_subreaper.c new file mode 100644 index 000000000..267795249 --- /dev/null +++ b/test/zdtm/static/child_subreaper.c @@ -0,0 +1,36 @@ +#include <stdlib.h> +#include <sys/prctl.h> + +#include "zdtmtst.h" + +const char *test_doc = "Check that child subreaper attribute is restored"; +const char *test_author = "Michał Cłapiński <mclapinski@google.com>"; + +int main(int argc, char **argv) +{ + test_init(argc, argv); + + int cs_before = 1; + int ret = prctl(PR_SET_CHILD_SUBREAPER, cs_before, 0, 0, 0); + if (ret) { + pr_perror("Can't set child subreaper attribute, err = %d", ret); + exit(1); + } + + test_daemon(); + test_waitsig(); + + int cs_after; + ret = prctl(PR_GET_CHILD_SUBREAPER, (unsigned long)&cs_after, 0, 0, 0); + if (ret) { + pr_perror("Can't get child subreaper attribute, err = %d", ret); + exit(1); + } + + if (cs_before != cs_after) + fail("%d != %d\n", cs_before, cs_after); + else + pass(); + + return 0; +} diff --git a/test/zdtm/static/child_subreaper_and_reparent.c b/test/zdtm/static/child_subreaper_and_reparent.c new file mode 100644 index 000000000..57943a67b --- /dev/null +++ b/test/zdtm/static/child_subreaper_and_reparent.c @@ -0,0 +1,142 @@ +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <sys/prctl.h> + +#include "zdtmtst.h" +#include "lock.h" + +const char *test_doc = "Check that child subreaper does not affect reparenting"; +const char *test_author = "Pavel Tikhomirov <ptikhomirov@virtuozzo.com>"; + +enum { + TEST_FORK, + TEST_SAVE, + TEST_CRIU, + TEST_CHECK, + TEST_EXIT, +}; + +struct shared { + futex_t fstate; + int parent_before_cr; + int parent_after_cr; +} *sh; + +int orphan() +{ + /* + * Wait until reparented to the pidns init. (By waiting + * for the SUBREAPER to reap our parent.) + */ + futex_wait_until(&sh->fstate, TEST_SAVE); + + sh->parent_before_cr = getppid(); + + /* Return the control back to MAIN worker to do C/R */ + futex_set_and_wake(&sh->fstate, TEST_CRIU); + futex_wait_until(&sh->fstate, TEST_CHECK); + + sh->parent_after_cr = getppid(); + + futex_set_and_wake(&sh->fstate, TEST_EXIT); + return 0; +} + +int helper() +{ + int pid; + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + return 1; + } else if (pid == 0) { + exit(orphan()); + } + return 0; +} + +int subreaper() +{ + int pid, ret, status; + + setsid(); + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + return 1; + } else if (pid == 0) { + exit(helper()); + } + + /* Reap the HELPER */ + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + pr_perror("Wrong exit status for helper: %d", status); + return 1; + } + + ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); + if (ret) { + pr_perror("Can't set child subreaper attribute, err = %d", ret); + return 1; + } + + /* Give control to ORPHAN to save it's parent */ + futex_set_and_wake(&sh->fstate, TEST_SAVE); + futex_wait_until(&sh->fstate, TEST_EXIT); + return 0; +} + +int main(int argc, char **argv) +{ + int pid, status; + + sh = mmap(NULL, sizeof(struct shared), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (sh == MAP_FAILED) { + pr_perror("Failed to alloc shared region"); + exit(1); + } + + futex_set(&sh->fstate, TEST_FORK); + + test_init(argc, argv); + + setsid(); + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + exit(1); + } else if (pid == 0) { + exit(subreaper()); + } + + /* Wait until ORPHAN is ready to C/R */ + futex_wait_until(&sh->fstate, TEST_CRIU); + + test_daemon(); + test_waitsig(); + + /* Give control to ORPHAN to check it's parent */ + futex_set_and_wake(&sh->fstate, TEST_CHECK); + futex_wait_until(&sh->fstate, TEST_EXIT); + + /* Cleanup */ + while (wait(&status) > 0) { + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fail("Wrong exit status: %d", status); + return 1; + } + } + + if (sh->parent_before_cr != sh->parent_after_cr) + fail("Parent mismatch before %d after %d", sh->parent_before_cr, sh->parent_after_cr); + else + pass(); + return 0; +} diff --git a/test/zdtm/static/child_subreaper_and_reparent.desc b/test/zdtm/static/child_subreaper_and_reparent.desc new file mode 100644 index 000000000..6c4afe5f0 --- /dev/null +++ b/test/zdtm/static/child_subreaper_and_reparent.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns'} diff --git a/test/zdtm/static/child_subreaper_existing_child.c b/test/zdtm/static/child_subreaper_existing_child.c new file mode 100644 index 000000000..28e9dbb8a --- /dev/null +++ b/test/zdtm/static/child_subreaper_existing_child.c @@ -0,0 +1,138 @@ +#include <unistd.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <sys/prctl.h> + +#include "zdtmtst.h" +#include "lock.h" + +const char *test_doc = "Check that property is restored for existing children"; +const char *test_author = "Michał Cłapiński <mclapinski@google.com>"; + +enum { + TEST_FORK, + TEST_CRIU, + TEST_DIE, + TEST_CHECK, + TEST_EXIT, +}; + +struct shared { + futex_t fstate; + int ppid_after_reparent; +} *sh; + + +int orphan() +{ + /* Return the control back to MAIN worker to do C/R */ + futex_set_and_wake(&sh->fstate, TEST_CRIU); + futex_wait_until(&sh->fstate, TEST_CHECK); + + sh->ppid_after_reparent = getppid(); + + futex_set_and_wake(&sh->fstate, TEST_EXIT); + return 0; +} + +int helper() +{ + int pid; + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + return 1; + } else if (pid == 0) { + exit(orphan()); + } + + futex_wait_until(&sh->fstate, TEST_DIE); + return 0; +} + +int subreaper() +{ + int pid, ret, status; + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + return 1; + } else if (pid == 0) { + exit(helper()); + } + + ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); + if (ret) { + pr_perror("Can't set child subreaper attribute, err = %d", ret); + return 1; + } + + /* Reap the HELPER */ + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + pr_perror("Wrong exit status for HELPER: %d", status); + return 1; + } + + /* Give control to ORPHAN so it can check its parent */ + futex_set_and_wake(&sh->fstate, TEST_CHECK); + futex_wait_until(&sh->fstate, TEST_EXIT); + + /* Cleanup: reap the ORPHAN */ + wait(&status); + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + pr_perror("Wrong exit status for ORPHAN: %d", status); + return 1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + int pid, status; + + sh = mmap(NULL, sizeof(struct shared), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (sh == MAP_FAILED) { + pr_perror("Failed to alloc shared region"); + exit(1); + } + + futex_set(&sh->fstate, TEST_FORK); + + test_init(argc, argv); + + pid = fork(); + if (pid < 0) { + pr_perror("Failed to fork"); + exit(1); + } else if (pid == 0) { + exit(subreaper()); + } + + /* Wait until ORPHAN is ready to C/R */ + futex_wait_until(&sh->fstate, TEST_CRIU); + + test_daemon(); + test_waitsig(); + + /* Give control to HELPER so it can die */ + futex_set_and_wake(&sh->fstate, TEST_DIE); + futex_wait_until(&sh->fstate, TEST_EXIT); + + /* Cleanup: reap the SUBREAPER */ + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fail("Wrong exit status: %d", status); + return 1; + } + + if (sh->ppid_after_reparent != pid) + fail("Orphan was reparented to %d instead of %d", sh->ppid_after_reparent, pid); + else + pass(); + return 0; +} |