]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
attach: handle namespace inheritance
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 1 Nov 2017 09:44:18 +0000 (10:44 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Thu, 9 Nov 2017 00:22:01 +0000 (01:22 +0100)
We need to have lxc_attach() distinguish between a caller specifying specific
namespaces to attach to and a caller not requesting specific namespaces. The
latter is taken by lxc_attach() to mean that all namespaces will be attached.
This also needs to include all inherited namespaces.

Closes #1890.
Closes #1897.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/attach.c
src/lxc/attach.h

index fd36429b4a4d0490d8f1d25e08153573a4417cfe..79a83c3c49bc12623ae08553e01d8b1dd578becb 100644 (file)
@@ -225,6 +225,8 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
        }
 
        info->lsm_label = lsm_process_label_get(pid);
+       info->ns_inherited = 0;
+       memset(info->ns_fd, -1, sizeof(int) * LXC_NS_MAX);
 
        return info;
 
@@ -233,11 +235,24 @@ on_error:
        return NULL;
 }
 
+static inline void lxc_proc_close_ns_fd(struct lxc_proc_context_info *ctx)
+{
+       int i;
+
+       for (i = 0; i < LXC_NS_MAX; i++) {
+               if (ctx->ns_fd[i] < 0)
+                       continue;
+               close(ctx->ns_fd[i]);
+               ctx->ns_fd[i] = -EBADF;
+       }
+}
+
 static void lxc_proc_put_context_info(struct lxc_proc_context_info *ctx)
 {
        free(ctx->lsm_label);
        if (ctx->container)
                lxc_container_put(ctx->container);
+       lxc_proc_close_ns_fd(ctx);
        free(ctx);
 }
 
@@ -292,73 +307,22 @@ out:
        return ret;
 }
 
