[28/28] zdtm: Add userns03 test

Submitted by Kirill Tkhai on June 5, 2017, 5:27 p.m.

Details

Message ID 149668365411.25229.12608973104174167367.stgit@localhost.localdomain
State New
Series "Support sockets leaked to child user_ns task"
Headers show

Commit Message

Kirill Tkhai June 5, 2017, 5:27 p.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).

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

Patch hide | download patch | download mbox

diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index 24e1420bf..dea3c662c 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -175,6 +175,7 @@  TST_NOFILE	:=				\
 		userns00			\
 		userns01			\
 		userns02			\
+		userns03			\
 		netns_sub_veth			\
 		pidns00				\
 		pidns01				\
diff --git a/test/zdtm/static/userns03.c b/test/zdtm/static/userns03.c
new file mode 100644
index 000000000..ba7aa7f1e
--- /dev/null
+++ b/test/zdtm/static/userns03.c
@@ -0,0 +1,143 @@ 
+#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,
+	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()");
+		return 1;
+	}
+
+	futex_wait_while_lt(futex, POST_RESTORE_CHECK);
+
+	sk = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		pr_perror("socket");
+		return 1;
+	}
+
+	/* 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");
+		return 1;
+	}
+
+	return 0;
+}
+
+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 0 1") < 0 ||
+	    write_map(pid, "gid_map", "0 0 1") < 0) {
+		fail("write map");
+		goto err;
+	}
+
+	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/userns03.desc b/test/zdtm/static/userns03.desc
new file mode 100644
index 000000000..703c925e2
--- /dev/null
+++ b/test/zdtm/static/userns03.desc
@@ -0,0 +1 @@ 
+{'flavor': 'uns', 'flags': 'suid', 'feature': 'ns_pid ns_get_parent ns_get_userns'}

Comments

Andrei Vagin June 6, 2017, 7:20 p.m.
On Mon, Jun 05, 2017 at 08:27:34PM +0300, Kirill Tkhai wrote:
> 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).
>
> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
> ---
>  test/zdtm/static/Makefile      |    1 
>  test/zdtm/static/userns03.c    |  143 ++++++++++++++++++++++++++++++++++++++++
>  test/zdtm/static/userns03.desc |    1 
>  3 files changed, 145 insertions(+)
>  create mode 100644 test/zdtm/static/userns03.c

the test name may be more informative. For example: userns-sockets

>  create mode 100644 test/zdtm/static/userns03.desc
> 
> diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
> index 24e1420bf..dea3c662c 100644
> --- a/test/zdtm/static/Makefile
> +++ b/test/zdtm/static/Makefile
> @@ -175,6 +175,7 @@ TST_NOFILE	:=				\
>  		userns00			\
>  		userns01			\
>  		userns02			\
> +		userns03			\
>  		netns_sub_veth			\
>  		pidns00				\
>  		pidns01				\
> diff --git a/test/zdtm/static/userns03.c b/test/zdtm/static/userns03.c
> new file mode 100644
> index 000000000..ba7aa7f1e
> --- /dev/null
> +++ b/test/zdtm/static/userns03.c
> @@ -0,0 +1,143 @@
> +#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,
> +	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()");
> +		return 1;
> +	}
> +
> +	futex_wait_while_lt(futex, POST_RESTORE_CHECK);
> +
> +	sk = socket(PF_UNIX, SOCK_DGRAM, 0);
> +	if (sk < 0) {
> +		pr_perror("socket");
> +		return 1;
> +	}
> +
> +	/* 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");
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +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 0 1") < 0 ||
> +	    write_map(pid, "gid_map", "0 0 1") < 0) {

can we use other mappings here ^^. One to one mappings isn't good,
because allow to skip something.

> +		fail("write map");
> +		goto err;
> +	}
> +
> +	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/userns03.desc b/test/zdtm/static/userns03.desc
> new file mode 100644
> index 000000000..703c925e2
> --- /dev/null
> +++ b/test/zdtm/static/userns03.desc
> @@ -0,0 +1 @@
> +{'flavor': 'uns', 'flags': 'suid', 'feature': 'ns_pid ns_get_parent ns_get_userns'}
>