]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
attach: move to file descriptor only namespace interactions
authorChristian Brauner <christian.brauner@ubuntu.com>
Fri, 29 Jan 2021 14:13:51 +0000 (15:13 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Fri, 29 Jan 2021 15:34:56 +0000 (16:34 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/attach.c
src/lxc/namespace.c
src/lxc/namespace.h

index 4ac4979b6b34aed9ac63830235e7e4d6f0b255d8..ea9a018b9cc2b6c6a7d612a71935291088c7a7e1 100644 (file)
@@ -58,7 +58,8 @@ static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_D
 
 struct attach_context {
        int init_pid;
-       int dfd_pid;
+       int dfd_init_pid;
+       int dfd_self_pid;
        char *lsm_label;
        struct lxc_container *container;
        signed long personality;
@@ -116,7 +117,7 @@ static int get_personality(const char *name, const char *lxcpath,
 static int get_attach_context(struct attach_context *ctx,
                              struct lxc_container *container)
 {
-       __do_close int fd_status = -EBADF;
+       __do_close int dfd_self_pid = -EBADF, dfd_init_pid = -EBADF, fd_status = -EBADF;
        __do_free char *line = NULL;
        __do_fclose FILE *f_status = NULL;
        int ret;
@@ -130,15 +131,23 @@ static int get_attach_context(struct attach_context *ctx,
        if (ctx->init_pid < 0)
                return log_error(-1, "Failed to get init pid");
 
+       ret = snprintf(path, sizeof(path), "/proc/%d", lxc_raw_getpid());
+       if (ret < 0 || ret >= sizeof(path))
+               return ret_errno(EIO);
+
+       dfd_self_pid = openat(-EBADF, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_PATH | O_DIRECTORY);
+       if (dfd_self_pid < 0)
+               return -errno;
+
        ret = snprintf(path, sizeof(path), "/proc/%d", ctx->init_pid);
        if (ret < 0 || ret >= sizeof(path))
                return ret_errno(EIO);
 
-       ctx->dfd_pid = openat(-EBADF, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_PATH | O_DIRECTORY);
-       if (ctx->dfd_pid < 0)
+       dfd_init_pid = openat(-EBADF, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_PATH | O_DIRECTORY);
+       if (dfd_init_pid < 0)
                return -errno;
 
-       fd_status = openat(ctx->dfd_pid, "status", O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_RDONLY);
+       fd_status = openat(dfd_init_pid, "status", O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_RDONLY);
        if (fd_status < 0)
                return -errno;
 
@@ -162,6 +171,7 @@ static int get_attach_context(struct attach_context *ctx,
 
        ctx->lsm_ops = lsm_init_static();
 
+       /* Move to file descriptor-only lsm label retrieval. */
        ctx->lsm_label = ctx->lsm_ops->process_label_get(ctx->lsm_ops, ctx->init_pid);
        ctx->ns_inherited = 0;
        for (int i = 0; i < LXC_NS_MAX; i++)
@@ -177,38 +187,27 @@ static int get_attach_context(struct attach_context *ctx,
                        return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate new lxc config");
        }
 
+       ctx->dfd_init_pid = move_fd(dfd_init_pid);
+       ctx->dfd_self_pid = move_fd(dfd_self_pid);
        return 0;
 }
 
-/**
- * in_same_namespace - Check whether two processes are in the same namespace.
- * @pid1 - PID of the first process.
- * @pid2 - PID of the second process.
- * @ns   - Name of the namespace to check. Must correspond to one of the names
- *         for the namespaces as shown in /proc/<pid/ns/
- *
- * If the two processes are not in the same namespace returns an fd to the
- * namespace of the second process identified by @pid2. If the two processes are
- * in the same namespace returns -EINVAL, -1 if an error occurred.
- */
-static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
+static int in_same_namespace(int ns_fd_pid1, int ns_fd_pid2, const char *ns_path)
 {
        __do_close int ns_fd1 = -EBADF, ns_fd2 = -EBADF;
        int ret = -1;
        struct stat ns_st1, ns_st2;
 
-       ns_fd1 = lxc_preserve_ns(pid1, ns);
+       ns_fd1 = openat(ns_fd_pid1, ns_path, O_CLOEXEC | O_NOCTTY | O_RDONLY);
        if (ns_fd1 < 0) {
-               /* The kernel does not support this namespace. This is not an
-                * error.
-                */
+               /* The kernel does not support this namespace. This is not an error. */
                if (errno == ENOENT)
                        return -EINVAL;
 
                return -1;
        }
 
-       ns_fd2 = lxc_preserve_ns(pid2, ns);
+       ns_fd2 = openat(ns_fd_pid2, ns_path, O_CLOEXEC | O_NOCTTY | O_RDONLY);
        if (ns_fd2 < 0)
                return -1;
 
@@ -221,7 +220,8 @@ static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
                return -1;
 
        /* processes are in the same namespace */
-       if ((ns_st1.st_dev == ns_st2.st_dev) && (ns_st1.st_ino == ns_st2.st_ino))
+        if ((ns_st1.st_dev == ns_st2.st_dev) &&
+            (ns_st1.st_ino == ns_st2.st_ino))
                return -EINVAL;
 
        /* processes are in different namespaces */
@@ -231,16 +231,13 @@ static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
 static int get_attach_context_nsfds(struct attach_context *ctx,
                                    lxc_attach_options_t *options)
 {
-
-       pid_t pid_self = lxc_raw_getpid();
-
        for (int i = 0; i < LXC_NS_MAX; i++) {
                int j;
 
                if (options->namespaces & ns_info[i].clone_flag)
-                       ctx->ns_fd[i] = lxc_preserve_ns(ctx->init_pid, ns_info[i].proc_name);
+                       ctx->ns_fd[i] = openat(ctx->dfd_init_pid, ns_info[i].proc_path, O_CLOEXEC | O_NOCTTY | O_RDONLY);
                else if (ctx->ns_inherited & ns_info[i].clone_flag)
-                       ctx->ns_fd[i] = in_same_namespace(pid_self, ctx->init_pid, ns_info[i].proc_name);
+                       ctx->ns_fd[i] = in_same_namespace(ctx->dfd_self_pid, ctx->dfd_init_pid, ns_info[i].proc_path);
                else
                        continue;
 
@@ -248,13 +245,13 @@ static int get_attach_context_nsfds(struct attach_context *ctx,
                        continue;
 
                if (ctx->ns_fd[i] == -EINVAL) {
-                       DEBUG("Inheriting %s namespace from %d", ns_info[i].proc_name, pid_self);
+                       DEBUG("Inheriting %s namespace", ns_info[i].proc_name);
                        ctx->ns_inherited &= ~ns_info[i].clone_flag;
                        continue;
                }
 
                /* We failed to preserve the namespace. */
-               SYSERROR("Failed to attach to %s namespace of %d", ns_info[i].proc_name, pid_self);
+               SYSERROR("Failed to preserve %s namespace of %d", ns_info[i].proc_name, ctx->init_pid);
 
                /* Close all already opened file descriptors before we return an
                 * error, so we don't leak them.
@@ -278,7 +275,7 @@ static void put_attach_context(struct attach_context *ctx)
 {
        if (ctx) {
                free_disarm(ctx->lsm_label);
-               close_prot_errno_disarm(ctx->dfd_pid);
+               close_prot_errno_disarm(ctx->dfd_init_pid);
 
                if (ctx->container) {
                        lxc_container_put(ctx->container);
@@ -318,9 +315,13 @@ static int attach_context_container(struct attach_context *ctx)
 static bool attach_context_security_barrier(struct attach_context *ctx)
 {
        if (ctx) {
-               if (close(ctx->dfd_pid))
+               if (close(ctx->dfd_self_pid))
+                       return false;
+               ctx->dfd_self_pid = -EBADF;
+
+               if (close(ctx->dfd_init_pid))
                        return false;
-               ctx->dfd_pid = -EBADF;
+               ctx->dfd_init_pid = -EBADF;
        }
 
        return true;
index a46923078d8add3fec4dabe5a9b3ba32ad547a6a..5a1b3206cddca9b4e0e7b145b63def848036133e 100644 (file)
@@ -38,14 +38,14 @@ lxc_log_define(namespace, lxc);
  *        linux/fs/namespace.c:mntns_install().
  */
 const struct ns_info ns_info[LXC_NS_MAX] = {
-       [LXC_NS_USER]    = { "user",   CLONE_NEWUSER,   "CLONE_NEWUSER",   "LXC_USER_NS"    },
-       [LXC_NS_MNT]    =  { "mnt",    CLONE_NEWNS,     "CLONE_NEWNS",     "LXC_MNT_NS"     },
-       [LXC_NS_PID]    =  { "pid",    CLONE_NEWPID,    "CLONE_NEWPID",    "LXC_PID_NS"     },
-       [LXC_NS_UTS]    =  { "uts",    CLONE_NEWUTS,    "CLONE_NEWUTS",    "LXC_UTS_NS"     },
-       [LXC_NS_IPC]    =  { "ipc",    CLONE_NEWIPC,    "CLONE_NEWIPC",    "LXC_IPC_NS"     },
-       [LXC_NS_NET]    =  { "net",    CLONE_NEWNET,    "CLONE_NEWNET",    "LXC_NET_NS"     },
-       [LXC_NS_CGROUP] =  { "cgroup", CLONE_NEWCGROUP, "CLONE_NEWCGROUP", "LXC_CGROUP_NS"  },
-       [LXC_NS_TIME]   =  { "time",   CLONE_NEWTIME,   "CLONE_NEWTIME",   "LXC_TIME_NS"    },
+       [LXC_NS_USER]    = { "user",   "ns/user",   CLONE_NEWUSER,   "CLONE_NEWUSER",   "LXC_USER_NS"    },
+       [LXC_NS_MNT]    =  { "mnt",    "ns/mnt",    CLONE_NEWNS,     "CLONE_NEWNS",     "LXC_MNT_NS"     },
+       [LXC_NS_PID]    =  { "pid",    "ns/pid",    CLONE_NEWPID,    "CLONE_NEWPID",    "LXC_PID_NS"     },
+       [LXC_NS_UTS]    =  { "uts",    "ns/uts",    CLONE_NEWUTS,    "CLONE_NEWUTS",    "LXC_UTS_NS"     },
+       [LXC_NS_IPC]    =  { "ipc",    "ns/ipc",    CLONE_NEWIPC,    "CLONE_NEWIPC",    "LXC_IPC_NS"     },
+       [LXC_NS_NET]    =  { "net",    "ns/net",    CLONE_NEWNET,    "CLONE_NEWNET",    "LXC_NET_NS"     },
+       [LXC_NS_CGROUP] =  { "cgroup", "ns/cgroup", CLONE_NEWCGROUP, "CLONE_NEWCGROUP", "LXC_CGROUP_NS"  },
+       [LXC_NS_TIME]   =  { "time",   "ns/time",   CLONE_NEWTIME,   "CLONE_NEWTIME",   "LXC_TIME_NS"    },
 };
 
 int lxc_namespace_2_cloneflag(const char *namespace)
index 4e3fc3dfc1227570c2ba7b52827cf19034196e4d..6dd83be14f25937da522fd90e6bf1133f256f39f 100644 (file)
@@ -23,6 +23,7 @@ enum {
 
 __hidden extern const struct ns_info {
        const char *proc_name;
+       const char *proc_path;
        int clone_flag;
        const char *flag_name;
        const char *env_name;