[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