[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