[lxc-devel] [PATCH 1/1] Fix unprivileged networking

Serge Hallyn serge.hallyn at ubuntu.com
Tue Feb 18 21:12:52 UTC 2014


If we are unprivileged and have asked for a veth device, then create
a pipe over which to pass the veth names.

Network-related todos:
1. set mtu on the container side of veth device
2. set mtu in lxc-user-nic.  Note that this probably requires an
   update to the /etc/lxc/lxc-usernet file :(

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/conf.c  | 16 ++++++++++--
 src/lxc/start.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index d482d22..c9dd7ac 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -3114,13 +3114,23 @@ static int unpriv_assign_nic(struct lxc_netdev *netdev, pid_t pid)
 	token = strtok_r(buffer, ":", &saveptr);
 	if (!token)
 		return -1;
-	netdev->name = strdup(token);
+	netdev->name = malloc(IFNAMSIZ+1);
+	if (!netdev->name) {
+		ERROR("Out of memory");
+		return -1;
+	}
+	memset(netdev->name, 0, IFNAMSIZ+1);
+	strncpy(netdev->name, token, IFNAMSIZ);
 
 	/* fill netdev->veth_attr.pair field */
 	token = strtok_r(NULL, ":", &saveptr);
 	if (!token)
 		return -1;
 	netdev->priv.veth_attr.pair = strdup(token);
+	if (!netdev->priv.veth_attr.pair) {
+		ERROR("Out of memory");
+		return -1;
+	}
 
 	return 0;
 }
@@ -3139,7 +3149,9 @@ int lxc_assign_network(struct lxc_list *network, pid_t pid)
 		if (netdev->type == LXC_NET_VETH && !am_root) {
 			if (unpriv_assign_nic(netdev, pid))
 				return -1;
-			// TODO fill in netdev->ifindex and name
+			// lxc-user-nic has moved the nic to the new ns.
+			// unpriv_assign_nic() fills in netdev->name.
+			// netdev->ifindex will be filed in at setup_netdev.
 			continue;
 		}
 
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 5b3b6eb..2faad8e 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -563,6 +563,52 @@ static int must_drop_cap_sys_boot(struct lxc_conf *conf)
 	return 0;
 }
 
+/*
+ * netpipe is used in the unprivileged case to transfer the ifindexes
+ * from parent to child
+ */
+static int netpipe = -1;
+
+static inline int count_veths(struct lxc_list *network)
+{
+	struct lxc_list *iterator;
+	struct lxc_netdev *netdev;
+	int count = 0;
+
+	lxc_list_for_each(iterator, network) {
+		netdev = iterator->elem;
+		if (netdev->type != LXC_NET_VETH)
+			continue;
+		count++;
+	}
+	return count;
+}
+
+static int read_unpriv_netifindex(struct lxc_list *network)
+{
+	struct lxc_list *iterator;
+	struct lxc_netdev *netdev;
+
+	if (netpipe == -1)
+		return 0;
+	lxc_list_for_each(iterator, network) {
+		netdev = iterator->elem;
+		if (netdev->type != LXC_NET_VETH)
+			continue;
+		if (!(netdev->name = malloc(IFNAMSIZ))) {
+			ERROR("Out of memory");
+			close(netpipe);
+			return -1;
+		}
+		if (read(netpipe, netdev->name, IFNAMSIZ) != IFNAMSIZ) {
+			close(netpipe);
+			return -1;
+		}
+	}
+	close(netpipe);
+	return 0;
+}
+
 static int do_start(void *data)
 {
 	struct lxc_handler *handler = data;
@@ -597,6 +643,9 @@ static int do_start(void *data)
 	if (lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE))
 		return -1;
 
+	if (read_unpriv_netifindex(&handler->conf->network) < 0)
+		goto out_warn_father;
+
 	/*
 	 * if we are in a new user namespace, become root there to have
 	 * privilege over our namespace
@@ -728,6 +777,7 @@ static int lxc_spawn(struct lxc_handler *handler)
 	const char *name = handler->name;
 	int saved_ns_fd[LXC_NS_MAX];
 	int preserve_mask = 0, i;
+	int netpipepair[2], nveths;
 
 	for (i = 0; i < LXC_NS_MAX; i++)
 		if (handler->conf->inherit_ns_fd[i] != -1)
@@ -816,6 +866,15 @@ static int lxc_spawn(struct lxc_handler *handler)
 	if (attach_ns(handler->conf->inherit_ns_fd) < 0)
 		goto out_delete_net;
 
+	if (am_unpriv() && (nveths = count_veths(&handler->conf->network))) {
+		if (pipe(netpipepair) < 0) {
+			SYSERROR("Error creating pipe");
+			goto out_delete_net;
+		}
+		/* store netpipe in the global var for do_start's use */
+		netpipe = netpipepair[0];
+	}
+
 	/* Create a process in a new set of namespaces */
 	handler->pid = lxc_clone(do_start, handler, handler->clone_flags);
 	if (handler->pid < 0) {
@@ -857,6 +916,23 @@ static int lxc_spawn(struct lxc_handler *handler)
 		}
 	}
 
+	if (netpipe != -1) {
+		struct lxc_list *iterator;
+		struct lxc_netdev *netdev;
+
+		close(netpipe);
+		lxc_list_for_each(iterator, &handler->conf->network) {
+			netdev = iterator->elem;
+			if (netdev->type != LXC_NET_VETH)
+				continue;
+			if (write(netpipepair[1], netdev->name, IFNAMSIZ) != IFNAMSIZ) {
+				ERROR("Error writing veth name to container");
+				goto out_delete_net;
+			}
+		}
+		close(netpipepair[1]);
+	}
+
 	/* map the container uids - the container became an invalid
 	 * userid the moment it was cloned with CLONE_NEWUSER - this
 	 * call doesn't change anything immediately, but allows the
-- 
1.9.rc1



More information about the lxc-devel mailing list