[CRIU] [PATCH v1 01/17] zdtm: Add userns00 test

Kirill Tkhai ktkhai at virtuozzo.com
Thu Jan 12 09:52:04 PST 2017


Create two children, and unshare() user_ns in one of them.
Then compare user_ns of parent and children.

Also, the one of the children forks one more time, and
the new descendant unshares too.

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 test/zdtm/static/Makefile      |    1 
 test/zdtm/static/userns00.c    |  186 ++++++++++++++++++++++++++++++++++++++++
 test/zdtm/static/userns00.desc |    1 
 3 files changed, 188 insertions(+)
 create mode 100644 test/zdtm/static/userns00.c
 create mode 100644 test/zdtm/static/userns00.desc

diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index d89e3edc2..133066f35 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -172,6 +172,7 @@ TST_NOFILE	:=				\
 		macvlan			\
 		cr_veth				\
 		sock_peercred			\
+		userns00			\
 #		jobctl00			\
 
 ifneq ($(SRCARCH),arm)
diff --git a/test/zdtm/static/userns00.c b/test/zdtm/static/userns00.c
new file mode 100644
index 000000000..15ef4ca55
--- /dev/null
+++ b/test/zdtm/static/userns00.c
@@ -0,0 +1,186 @@
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <dirent.h>
+
+#include "zdtmtst.h"
+
+/*
+ * Child1 makes unshare(), while Child2 does not do. Then check,
+ * that Parent's user ns is not equal to Child1's and is the same as Child2's.
+ * Also, Child2 creates Child3, which tries to do one more unshare().
+ */
+const char *test_doc	= "Check UID in unshared userns remains the same";
+const char *test_author	= "Kirill Tkhai <ktkhai at virtuozzo.com>";
+
+int get_user_ns(pid_t pid, unsigned int *ns_id)
+{
+	char path[PATH_MAX], buf[PATH_MAX];
+	int len;
+
+	sprintf(path, "/proc/%d/ns/user", pid);
+	len = readlink(path, buf, PATH_MAX);
+	if (len < 0) {
+		pr_perror("Can't read link %s\n", path);
+		return -1;
+	}
+
+	buf[len] = '\0';
+	if (sscanf(buf, "user:[%u", ns_id) < 1) {
+		pr_err("Can't get id: %s\n", buf);
+		return -1;
+	}
+
+	return 0;
+}
+
+int write_map(pid_t pid, char *map)
+{
+	char path[4096];
+	int fd, ret;
+
+	sprintf(path, "/proc/%d/%s", pid, map);
+	fd = open(path, O_WRONLY);
+	if (fd < 0) {
+		fail("Can't open");
+		return -1;
+	}
+	ret = write(fd, "1 0 1\n", 6);
+	if (ret != 6) {
+		fail("Can't write");
+		return -1;
+	}
+	close(fd);
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	unsigned int ns_p, ns_c1, ns_c2;
+	task_waiter_t lock;
+	pid_t pid1, pid2;
+	int status, ret;
+
+	test_init(argc, argv);
+	task_waiter_init(&lock);
+
+	pid1 = fork();
+	if (pid1 == -1) {
+		pr_perror("fork");
+		return 1;
+	} else if (pid1 == 0) {
+		unsigned int ns_c3;
+		pid_t pid3;
+
+		/* Child1 */
+		ret = unshare(CLONE_NEWUSER);
+		if (ret < 0)
+			pr_perror("unshare");
+		task_waiter_complete(&lock, 1);
+		if (ret < 0)
+			return 1;
+
+		task_waiter_wait4(&lock, 2);
+		if (setuid(1) < 0 || setgid(1) < 0) {
+			fail("setuid");
+			return 1;
+		}
+		if (get_user_ns(getpid(), &ns_c2) < 0) {
+			fail("get_user_ns()");
+			return 1;
+		}
+		pid3 = fork();
+		if (pid3 < 0) {
+			fail("fork");
+			return 1;
+		}
+		if (!pid3) {
+			ret = unshare(CLONE_NEWUSER);
+			if (ret < 0) {
+				pr_perror("unshare");
+				return 1;
+			}
+			task_waiter_complete(&lock, 3);
+			test_waitsig();
+			if (get_user_ns(getpid(), &ns_c3) < 0) {
+				fail("get_user_ns()");
+				return 1;
+			}
+			if (ns_c2 == ns_c3) {
+				fail("same ns\n");
+				return 1;
+			}
+			return 0;
+		}
+		test_waitsig();
+		kill(pid3, SIGTERM);
+		wait(&status);
+		if (status) {
+			fail("Can't wait");
+			return 1;
+		}
+		return 0;
+	}
+
+	task_waiter_wait4(&lock, 1);
+
+	pid2 = fork();
+	if (pid2 < 0) {
+		pr_perror("fork");
+		return 1;
+	} else if (pid2 == 0) {
+		/* Child2 */
+		test_waitsig();
+		return 0;
+	}
+
+	if (write_map(pid1, "uid_map") < 0 ||
+	    write_map(pid1, "gid_map") < 0)
+		exit(1);
+
+	task_waiter_complete(&lock, 2);
+	task_waiter_wait4(&lock, 3);
+
+	test_daemon();
+	test_waitsig();
+
+	if (get_user_ns(getpid(), &ns_p) < 0 ||
+	    get_user_ns(pid1, &ns_c1) < 0 ||
+	    get_user_ns(pid2, &ns_c2) < 0) {
+		fail("Can't get user ns\n");
+		return 1;
+	}
+
+	kill(pid1, SIGTERM);
+	wait(&status);
+	if (status) {
+		fail("Test died");
+		return 1;
+	}
+
+	kill(pid2, SIGTERM);
+	wait(&status);
+	if (status) {
+		fail("Test died");
+		return 1;
+	}
+
+	if (ns_p != ns_c1 && ns_p == ns_c2) {
+		pass();
+		return 0;
+	} else {
+		fail("ns_p=%u, ns_c1=%u, ns_c2=%u\n", ns_p, ns_c1, ns_c2);
+		return 1;
+	}
+}
diff --git a/test/zdtm/static/userns00.desc b/test/zdtm/static/userns00.desc
new file mode 100644
index 000000000..1f8bec515
--- /dev/null
+++ b/test/zdtm/static/userns00.desc
@@ -0,0 +1 @@
+{'flavor': 'uns', 'flags': 'suid noauto'}



More information about the CRIU mailing list