[CRIU] [PATCH v2 21/21] zdtm: Add pidns03 test
Kirill Tkhai
ktkhai at virtuozzo.com
Wed May 31 10:55:16 PDT 2017
Create a child in new pid_ns; then the child creats thread and zombie.
Zombie is in the second created new pid_ns. Then the great parent
setns() to its active pid_ns. So, lets draw the table:
pid_ns vs pid_for_children_ns
great parent: equal
child: not equal
child thread: equal
grand child zombie: zombies don't have pid_for_children_ns
After signal chech that everything remains the same.
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
test/zdtm/static/Makefile | 4 +
test/zdtm/static/pidns03.c | 200 +++++++++++++++++++++++++++++++++++++++++
test/zdtm/static/pidns03.desc | 1
3 files changed, 205 insertions(+)
create mode 100644 test/zdtm/static/pidns03.c
create mode 100644 test/zdtm/static/pidns03.desc
diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index 178e564d7..24e1420bf 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -179,6 +179,7 @@ TST_NOFILE := \
pidns00 \
pidns01 \
pidns02 \
+ pidns03 \
# jobctl00 \
ifneq ($(SRCARCH),arm)
@@ -464,6 +465,9 @@ pty-console: CFLAGS += -D ZDTM_DEV_CONSOLE
userns02: CFLAGS += -D USERNS02
proc-self01: override CFLAGS += -D PROC_SELF01
+pidns03: CFLAGS += -pthread
+pidns03: LDFLAGS += -pthread
+
$(LIB): force
$(Q) $(MAKE) -C $(LIBDIR)
diff --git a/test/zdtm/static/pidns03.c b/test/zdtm/static/pidns03.c
new file mode 100644
index 000000000..1cca6e72a
--- /dev/null
+++ b/test/zdtm/static/pidns03.c
@@ -0,0 +1,200 @@
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include "zdtmtst.h"
+#include "lock.h"
+
+const char *test_doc = "Check pid_for_children of tasks and threads restore right";
+const char *test_author = "Kirill Tkhai <ktkhai at virtuozzo.com>";
+/*
+ * Create a child in new pid_ns; then the child creats thread and zombie.
+ * Zombie is in the second created new pid_ns. Then the great parent
+ * setns() to its active pid_ns. So, lets draw the table:
+ *
+ * pid_ns vs pid_for_children_ns
+ * great parent: equal
+ * child: not equal
+ * child thread: equal
+ * grand child zombie: zombies don't have pid_for_children_ns
+ */
+
+enum {
+ FUTEX_INITIALIZED = 0,
+ CHILD_PREPARED,
+ POST_RESTORE_CHECK,
+ EMERGENCY_ABORT,
+};
+
+futex_t *futex;
+
+enum {
+ EQUAL = 0,
+ NOTEQUAL,
+ ERROR,
+};
+
+char *ret_names[] = {"equal", "not equal", "error"};
+
+static int read_ns_link(const char *file_name, ino_t *id)
+{
+ char ns_path[128];
+ struct stat st;
+
+ sprintf(ns_path, "/proc/thread-self/ns/%s", file_name);
+
+ if (stat(ns_path, &st)) {
+ pr_perror("Unable to stat %s", ns_path);
+ return -1;
+ }
+ *id = st.st_ino;
+ return 0;
+}
+
+static int compare_pid_and_pfc(void)
+{
+ ino_t pid, pid_for_children;
+
+ if (read_ns_link("pid", &pid) || read_ns_link("pid_for_children", &pid_for_children)) {
+ pr_err("Can't read link\n");
+ return ERROR;
+ }
+
+ if (pid != pid_for_children)
+ return NOTEQUAL;
+ return EQUAL;
+}
+
+static void *thread_fn(void *unused)
+{
+ int ret;
+ futex_wait_while_lt(futex, POST_RESTORE_CHECK);
+ ret = compare_pid_and_pfc();
+ if (ret != EQUAL) {
+ pr_err("thread: %s\n", ret_names[ret]);
+ return (void *)(long)-1;
+ }
+ return (void *)(long)0;
+}
+
+static int child_fn(void)
+{
+ long thread_retval;
+ pthread_t thread;
+ pid_t pid;
+ int ret;
+
+ ret = pthread_create(&thread, NULL, thread_fn, NULL);
+ if (ret) {
+ pr_perror("Can't creat thread");
+ goto err;
+ }
+
+ if (unshare(CLONE_NEWPID) < 0) {
+ pr_perror("Can't unshare");
+ goto err;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ pr_perror("Can't fork");
+ goto err;
+ } else if (!pid)
+ exit(0);
+ futex_set_and_wake(futex, CHILD_PREPARED);
+ futex_wait_while_lt(futex, POST_RESTORE_CHECK);
+
+ ret = pthread_join(thread, (void **)&thread_retval);
+ if (ret) {
+ pr_perror("Can't join thread");
+ goto err;
+ }
+
+ if (thread_retval == -1) {
+ pr_err("Thread finished with error\n");
+ goto err;
+ }
+
+ ret = compare_pid_and_pfc();
+ if (ret != NOTEQUAL) {
+ pr_err("child: %s\n", ret_names[ret]);
+ goto err;
+ }
+
+ return 0;
+err:
+ futex_set_and_wake(futex, EMERGENCY_ABORT);
+ return -1;
+}
+
+int main(int argc, char **argv)
+{
+ int status, fd, ret;
+ pid_t pid;
+
+ test_init(argc, argv);
+ futex = mmap(NULL, sizeof(*futex), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (futex == MAP_FAILED) {
+ fail("mmap futex\n");
+ return 1;
+ }
+ futex_init(futex);
+
+ if (unshare(CLONE_NEWPID) < 0) {
+ fail("Can't unshare");
+ return 1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ fail("Can't fork");
+ return 1;
+ } else if (pid == 0)
+ exit(child_fn());
+
+ fd = open("/proc/self/ns/pid", O_RDONLY);
+ if (fd < 0) {
+ fail("Can't open");
+ return 1;
+ }
+
+ if (setns(fd, CLONE_NEWPID) < 0) {
+ fail("Can't setns");
+ return 1;
+ }
+
+ futex_wait_while_lt(futex, CHILD_PREPARED);
+
+ test_daemon();
+ test_waitsig();
+
+ ret = compare_pid_and_pfc();
+ if (ret != EQUAL) {
+ fail("parent: %s\n", ret_names[ret]);
+ kill(pid, SIGKILL);
+ return 1;
+ }
+
+ futex_set_and_wake(futex, POST_RESTORE_CHECK);
+
+ errno = 0;
+ if (waitpid(pid, &status, 0) != pid || !WIFEXITED(status) || WEXITSTATUS(status)) {
+ fail("Can't wait or bad status: errno=%d, status=%d", errno, status);
+ return 1;
+ }
+
+ pass();
+ return 0;
+}
diff --git a/test/zdtm/static/pidns03.desc b/test/zdtm/static/pidns03.desc
new file mode 100644
index 000000000..8b53d6205
--- /dev/null
+++ b/test/zdtm/static/pidns03.desc
@@ -0,0 +1 @@
+{'flavor': 'uns', 'flags': 'suid', 'feature': 'ns_pid ns_get_userns ns_get_parent pid_for_children_ns'}
More information about the CRIU
mailing list