]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
Fix unprivileged networking
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Tue, 18 Feb 2014 21:12:52 +0000 (15:12 -0600)
committerStéphane Graber <stgraber@ubuntu.com>
Tue, 18 Feb 2014 21:36:34 +0000 (16:36 -0500)
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@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
src/lxc/conf.c
src/lxc/start.c

index d482d2220f5f6a638137203fa9c0ffd61a8b4634..c9dd7ac5a28fcb8648677c6b7f4dc3bce854a2db 100644 (file)
@@ -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;
                }
 
index 5b3b6eb11215f476b694a00a20005c6c64901d28..2faad8edf6a6289e7619a75492b740f0b51bec45 100644 (file)
@@ -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