lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20190124155053.7795-1-mcroce@redhat.com>
Date:   Thu, 24 Jan 2019 16:50:53 +0100
From:   Matteo Croce <mcroce@...hat.com>
To:     netdev@...r.kernel.org
Cc:     David Ahern <dsahern@...il.com>,
        Stephen Hemminger <sthemmin@...rosoft.com>
Subject: [PATCH iproute2-next] netns: add subcommand to attach an existing network namespace

ip tracks namespaces with dummy files in /var/run/netns/, but can't see
namespaces created with other tools.
Creating the dummy file and bind mounting the correct procfs entry will
make ip aware of that namespace.
Add an ip netns subcommand to automate this task.

Signed-off-by: Matteo Croce <mcroce@...hat.com>
---
 ip/ipnetns.c        | 84 +++++++++++++++++++++++++++++++++++++++++++++
 man/man8/ip-netns.8 | 10 ++++++
 2 files changed, 94 insertions(+)

diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 03879b49..86b1a36b 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -28,6 +28,7 @@ static int usage(void)
 {
 	fprintf(stderr, "Usage: ip netns list\n");
 	fprintf(stderr, "       ip netns add NAME\n");
+	fprintf(stderr, "       ip netns attach NAME PID\n");
 	fprintf(stderr, "       ip netns set NAME NETNSID\n");
 	fprintf(stderr, "       ip [-all] netns delete [NAME]\n");
 	fprintf(stderr, "       ip netns identify [PID]\n");
@@ -811,6 +812,86 @@ static int netns_monitor(int argc, char **argv)
 	return 0;
 }
 
+static int netns_attach(int argc, char **argv)
+{
+	/* This function bind mounts an existing network namespace to a
+	 * well known location in the filesystem based on the name provided.
+	 * If everything succeeds, the result is the same as netns_add.
+	 *
+	 * The mount namespace is created so that any necessary
+	 * userspace tweaks like remounting /sys, or bind mounting
+	 * a new /etc/resolv.conf can be shared between users.
+	 */
+	char netns_path[PATH_MAX], proc_path[PATH_MAX];
+	const char *name;
+	int fd;
+	pid_t pid;
+	int made_netns_run_dir_mount = 0;
+
+	if (argc < 2) {
+		fprintf(stderr, "No netns name and PID specified\n");
+		return -1;
+	}
+	name = argv[0];
+
+	if (get_s32(&pid, argv[1], 0) || !pid) {
+		fprintf(stderr, "Invalid PID: %s\n", argv[1]);
+		return -1;
+	}
+
+	snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
+
+	if (create_netns_dir())
+		return -1;
+
+	/* Make it possible for network namespace mounts to propagate between
+	 * mount namespaces.  This makes it likely that a unmounting a network
+	 * namespace file in one namespace will unmount the network namespace
+	 * file in all namespaces allowing the network namespace to be freed
+	 * sooner.
+	 */
+	while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
+		/* Fail unless we need to make the mount point */
+		if (errno != EINVAL || made_netns_run_dir_mount) {
+			fprintf(stderr, "mount --make-shared %s failed: %s\n",
+				NETNS_RUN_DIR, strerror(errno));
+			return -1;
+		}
+
+		/* Upgrade NETNS_RUN_DIR to a mount point */
+		if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
+			fprintf(stderr, "mount --bind %s %s failed: %s\n",
+				NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
+			return -1;
+		}
+		made_netns_run_dir_mount = 1;
+	}
+
+	/* Create the filesystem state */
+	fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
+			netns_path, strerror(errno));
+		return -1;
+	}
+	close(fd);
+
+	snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
+
+	/* Bind the netns last so I can watch for it */
+	if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) {
+		fprintf(stderr, "Bind %s -> %s failed: %s\n",
+			proc_path, netns_path, strerror(errno));
+		goto out_delete;
+	}
+	return 0;
+out_delete:
+	if (unlink(netns_path) < 0)
+		fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
+			netns_path, strerror(errno));
+	return -1;
+}
+
 static int invalid_name(const char *name)
 {
 	return !*name || strlen(name) > NAME_MAX ||
@@ -866,6 +947,9 @@ int do_netns(int argc, char **argv)
 	if (matches(*argv, "monitor") == 0)
 		return netns_monitor(argc-1, argv+1);
 
+	if (matches(*argv, "attach") == 0)
+		return netns_attach(argc-1, argv+1);
+
 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
 	exit(-1);
 }
diff --git a/man/man8/ip-netns.8 b/man/man8/ip-netns.8
index d539f18b..39a10e76 100644
--- a/man/man8/ip-netns.8
+++ b/man/man8/ip-netns.8
@@ -19,6 +19,10 @@ ip-netns \- process network namespace management
 .B ip netns add
 .I NETNSNAME
 
+.ti -8
+.B ip netns attach
+.I NETNSNAME PID
+
 .ti -8
 .B ip [-all] netns del
 .RI "[ " NETNSNAME " ]"
@@ -89,6 +93,12 @@ This command displays all of the network namespaces in /var/run/netns
 If NAME is available in /var/run/netns/ this command creates a new
 network namespace and assigns NAME.
 
+.TP
+.B ip netns attach NAME PID - create a new named network namespace
+.sp
+If NAME is available in /var/run/netns/ this command attaches the network
+namespace of the process PID to NAME as if it were created with ip netns.
+
 .TP
 .B ip [-all] netns delete [ NAME ] - delete the name of a network namespace(s)
 .sp
-- 
2.20.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