From: Christian Brauner Date: Wed, 1 Nov 2017 09:44:18 +0000 (+0100) Subject: attach: handle namespace inheritance X-Git-Tag: lxc-2.0.10~596 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=044640874aa49c3a4f62f8dd8ab351b42433aa11;p=thirdparty%2Flxc.git attach: handle namespace inheritance 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 --- diff --git a/src/lxc/attach.c b/src/lxc/attach.c index fd36429b4..79a83c3c4 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -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) diff --git a/src/lxc/attach.h b/src/lxc/attach.h index fb6bc5a07..4bf9578ee 100644 --- a/src/lxc/attach.h +++ b/src/lxc/attach.h @@ -24,9 +24,12 @@ #ifndef __LXC_ATTACH_H #define __LXC_ATTACH_H +#include #include #include +#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,