From: Serge Hallyn Date: Tue, 18 Feb 2014 21:12:52 +0000 (-0600) Subject: Fix unprivileged networking X-Git-Tag: lxc-1.0.0.rc4~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=658979c5f9276e7b69c9f0e51be7d9e22dd49848;p=thirdparty%2Flxc.git Fix unprivileged networking 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 Acked-by: Stéphane Graber --- diff --git a/src/lxc/conf.c b/src/lxc/conf.c index d482d2220..c9dd7ac5a 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 5b3b6eb11..2faad8edf 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