Unverified Commit 562924dc by Serge Hallyn Committed by GitHub

Merge pull request #1893 from brauner/2017-11-01/attach_handle_namespace_inheritance

attach: handle namespace inheritance
parents da3dcce6 877f3a04
...@@ -233,6 +233,8 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) ...@@ -233,6 +233,8 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
} }
info->lsm_label = lsm_process_label_get(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; return info;
...@@ -241,11 +243,24 @@ on_error: ...@@ -241,11 +243,24 @@ on_error:
return NULL; 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) static void lxc_proc_put_context_info(struct lxc_proc_context_info *ctx)
{ {
free(ctx->lsm_label); free(ctx->lsm_label);
if (ctx->container) if (ctx->container)
lxc_container_put(ctx->container); lxc_container_put(ctx->container);
lxc_proc_close_ns_fd(ctx);
free(ctx); free(ctx);
} }
...@@ -300,73 +315,22 @@ out: ...@@ -300,73 +315,22 @@ out:
return ret; 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, ret;
int i, j, ret, saved_errno;
ret = access("/proc/self/ns", X_OK);
if (ret) {
ERROR("Does this kernel version support namespaces?");
return -1;
}
for (i = 0; i < LXC_NS_MAX; i++) { for (i = 0; i < LXC_NS_MAX; i++) {
fd[i] = -EINVAL; if (ctx->ns_fd[i] < 0)
/* 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)
continue; continue;
if (setns(fd[i], 0) < 0) { ret = setns(ctx->ns_fd[i], ns_info[i].clone_flag);
saved_errno = errno; if (ret < 0) {
for (j = i; j < LXC_NS_MAX; j++)
close(fd[j]);
errno = saved_errno;
SYSERROR("Failed to attach to %s namespace of %d", SYSERROR("Failed to attach to %s namespace of %d",
ns_info[i].proc_name, pid); ns_info[i].proc_name, pid);
return -1; return -1;
} }
DEBUG("Attached to %s namespace of %d", ns_info[i].proc_name, pid); DEBUG("Attached to %s namespace of %d", ns_info[i].proc_name, pid);
close(fd[i]);
} }
return 0; return 0;
...@@ -844,13 +808,19 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -844,13 +808,19 @@ int lxc_attach(const char *name, const char *lxcpath,
lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_exec_t exec_function, void *exec_payload,
lxc_attach_options_t *options, pid_t *attached_process) lxc_attach_options_t *options, pid_t *attached_process)
{ {
int ret, status; int i, ret, status;
int ipc_sockets[2]; int ipc_sockets[2];
char *cwd, *new_cwd; char *cwd, *new_cwd;
signed long personality; signed long personality;
pid_t attached_pid, expected, init_pid, pid; pid_t attached_pid, expected, init_pid, pid;
struct lxc_proc_context_info *init_ctx; 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) if (!options)
options = &attach_static_default_options; options = &attach_static_default_options;
...@@ -894,11 +864,59 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -894,11 +864,59 @@ int lxc_attach(const char *name, const char *lxcpath,
/* call failed */ /* call failed */
if (options->namespaces == -1) { if (options->namespaces == -1) {
ERROR("Failed to automatically determine the " ERROR("Failed to automatically determine the "
"namespaces which the container uses."); "namespaces which the container uses");
free(cwd); free(cwd);
lxc_proc_put_context_info(init_ctx); lxc_proc_put_context_info(init_ctx);
return -1; 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 /* Create a socket pair for IPC communication; set SOCK_CLOEXEC in order
...@@ -964,6 +982,9 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -964,6 +982,9 @@ int lxc_attach(const char *name, const char *lxcpath,
int procfd = -1; int procfd = -1;
pid_t to_cleanup_pid = pid; 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 /* Initial thread, we close the socket that is for the
* subprocesses. * subprocesses.
*/ */
...@@ -1128,18 +1149,17 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1128,18 +1149,17 @@ int lxc_attach(const char *name, const char *lxcpath,
rexit(-1); 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 /* Attach now, create another subprocess later, since pid namespaces
* only really affect the children of the current process. * 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) { if (ret < 0) {
ERROR("Failed to enter namespaces."); ERROR("Failed to enter namespaces.");
shutdown(ipc_sockets[1], SHUT_RDWR); shutdown(ipc_sockets[1], SHUT_RDWR);
rexit(-1); rexit(-1);
} }
/* close namespace file descriptors */
lxc_proc_close_ns_fd(init_ctx);
/* Attach succeeded, try to cwd. */ /* Attach succeeded, try to cwd. */
if (options->initial_cwd) if (options->initial_cwd)
......
...@@ -24,9 +24,12 @@ ...@@ -24,9 +24,12 @@
#ifndef __LXC_ATTACH_H #ifndef __LXC_ATTACH_H
#define __LXC_ATTACH_H #define __LXC_ATTACH_H
#include <stdbool.h>
#include <lxc/attach_options.h> #include <lxc/attach_options.h>
#include <sys/types.h> #include <sys/types.h>
#include "namespace.h"
struct lxc_conf; struct lxc_conf;
struct lxc_proc_context_info { struct lxc_proc_context_info {
...@@ -34,6 +37,8 @@ struct lxc_proc_context_info { ...@@ -34,6 +37,8 @@ struct lxc_proc_context_info {
struct lxc_container *container; struct lxc_container *container;
signed long personality; signed long personality;
unsigned long long capability_mask; unsigned long long capability_mask;
int ns_inherited;
int ns_fd[LXC_NS_MAX];
}; };
extern int lxc_attach(const char *name, const char *lxcpath, extern int lxc_attach(const char *name, const char *lxcpath,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment