[v2,23/30] zdtm: Add userns-leaked-sock test

Submitted by Kirill Tkhai on June 7, 2017, 11:29 a.m.

Details

Message ID 149683498306.4663.130662813711293040.stgit@localhost.localdomain
State Accepted
Series "Support sockets leaked to child user_ns task"
Commit c37b032275b86a201567af2fefaf9edc8ac33dc5
Headers show

Commit Message

Kirill Tkhai June 7, 2017, 11:29 a.m.
1)Create a socket, bind it, then create a child in lower user, pid and net ns.
2)Close socket in parent
3)After signal, check that child can create the socket with the same name.
  (It must, as it's in another net namespace).

v2: Add uid/gid mapping.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 test/zdtm/static/Makefile                |    1 
 test/zdtm/static/userns-leaked-sock.c    |  164 ++++++++++++++++++++++++++++++
 test/zdtm/static/userns-leaked-sock.desc |    1 
 3 files changed, 166 insertions(+)
 create mode 100644 test/zdtm/static/userns-leaked-sock.c
 create mode 100644 test/zdtm/static/userns-leaked-sock.desc

Patch hide | download patch | download mbox

diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index 0ea6c3d87..31ba6d590 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -176,6 +176,7 @@  TST_NOFILE	:=				\
 		userns00			\
 		userns01			\
 		userns02			\
+		userns-leaked-sock		\
 		netns_sub_veth			\
 		pidns00				\
 		pidns01				\
diff --git a/test/zdtm/static/userns-leaked-sock.c b/test/zdtm/static/userns-leaked-sock.c
new file mode 100644
index 000000000..8a84efe6a
--- /dev/null
+++ b/test/zdtm/static/userns-leaked-sock.c
@@ -0,0 +1,164 @@ 
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "zdtmtst.h"
+#include "lock.h"
+
+const char *test_doc	= "Check that restorer for sockets is choosed right in dependence of net_ns->user_ns";
+const char *test_author	= "Kirill Tkhai <ktkhai@virtuozzo.com>";
+
+enum {
+	FUTEX_INITIALIZED = 0,
+	MAPS_SET,
+	CHILD_PREPARED,
+	POST_RESTORE_CHECK,
+	EMERGENCY_ABORT,
+};
+
+futex_t *futex;
+
+int write_map(pid_t pid, char *file, char *map)
+{
+	char path[PATH_MAX];
+	int fd, ret;
+
+	sprintf(path, "/proc/%d/%s", pid, file);
+	fd = open(path, O_WRONLY);
+	if (fd < 0) {
+		fail("Can't open");
+		return -1;
+	}
+	ret = write(fd, map, strlen(map));
+	if (ret != strlen(map)) {
+		fail("Can't write");
+		close(fd);
+		return -1;
+	}
+	close(fd);
+
+	return 0;
+}
+
+int child_fn(void *arg)
+{
+	int sk, orig_sk = (int)(long)arg;
+	struct sockaddr_un addr;
+	socklen_t len = sizeof(addr);
+
+	if (getsockname(orig_sk, &addr, &len) < 0) {
+		pr_perror("getsockname()");
+		goto err;
+	}
+	futex_wait_while_lt(futex, MAPS_SET);
+	if (futex_get(futex) == EMERGENCY_ABORT)
+		return 1;
+
+	if (setuid(0)) {
+		pr_perror("Can't set uid");
+		goto err;
+	}
+	if (setgid(0)) {
+		pr_perror("Can't set gid");
+		goto err;
+	}
+
+	futex_set_and_wake(futex, CHILD_PREPARED);
+	futex_wait_while_lt(futex, POST_RESTORE_CHECK);
+
+	sk = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		pr_perror("socket");
+		goto err;
+	}
+
+	/* This must complete w/o errors, as orig_sk is from another net namespace */
+	if (bind(sk, (struct sockaddr *)&addr, len) < 0) {
+		pr_perror("bind");
+		goto err;
+	}
+
+	return 0;
+err:
+	futex_set_and_wake(futex, EMERGENCY_ABORT);
+	return 1;
+}
+
+int main(int argc, char **argv)
+{
+	struct sockaddr_un addr;
+	int sk, len;
+	int status;
+	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);
+
+	sk = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		fail("socket");
+		return 1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	sprintf(addr.sun_path, "x/test-socket-name");
+	len = SUN_LEN(&addr);
+	*addr.sun_path = '\0';
+
+	if (bind(sk, (struct sockaddr *)&addr, len) < 0) {
+		fail("bind");
+		return 1;
+	}
+
+	{
+		char stack;
+		pid = clone(child_fn, &stack - 256, CLONE_NEWUSER|CLONE_NEWNET|CLONE_NEWPID, (void *)(long)sk);
+		if (pid == -1) {
+			fail("clone");
+			return 1;
+		}
+	}
+
+	if (write_map(pid, "uid_map", "0 10 1") < 0 ||
+	    write_map(pid, "gid_map", "0 12 1") < 0) {
+		fail("write map");
+		goto err;
+	}
+
+	futex_set_and_wake(futex, MAPS_SET);
+	futex_wait_while_lt(futex, CHILD_PREPARED);
+
+	close(sk);
+
+	test_daemon();
+	test_waitsig();
+
+	futex_set_and_wake(futex, POST_RESTORE_CHECK);
+
+	if (wait(&status) < 0 || WEXITSTATUS(status)) {
+		fail("pid: status=%d\n", WEXITSTATUS(status));
+		goto err;
+	}
+
+	pass();
+	return 0;
+err:
+	futex_set_and_wake(futex, EMERGENCY_ABORT);
+	wait(&status);
+	return 1;
+}
diff --git a/test/zdtm/static/userns-leaked-sock.desc b/test/zdtm/static/userns-leaked-sock.desc
new file mode 100644
index 000000000..703c925e2
--- /dev/null
+++ b/test/zdtm/static/userns-leaked-sock.desc
@@ -0,0 +1 @@ 
+{'flavor': 'uns', 'flags': 'suid', 'feature': 'ns_pid ns_get_parent ns_get_userns'}