-static int lxc_attach_to_ns(pid_t pid, int which)
+static int lxc_attach_to_ns(pid_t pid, struct lxc_proc_context_info *ctx)
 {
-       int fd[LXC_NS_MAX];
-       int i, j, ret, saved_errno;
-
-       ret = access("/proc/self/ns", X_OK);
-       if (ret) {
-               ERROR("Does this kernel version support namespaces?");
-               return -1;
-       }
+       int i, ret;
 
        for (i = 0; i < LXC_NS_MAX; i++) {
-               fd[i] = -EINVAL;
-
-               /* Ignore if we are not supposed to attach to that namespace. */
-               if (which != -1 && !(which & ns_info[i].clone_flag)) {
-                       /* We likely inherited the namespace from someone. We
-                        * need to check whether we are already in the same
-                        * namespace. If we are then there's nothing for us to
-                        * do. If we are not then we need to attach to it.
-                        */
-                       fd[i] = in_same_namespace(getpid(), pid, ns_info[i].proc_name);
-                       /* we are in the same namespace */
-                       if (fd[i] == -EINVAL) {
-                               DEBUG("Inheriting %s namespace from %d",
-                                     ns_info[i].proc_name, pid);
-                               continue;
-                       }
-               }
-
-               if (fd[i] == -EINVAL)
-                       fd[i] = lxc_preserve_ns(pid, ns_info[i].proc_name);
-               if (fd[i] < 0) {
-                       saved_errno = errno;
-
-                       /* Close all already opened file descriptors before we
-                        * return an error, so we don't leak them.
-                        */
-                       for (j = 0; j < i; j++)
-                               close(fd[j]);
-
-                       errno = saved_errno;
-                       SYSERROR("Failed to attach to %s namespace of %d",
-                                ns_info[i].proc_name, pid);
-                       return -1;
-               }
-       }
-
-       for (i = 0; i < LXC_NS_MAX; i++) {
-               if (fd[i] < 0)
+               if (ctx->ns_fd[i] < 0)
                        continue;
 
-               if (setns(fd[i], 0) < 0) {
-                       saved_errno = errno;
-
-                       for (j = i; j < LXC_NS_MAX; j++)
-                               close(fd[j]);
-
-                       errno = saved_errno;
+               ret = setns(ctx->ns_fd[i], ns_info[i].clone_flag);
+               if (ret < 0) {
                        SYSERROR("Failed to attach to %s namespace of %d",
                                 ns_info[i].proc_name, pid);
                        return -1;
                }
 
                DEBUG("Attached to %s namespace of %d", ns_info[i].proc_name, pid);
-
-               close(fd[i]);
        }
 
        return 0;
@@ -805,13 +769,19 @@ int lxc_attach(const char *name, const char *lxcpath,
               lxc_attach_exec_t exec_function, void *exec_payload,
               lxc_attach_options_t *options, pid_t *attached_process)
 {
-       int ret, status;
+       int i, ret, status;
        int ipc_sockets[2];
        char *cwd, *new_cwd;
        signed long personality;
        pid_t attached_pid, expected, init_pid, pid;
        struct lxc_proc_context_info *init_ctx;
 
+       ret = access("/proc/self/ns", X_OK);
+       if (ret) {
+               ERROR("Does this kernel version support namespaces?");
+               return -1;
+       }
+
        if (!options)
                options = &attach_static_default_options;
 
@@ -852,11 +822,59 @@ int lxc_attach(const char *name, const char *lxcpath,
                /* call failed */
                if (options->namespaces == -1) {
                        ERROR("Failed to automatically determine the "
-                             "namespaces which the container uses.");
+                             "namespaces which the container uses");
                        free(cwd);
                        lxc_proc_put_context_info(init_ctx);
                        return -1;
                }
+
+               for (i = 0; i < LXC_NS_MAX; i++) {
+                       if (ns_info[i].clone_flag & CLONE_NEWCGROUP)
+                               if (!(options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) ||
+                                   !cgns_supported())
+                                       continue;
+
+                       if (ns_info[i].clone_flag & options->namespaces)
+                               continue;
+
+                       init_ctx->ns_inherited |= ns_info[i].clone_flag;
+               }
+       }
+
+       pid = getpid();
+       for (i = 0; i < LXC_NS_MAX; i++) {
+               int j, saved_errno;
+
+               if (options->namespaces & ns_info[i].clone_flag)
+                       init_ctx->ns_fd[i] = lxc_preserve_ns(init_pid, ns_info[i].proc_name);
+               else if (init_ctx->ns_inherited & ns_info[i].clone_flag)
+                       init_ctx->ns_fd[i] = in_same_namespace(pid, init_pid, ns_info[i].proc_name);
+               else
+                       continue;
+               if (init_ctx->ns_fd[i] >= 0)
+                       continue;
+
+               if (init_ctx->ns_fd[i] == -EINVAL) {
+                       DEBUG("Inheriting %s namespace from %d",
+                             ns_info[i].proc_name, pid);
+                       init_ctx->ns_inherited &= ~ns_info[i].clone_flag;
+                       continue;
+               }
+
+               /* We failed to preserve the namespace. */
+               saved_errno = errno;
+               /* Close all already opened file descriptors before we return an
+                * error, so we don't leak them.
+                */
+               for (j = 0; j < i; j++)
+                       close(init_ctx->ns_fd[j]);
+
+               errno = saved_errno;
+               SYSERROR("Failed to attach to %s namespace of %d",
+                        ns_info[i].proc_name, pid);
+               free(cwd);
+               lxc_proc_put_context_info(init_ctx);
+               return -1;
        }
 
        /* Create a socket pair for IPC communication; set SOCK_CLOEXEC in order
@@ -922,6 +940,9 @@ int lxc_attach(const char *name, const char *lxcpath,
                int procfd = -1;
                pid_t to_cleanup_pid = pid;
 
+               /* close file namespace descriptors */
+               lxc_proc_close_ns_fd(init_ctx);
+
                /* Initial thread, we close the socket that is for the
                 * subprocesses.
                 */
@@ -1081,18 +1102,17 @@ int lxc_attach(const char *name, const char *lxcpath,
                rexit(-1);
        }
 
-       if ((options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) && cgns_supported())
-               options->namespaces |= CLONE_NEWCGROUP;
-
        /* Attach now, create another subprocess later, since pid namespaces
         * only really affect the children of the current process.
         */
-       ret = lxc_attach_to_ns(init_pid, options->namespaces);
+       ret = lxc_attach_to_ns(init_pid, init_ctx);
        if (ret < 0) {
                ERROR("Failed to enter namespaces.");
                shutdown(ipc_sockets[1], SHUT_RDWR);
                rexit(-1);
        }
+       /* close namespace file descriptors */
+       lxc_proc_close_ns_fd(init_ctx);
 
        /* Attach succeeded, try to cwd. */
        if (options->initial_cwd)
index fb6bc5a079030e8ca7155ed63a9a48868ae7b6e3..4bf9578ee95aaf3cf9a47c4c08a4c89bd59c8305 100644 (file)
 #ifndef __LXC_ATTACH_H
 #define __LXC_ATTACH_H
 
+#include <stdbool.h>
 #include <lxc/attach_options.h>
 #include <sys/types.h>
 
+#include "namespace.h"
+
 struct lxc_conf;
 
 struct lxc_proc_context_info {
@@ -34,6 +37,8 @@ struct lxc_proc_context_info {
        struct lxc_container *container;
        signed long personality;
        unsigned long long capability_mask;
+       int ns_inherited;
+       int ns_fd[LXC_NS_MAX];
 };
 
 extern int lxc_attach(const char *name, const char *lxcpath,