Unverified Commit 0e24c560 by Stéphane Graber Committed by GitHub

Merge pull request #3638 from brauner/2021-01-28/fixes

attach: improve attach codepaths
parents 0fa84a8c 581b849a
...@@ -61,6 +61,18 @@ if test "x$valid_compiler" = "xno"; then ...@@ -61,6 +61,18 @@ if test "x$valid_compiler" = "xno"; then
AC_MSG_ERROR([Sorry, your compiler is too old - please upgrade it]) AC_MSG_ERROR([Sorry, your compiler is too old - please upgrade it])
fi fi
AC_PROG_GCC_TRADITIONAL
AC_ENABLE_SHARED
AC_ENABLE_STATIC
# Check binaries
AC_PROG_SED
case $CC in clang*)
AC_CHECK_TOOL([AR], llvm-ar)
AC_CHECK_TOOL([NM], llvm-nm)
AC_CHECK_TOOL([OBJCOPY], llvm-objcopy)
AC_CHECK_TOOL([RANLIB], llvm-ranlib)
esac
# libtool # libtool
LT_INIT LT_INIT
AC_SUBST([LIBTOOL_DEPS]) AC_SUBST([LIBTOOL_DEPS])
...@@ -731,10 +743,6 @@ AC_CHECK_TYPES([struct rtnl_link_stats64], [], [], [[#include <linux/if_link.h>] ...@@ -731,10 +743,6 @@ AC_CHECK_TYPES([struct rtnl_link_stats64], [], [], [[#include <linux/if_link.h>]
AX_PTHREAD AX_PTHREAD
AC_SEARCH_LIBS(clock_gettime, [rt]) AC_SEARCH_LIBS(clock_gettime, [rt])
# Check for some standard binaries
AC_PROG_GCC_TRADITIONAL
AC_PROG_SED
# See if we support thread-local storage. # See if we support thread-local storage.
LXC_CHECK_TLS LXC_CHECK_TLS
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "mount_utils.h" #include "mount_utils.h"
#include "namespace.h" #include "namespace.h"
#include "process_utils.h" #include "process_utils.h"
#include "sync.h"
#include "syscall_wrappers.h" #include "syscall_wrappers.h"
#include "terminal.h" #include "terminal.h"
#include "utils.h" #include "utils.h"
...@@ -55,33 +56,122 @@ lxc_log_define(attach, lxc); ...@@ -55,33 +56,122 @@ lxc_log_define(attach, lxc);
/* Define default options if no options are supplied by the user. */ /* Define default options if no options are supplied by the user. */
static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_DEFAULT; static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_DEFAULT;
static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) struct attach_context {
int init_pid;
int dfd_init_pid;
int dfd_self_pid;
char *lsm_label;
struct lxc_container *container;
signed long personality;
unsigned long long capability_mask;
int ns_inherited;
int ns_fd[LXC_NS_MAX];
struct lsm_ops *lsm_ops;
};
static inline bool sync_wake_pid(int fd, pid_t pid)
{
return lxc_write_nointr(fd, &pid, sizeof(pid_t)) == sizeof(pid_t);
}
static inline bool sync_wait_pid(int fd, pid_t *pid)
{
return lxc_read_nointr(fd, pid, sizeof(pid_t)) == sizeof(pid_t);
}
static inline bool sync_wake_fd(int fd, int fd_send)
{
return lxc_abstract_unix_send_fds(fd, &fd_send, 1, NULL, 0) > 0;
}
static inline bool sync_wait_fd(int fd, int *fd_recv)
{
return lxc_abstract_unix_recv_fds(fd, fd_recv, 1, NULL, 0) > 0;
}
static struct attach_context *alloc_attach_context(void)
{
struct attach_context *ctx;
ctx = zalloc(sizeof(struct attach_context));
if (!ctx)
return ret_set_errno(NULL, ENOMEM);
ctx->dfd_self_pid = -EBADF;
ctx->dfd_init_pid = -EBADF;
for (int i = 0; i < LXC_NS_MAX; i++)
ctx->ns_fd[i] = -EBADF;
return ctx;
}
static int get_personality(const char *name, const char *lxcpath,
signed long *personality)
{
__do_free char *p = NULL;
signed long per;
p = lxc_cmd_get_config_item(name, "lxc.arch", lxcpath);
if (!p) {
*personality = LXC_ARCH_UNCHANGED;
return 0;
}
per = lxc_config_parse_arch(p);
if (per == LXC_ARCH_UNCHANGED)
return ret_errno(EINVAL);
*personality = per;
return 0;
}
static int get_attach_context(struct attach_context *ctx,
struct lxc_container *container)
{ {
__do_close int dfd_self_pid = -EBADF, dfd_init_pid = -EBADF, fd_status = -EBADF;
__do_free char *line = NULL; __do_free char *line = NULL;
__do_fclose FILE *proc_file = NULL; __do_fclose FILE *f_status = NULL;
__do_free struct lxc_proc_context_info *info = NULL;
int ret; int ret;
bool found; bool found;
char proc_fn[LXC_PROC_STATUS_LEN]; char path[LXC_PROC_PID_LEN];
size_t line_bufsz = 0; size_t line_bufsz = 0;
/* Read capabilities. */ ctx->container = container;
ret = snprintf(proc_fn, LXC_PROC_STATUS_LEN, "/proc/%d/status", pid);
if (ret < 0 || ret >= LXC_PROC_STATUS_LEN)
return NULL;
proc_file = fopen(proc_fn, "re"); ctx->init_pid = lxc_cmd_get_init_pid(container->name, container->config_path);
if (!proc_file) if (ctx->init_pid < 0)
return log_error_errno(NULL, errno, "Failed to open %s", proc_fn); return log_error(-1, "Failed to get init pid");
info = calloc(1, sizeof(*info)); ret = snprintf(path, sizeof(path), "/proc/%d", lxc_raw_getpid());
if (!info) if (ret < 0 || ret >= sizeof(path))
return NULL; 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);
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(dfd_init_pid, "status", O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_RDONLY);
if (fd_status < 0)
return -errno;
f_status = fdopen(fd_status, "re");
if (!f_status)
return log_error_errno(-errno, errno, "Failed to open file descriptor %d", fd_status);
move_fd(fd_status);
found = false; found = false;
while (getline(&line, &line_bufsz, proc_file) != -1) { while (getline(&line, &line_bufsz, f_status) != -1) {
ret = sscanf(line, "CapBnd: %llx", &info->capability_mask); ret = sscanf(line, "CapBnd: %llx", &ctx->capability_mask);
if (ret != EOF && ret == 1) { if (ret != EOF && ret == 1) {
found = true; found = true;
break; break;
...@@ -89,66 +179,45 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) ...@@ -89,66 +179,45 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
} }
if (!found) if (!found)
return log_error_errno(NULL, ENOENT, "Failed to read capability bounding set from %s", proc_fn); return log_error_errno(-ENOENT, ENOENT, "Failed to read capability bounding set from %s/status", path);
info->lsm_ops = lsm_init();
info->lsm_label = info->lsm_ops->process_label_get(info->lsm_ops, pid);
info->ns_inherited = 0;
for (int i = 0; i < LXC_NS_MAX; i++)
info->ns_fd[i] = -EBADF;
return move_ptr(info); ctx->lsm_ops = lsm_init_static();
}
static inline void lxc_proc_close_ns_fd(struct lxc_proc_context_info *ctx) /* Move to file descriptor-only lsm label retrieval. */
{ ctx->lsm_label = ctx->lsm_ops->process_label_get(ctx->lsm_ops, ctx->init_pid);
for (int i = 0; i < LXC_NS_MAX; i++) ctx->ns_inherited = 0;
close_prot_errno_disarm(ctx->ns_fd[i]);
}
static void lxc_proc_put_context_info(struct lxc_proc_context_info *ctx) ret = get_personality(container->name, container->config_path, &ctx->personality);
{ if (ret)
free_disarm(ctx->lsm_label); return log_error_errno(ret, errno, "Failed to get personality of the container");
if (ctx->container) { if (!ctx->container->lxc_conf) {
lxc_container_put(ctx->container); ctx->container->lxc_conf = lxc_conf_init();
ctx->container = NULL; if (!ctx->container->lxc_conf)
return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate new lxc config");
} }
lxc_proc_close_ns_fd(ctx); ctx->dfd_init_pid = move_fd(dfd_init_pid);
free(ctx); ctx->dfd_self_pid = move_fd(dfd_self_pid);
return 0;
} }
/** static int in_same_namespace(int ns_fd_pid1, int ns_fd_pid2, const char *ns_path)
* 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)
{ {
__do_close int ns_fd1 = -EBADF, ns_fd2 = -EBADF; __do_close int ns_fd1 = -EBADF, ns_fd2 = -EBADF;
int ret = -1; int ret = -1;
struct stat ns_st1, ns_st2; 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) { if (ns_fd1 < 0) {
/* The kernel does not support this namespace. This is not an /* The kernel does not support this namespace. This is not an error. */
* error.
*/
if (errno == ENOENT) if (errno == ENOENT)
return -EINVAL; return -EINVAL;
return -1; 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) if (ns_fd2 < 0)
return -1; return -1;
...@@ -161,14 +230,74 @@ static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns) ...@@ -161,14 +230,74 @@ static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
return -1; return -1;
/* processes are in the same namespace */ /* 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; return -EINVAL;
/* processes are in different namespaces */ /* processes are in different namespaces */
return move_fd(ns_fd2); return move_fd(ns_fd2);
} }
static int lxc_attach_to_ns(pid_t pid, struct lxc_proc_context_info *ctx) static int get_attach_context_nsfds(struct attach_context *ctx,
lxc_attach_options_t *options)
{
for (int i = 0; i < LXC_NS_MAX; i++) {
int j;
if (options->namespaces & ns_info[i].clone_flag)
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(ctx->dfd_self_pid, ctx->dfd_init_pid, ns_info[i].proc_path);
else
continue;
if (ctx->ns_fd[i] >= 0)
continue;
if (ctx->ns_fd[i] == -EINVAL) {
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 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.
*/
for (j = 0; j < i; j++)
close_prot_errno_disarm(ctx->ns_fd[j]);
return -1;
}
return 0;
}
static inline void close_nsfds(struct attach_context *ctx)
{
for (int i = 0; i < LXC_NS_MAX; i++)
close_prot_errno_disarm(ctx->ns_fd[i]);
}
static void put_attach_context(struct attach_context *ctx)
{
if (ctx) {
free_disarm(ctx->lsm_label);
close_prot_errno_disarm(ctx->dfd_init_pid);
if (ctx->container) {
lxc_container_put(ctx->container);
ctx->container = NULL;
}
close_nsfds(ctx);
free(ctx);
}
}
static int attach_context_container(struct attach_context *ctx)
{ {
for (int i = 0; i < LXC_NS_MAX; i++) { for (int i = 0; i < LXC_NS_MAX; i++) {
int ret; int ret;
...@@ -178,16 +307,36 @@ static int lxc_attach_to_ns(pid_t pid, struct lxc_proc_context_info *ctx) ...@@ -178,16 +307,36 @@ static int lxc_attach_to_ns(pid_t pid, struct lxc_proc_context_info *ctx)
ret = setns(ctx->ns_fd[i], ns_info[i].clone_flag); ret = setns(ctx->ns_fd[i], ns_info[i].clone_flag);
if (ret < 0) if (ret < 0)
return log_error_errno(-1, return log_error_errno(-1, errno,
errno, "Failed to attach to %s namespace of %d", "Failed to attach to %s namespace of %d",
ns_info[i].proc_name, pid); ns_info[i].proc_name, ctx->init_pid);
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, ctx->init_pid);
} }
return 0; return 0;
} }
/*
* Place anything in here that needs to be get rid of before we move into the
* container's context and fail hard if we can't.
*/
static bool attach_context_security_barrier(struct attach_context *ctx)
{
if (ctx) {
if (close(ctx->dfd_self_pid))
return false;
ctx->dfd_self_pid = -EBADF;
if (close(ctx->dfd_init_pid))
return false;
ctx->dfd_init_pid = -EBADF;
}
return true;
}
int lxc_attach_remount_sys_proc(void) int lxc_attach_remount_sys_proc(void)
{ {
int ret; int ret;
...@@ -223,7 +372,7 @@ int lxc_attach_remount_sys_proc(void) ...@@ -223,7 +372,7 @@ int lxc_attach_remount_sys_proc(void)
return 0; return 0;
} }
static int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx) static int drop_capabilities(struct attach_context *ctx)
{ {
int last_cap; int last_cap;
...@@ -242,7 +391,7 @@ static int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx) ...@@ -242,7 +391,7 @@ static int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
return 0; return 0;
} }
static int lxc_attach_set_environment(struct lxc_proc_context_info *init_ctx, static int lxc_attach_set_environment(struct attach_context *ctx,
enum lxc_attach_env_policy_t policy, enum lxc_attach_env_policy_t policy,
char **extra_env, char **extra_keep) char **extra_env, char **extra_keep)
{ {
...@@ -259,7 +408,7 @@ static int lxc_attach_set_environment(struct lxc_proc_context_info *init_ctx, ...@@ -259,7 +408,7 @@ static int lxc_attach_set_environment(struct lxc_proc_context_info *init_ctx,
for (count = 0; extra_keep[count]; count++) for (count = 0; extra_keep[count]; count++)
; ;
extra_keep_store = calloc(count, sizeof(char *)); extra_keep_store = zalloc(count * sizeof(char *));
if (!extra_keep_store) if (!extra_keep_store)
return -1; return -1;
...@@ -327,8 +476,8 @@ static int lxc_attach_set_environment(struct lxc_proc_context_info *init_ctx, ...@@ -327,8 +476,8 @@ static int lxc_attach_set_environment(struct lxc_proc_context_info *init_ctx,
return log_warn(-1, "Failed to set environment variable"); return log_warn(-1, "Failed to set environment variable");
/* Set container environment variables.*/ /* Set container environment variables.*/
if (init_ctx && init_ctx->container && init_ctx->container->lxc_conf) { if (ctx && ctx->container && ctx->container->lxc_conf) {
lxc_list_for_each(iterator, &init_ctx->container->lxc_conf->environment) { lxc_list_for_each(iterator, &ctx->container->lxc_conf->environment) {
char *env_tmp; char *env_tmp;
env_tmp = strdup((char *)iterator->elem); env_tmp = strdup((char *)iterator->elem);
...@@ -614,48 +763,38 @@ static bool no_new_privs(struct lxc_container *c, lxc_attach_options_t *options) ...@@ -614,48 +763,38 @@ static bool no_new_privs(struct lxc_container *c, lxc_attach_options_t *options)
return c->set_config_item(c, "lxc.no_new_privs", val); return c->set_config_item(c, "lxc.no_new_privs", val);
} }
static signed long get_personality(const char *name, const char *lxcpath) struct attach_payload {
{
__do_free char *p = NULL;
p = lxc_cmd_get_config_item(name, "lxc.arch", lxcpath);
if (!p)
return -1;
return lxc_config_parse_arch(p);
}
struct attach_clone_payload {
int ipc_socket; int ipc_socket;
int terminal_pts_fd; int terminal_pts_fd;
lxc_attach_options_t *options; lxc_attach_options_t *options;
struct lxc_proc_context_info *init_ctx; struct attach_context *ctx;
lxc_attach_exec_t exec_function; lxc_attach_exec_t exec_function;
void *exec_payload; void *exec_payload;
}; };
static void lxc_put_attach_clone_payload(struct attach_clone_payload *p) static void put_attach_payload(struct attach_payload *p)
{ {
close_prot_errno_disarm(p->ipc_socket); close_prot_errno_disarm(p->ipc_socket);
close_prot_errno_disarm(p->terminal_pts_fd); close_prot_errno_disarm(p->terminal_pts_fd);
if (p->init_ctx) { if (p->ctx) {
lxc_proc_put_context_info(p->init_ctx); put_attach_context(p->ctx);
p->init_ctx = NULL; p->ctx = NULL;
} }
} }
__noreturn static void do_attach(struct attach_clone_payload *payload) __noreturn static void do_attach(struct attach_payload *ap)
{ {
int lsm_fd, ret; int lsm_fd, ret;
uid_t new_uid; uid_t new_uid;
gid_t new_gid; gid_t new_gid;
uid_t ns_root_uid = 0; uid_t ns_root_uid = 0;
gid_t ns_root_gid = 0; gid_t ns_root_gid = 0;
lxc_attach_options_t* options = payload->options; lxc_attach_options_t* options = ap->options;
struct lxc_proc_context_info* init_ctx = payload->init_ctx; struct attach_context *ctx = ap->ctx;
struct lxc_conf *conf = ctx->container->lxc_conf;
bool needs_lsm = (options->namespaces & CLONE_NEWNS) && bool needs_lsm = (options->namespaces & CLONE_NEWNS) &&
(options->attach_flags & LXC_ATTACH_LSM) && (options->attach_flags & LXC_ATTACH_LSM) &&
init_ctx->lsm_label; ctx->lsm_label;
char *lsm_label = NULL; char *lsm_label = NULL;
/* A description of the purpose of this functionality is provided in the /* A description of the purpose of this functionality is provided in the
...@@ -672,26 +811,28 @@ __noreturn static void do_attach(struct attach_clone_payload *payload) ...@@ -672,26 +811,28 @@ __noreturn static void do_attach(struct attach_clone_payload *payload)
TRACE("Remounted \"/proc\" and \"/sys\""); TRACE("Remounted \"/proc\" and \"/sys\"");
} }
/* Now perform additional attachments. */ /* Now perform additional attachments. */
#if HAVE_SYS_PERSONALITY_H #if HAVE_SYS_PERSONALITY_H
if (options->attach_flags & LXC_ATTACH_SET_PERSONALITY) { if (options->attach_flags & LXC_ATTACH_SET_PERSONALITY) {
long new_personality; long new_personality;
if (options->personality < 0) if (options->personality < 0)
new_personality = init_ctx->personality; new_personality = ctx->personality;
else else
new_personality = options->personality; new_personality = options->personality;
if (new_personality != LXC_ARCH_UNCHANGED) {
ret = personality(new_personality); ret = personality(new_personality);
if (ret < 0) if (ret < 0)
goto on_error; goto on_error;
TRACE("Set new personality"); TRACE("Set new personality");
} }
}
#endif #endif
if (options->attach_flags & LXC_ATTACH_DROP_CAPABILITIES) { if (options->attach_flags & LXC_ATTACH_DROP_CAPABILITIES) {
ret = lxc_attach_drop_privs(init_ctx); ret = drop_capabilities(ctx);
if (ret < 0) if (ret < 0)
goto on_error; goto on_error;
...@@ -701,7 +842,7 @@ __noreturn static void do_attach(struct attach_clone_payload *payload) ...@@ -701,7 +842,7 @@ __noreturn static void do_attach(struct attach_clone_payload *payload)
/* Always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL) /* Always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL)
* if you want this to be a no-op). * if you want this to be a no-op).
*/ */
ret = lxc_attach_set_environment(init_ctx, ret = lxc_attach_set_environment(ctx,
options->env_policy, options->env_policy,
options->extra_env_vars, options->extra_env_vars,
options->extra_keep_env); options->extra_keep_env);
...@@ -722,11 +863,8 @@ __noreturn static void do_attach(struct attach_clone_payload *payload) ...@@ -722,11 +863,8 @@ __noreturn static void do_attach(struct attach_clone_payload *payload)
* set{g,u}id(). * set{g,u}id().
*/ */
if (needs_lsm) { if (needs_lsm) {
ret = lxc_abstract_unix_recv_fds(payload->ipc_socket, &lsm_fd, 1, NULL, 0); if (!sync_wait_fd(ap->ipc_socket, ATTACH_SYNC_LSM(&lsm_fd))) {
if (ret <= 0) {
if (ret < 0)
SYSERROR("Failed to receive lsm label fd"); SYSERROR("Failed to receive lsm label fd");
goto on_error; goto on_error;
} }
...@@ -781,18 +919,17 @@ __noreturn static void do_attach(struct attach_clone_payload *payload) ...@@ -781,18 +919,17 @@ __noreturn static void do_attach(struct attach_clone_payload *payload)
if (options->attach_flags & LXC_ATTACH_LSM_LABEL) if (options->attach_flags & LXC_ATTACH_LSM_LABEL)
lsm_label = options->lsm_label; lsm_label = options->lsm_label;
if (!lsm_label) if (!lsm_label)
lsm_label = init_ctx->lsm_label; lsm_label = ctx->lsm_label;
ret = init_ctx->lsm_ops->process_label_set_at(init_ctx->lsm_ops, lsm_fd, ret = ctx->lsm_ops->process_label_set_at(ctx->lsm_ops, lsm_fd,
lsm_label, on_exec); lsm_label, on_exec);
close(lsm_fd); close_prot_errno_disarm(lsm_fd);
if (ret < 0) if (ret < 0)
goto on_error; goto on_error;
TRACE("Set %s LSM label to \"%s\"", init_ctx->lsm_ops->name, init_ctx->lsm_label); TRACE("Set %s LSM label to \"%s\"", ctx->lsm_ops->name, ctx->lsm_label);
} }
if ((init_ctx->container && init_ctx->container->lxc_conf && if ((ctx->container && conf && conf->no_new_privs) ||
init_ctx->container->lxc_conf->no_new_privs) ||
(options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) { (options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) {
ret = prctl(PR_SET_NO_NEW_PRIVS, prctl_arg(1), prctl_arg(0), ret = prctl(PR_SET_NO_NEW_PRIVS, prctl_arg(1), prctl_arg(0),
prctl_arg(0), prctl_arg(0)); prctl_arg(0), prctl_arg(0));
...@@ -802,24 +939,21 @@ __noreturn static void do_attach(struct attach_clone_payload *payload) ...@@ -802,24 +939,21 @@ __noreturn static void do_attach(struct attach_clone_payload *payload)
TRACE("Set PR_SET_NO_NEW_PRIVS"); TRACE("Set PR_SET_NO_NEW_PRIVS");
} }
if (init_ctx->container && init_ctx->container->lxc_conf && if (ctx->container && conf && conf->seccomp.seccomp) {
init_ctx->container->lxc_conf->seccomp.seccomp) {
struct lxc_conf *conf = init_ctx->container->lxc_conf;
ret = lxc_seccomp_load(conf); ret = lxc_seccomp_load(conf);
if (ret < 0) if (ret < 0)
goto on_error; goto on_error;
TRACE("Loaded seccomp profile"); TRACE("Loaded seccomp profile");
ret = lxc_seccomp_send_notifier_fd(&conf->seccomp, payload->ipc_socket); ret = lxc_seccomp_send_notifier_fd(&conf->seccomp, ap->ipc_socket);
if (ret < 0) if (ret < 0)
goto on_error; goto on_error;
} }
close_prot_errno_disarm(payload->ipc_socket); close_prot_errno_disarm(ap->ipc_socket);
lxc_proc_put_context_info(init_ctx); put_attach_context(ctx);
payload->init_ctx = NULL; ap->ctx = NULL;
/* The following is done after the communication socket is shut down. /* The following is done after the communication socket is shut down.
* That way, all errors that might (though unlikely) occur up until this * That way, all errors that might (though unlikely) occur up until this
...@@ -865,13 +999,13 @@ __noreturn static void do_attach(struct attach_clone_payload *payload) ...@@ -865,13 +999,13 @@ __noreturn static void do_attach(struct attach_clone_payload *payload)
} }
if (options->attach_flags & LXC_ATTACH_TERMINAL) { if (options->attach_flags & LXC_ATTACH_TERMINAL) {
ret = lxc_terminal_prepare_login(payload->terminal_pts_fd); ret = lxc_terminal_prepare_login(ap->terminal_pts_fd);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to prepare terminal file descriptor %d", payload->terminal_pts_fd); SYSERROR("Failed to prepare terminal file descriptor %d", ap->terminal_pts_fd);
goto on_error; goto on_error;
} }
TRACE("Prepared terminal file descriptor %d", payload->terminal_pts_fd); TRACE("Prepared terminal file descriptor %d", ap->terminal_pts_fd);
} }
/* Avoid unnecessary syscalls. */ /* Avoid unnecessary syscalls. */
...@@ -890,10 +1024,10 @@ __noreturn static void do_attach(struct attach_clone_payload *payload) ...@@ -890,10 +1024,10 @@ __noreturn static void do_attach(struct attach_clone_payload *payload)
goto on_error; goto on_error;
/* We're done, so we can now do whatever the user intended us to do. */ /* We're done, so we can now do whatever the user intended us to do. */
_exit(payload->exec_function(payload->exec_payload)); _exit(ap->exec_function(ap->exec_payload));
on_error: on_error:
lxc_put_attach_clone_payload(payload); put_attach_payload(ap);
ERROR("Failed to attach to container"); ERROR("Failed to attach to container");
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
...@@ -954,24 +1088,15 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -954,24 +1088,15 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
void *exec_payload, lxc_attach_options_t *options, void *exec_payload, lxc_attach_options_t *options,
pid_t *attached_process) pid_t *attached_process)
{ {
__do_free char *cwd = NULL; int ret_parent = -1;
int i, ret, status; struct lxc_epoll_descr descr = {};
int ret;
char *name, *lxcpath;
int ipc_sockets[2]; int ipc_sockets[2];
char *new_cwd; pid_t attached_pid, pid, to_cleanup_pid;
signed long personality; struct attach_context *ctx;
pid_t attached_pid, init_pid, pid;
struct lxc_proc_context_info *init_ctx;
struct lxc_terminal terminal; struct lxc_terminal terminal;
struct lxc_conf *conf; struct lxc_conf *conf;
char *name, *lxcpath;
struct attach_clone_payload payload = {0};
int ret_parent = -1;
pid_t to_cleanup_pid;
struct lxc_epoll_descr descr = {0};
ret = access("/proc/self/ns", X_OK);
if (ret)
return log_error_errno(-1, errno, "Does this kernel version support namespaces?");
if (!container) if (!container)
return ret_set_errno(-1, EINVAL); return ret_set_errno(-1, EINVAL);
...@@ -985,62 +1110,35 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -985,62 +1110,35 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
if (!options) if (!options)
options = &attach_static_default_options; options = &attach_static_default_options;
init_pid = lxc_cmd_get_init_pid(name, lxcpath); ctx = alloc_attach_context();
if (init_pid < 0) { if (!ctx) {
lxc_container_put(container); lxc_container_put(container);
return log_error(-1, "Failed to get init pid"); return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate attach context");
} }
init_ctx = lxc_proc_get_context_info(init_pid); ret = get_attach_context(ctx, container);
if (!init_ctx) { if (ret) {
ERROR("Failed to get context of init process: %ld", (long)init_pid); put_attach_context(ctx);
lxc_container_put(container); return log_error(-1, "Failed to get attach context");
return -1;
} }
init_ctx->container = container; conf = ctx->container->lxc_conf;
personality = get_personality(name, lxcpath);
if (init_ctx->personality < 0) {
ERROR("Failed to get personality of the container");
lxc_proc_put_context_info(init_ctx);
return -1;
}
init_ctx->personality = personality;
if (!init_ctx->container->lxc_conf) { if (!fetch_seccomp(ctx->container, options))
init_ctx->container->lxc_conf = lxc_conf_init();
if (!init_ctx->container->lxc_conf) {
lxc_proc_put_context_info(init_ctx);
return -1;
}
}
conf = init_ctx->container->lxc_conf;
if (!conf)
return log_error_errno(-EINVAL, EINVAL, "Missing container confifg");
if (!fetch_seccomp(init_ctx->container, options))
WARN("Failed to get seccomp policy"); WARN("Failed to get seccomp policy");
if (!no_new_privs(init_ctx->container, options)) if (!no_new_privs(ctx->container, options))
WARN("Could not determine whether PR_SET_NO_NEW_PRIVS is set"); WARN("Could not determine whether PR_SET_NO_NEW_PRIVS is set");
cwd = getcwd(NULL, 0); /* Determine which namespaces the container was created with. */
/* Determine which namespaces the container was created with
* by asking lxc-start, if necessary.
*/
if (options->namespaces == -1) { if (options->namespaces == -1) {
options->namespaces = lxc_cmd_get_clone_flags(name, lxcpath); options->namespaces = lxc_cmd_get_clone_flags(name, lxcpath);
/* call failed */
if (options->namespaces == -1) { if (options->namespaces == -1) {
ERROR("Failed to automatically determine the " put_attach_context(ctx);
"namespaces which the container uses"); return log_error(-1, "Failed to automatically determine the namespaces which the container uses");
lxc_proc_put_context_info(init_ctx);
return -1;
} }
for (i = 0; i < LXC_NS_MAX; i++) { for (int i = 0; i < LXC_NS_MAX; i++) {
if (ns_info[i].clone_flag & CLONE_NEWCGROUP) if (ns_info[i].clone_flag & CLONE_NEWCGROUP)
if (!(options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) || if (!(options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) ||
!cgns_supported()) !cgns_supported())
...@@ -1049,52 +1147,21 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1049,52 +1147,21 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
if (ns_info[i].clone_flag & options->namespaces) if (ns_info[i].clone_flag & options->namespaces)
continue; continue;
init_ctx->ns_inherited |= ns_info[i].clone_flag; ctx->ns_inherited |= ns_info[i].clone_flag;
} }
} }
pid = lxc_raw_getpid(); ret = get_attach_context_nsfds(ctx, options);
if (ret) {
for (i = 0; i < LXC_NS_MAX; i++) { lxc_container_put(container);
int j; return log_error(-1, "Failed to get namespace file descriptors");
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. */
SYSERROR("Failed to attach to %s namespace of %d",
ns_info[i].proc_name, pid);
/* 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]);
lxc_proc_put_context_info(init_ctx);
return -1;
} }
if (options->attach_flags & LXC_ATTACH_TERMINAL) { if (options->attach_flags & LXC_ATTACH_TERMINAL) {
ret = lxc_attach_terminal(name, lxcpath, conf, &terminal); ret = lxc_attach_terminal(name, lxcpath, conf, &terminal);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to setup new terminal"); put_attach_context(ctx);
lxc_proc_put_context_info(init_ctx); return log_error(-1, "Failed to setup new terminal");
return -1;
} }
terminal.log_fd = options->log_fd; terminal.log_fd = options->log_fd;
...@@ -1137,9 +1204,8 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1137,9 +1204,8 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
*/ */
ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
if (ret < 0) { if (ret < 0) {
SYSERROR("Could not set up required IPC mechanism for attaching"); put_attach_context(ctx);
lxc_proc_put_context_info(init_ctx); return log_error_errno(-1, errno, "Could not set up required IPC mechanism for attaching");
return -1;
} }
/* Create intermediate subprocess, two reasons: /* Create intermediate subprocess, two reasons:
...@@ -1151,12 +1217,13 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1151,12 +1217,13 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
*/ */
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
SYSERROR("Failed to create first subprocess"); put_attach_context(ctx);
lxc_proc_put_context_info(init_ctx); return log_error_errno(-1, errno, "Failed to create first subprocess");
return -1;
} }
if (pid == 0) { if (pid == 0) {
char *cwd, *new_cwd;
/* close unneeded file descriptors */ /* close unneeded file descriptors */
close_prot_errno_disarm(ipc_sockets[0]); close_prot_errno_disarm(ipc_sockets[0]);
...@@ -1167,28 +1234,42 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1167,28 +1234,42 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
} }
/* Wait for the parent to have setup cgroups. */ /* Wait for the parent to have setup cgroups. */
ret = lxc_read_nointr(ipc_sockets[1], &status, sizeof(status)); if (!sync_wait(ipc_sockets[1], ATTACH_SYNC_CGROUP)) {
if (ret != sizeof(status)) { shutdown(ipc_sockets[1], SHUT_RDWR);
put_attach_context(ctx);
_exit(EXIT_FAILURE);
}
if (!attach_context_security_barrier(ctx)) {
shutdown(ipc_sockets[1], SHUT_RDWR); shutdown(ipc_sockets[1], SHUT_RDWR);
lxc_proc_put_context_info(init_ctx); put_attach_context(ctx);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
TRACE("Intermediate process starting to initialize"); TRACE("Intermediate process starting to initialize");
/* Attach now, create another subprocess later, since pid namespaces cwd = getcwd(NULL, 0);
* only really affect the children of the current process.
/*
* Attach now, create another subprocess later, since pid
* namespaces only really affect the children of the current
* process.
*
* Note that this is a crucial barrier. We're no moving into
* the container's context so we need to make sure to not leak
* anything sensitive. That especially means things such as
* open file descriptors!
*/ */
ret = lxc_attach_to_ns(init_pid, init_ctx); ret = attach_context_container(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);
lxc_proc_put_context_info(init_ctx); put_attach_context(ctx);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* close namespace file descriptors */ /* close namespace file descriptors */
lxc_proc_close_ns_fd(init_ctx); close_nsfds(ctx);
/* Attach succeeded, try to cwd. */ /* Attach succeeded, try to cwd. */
if (options->initial_cwd) if (options->initial_cwd)
...@@ -1200,24 +1281,27 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1200,24 +1281,27 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
if (ret < 0) if (ret < 0)
WARN("Could not change directory to \"%s\"", new_cwd); WARN("Could not change directory to \"%s\"", new_cwd);
} }
free_disarm(cwd);
/* Create attached process. */ /* Create attached process. */
payload.ipc_socket = ipc_sockets[1];
payload.options = options;
payload.init_ctx = init_ctx;
payload.terminal_pts_fd = terminal.pty;
payload.exec_function = exec_function;
payload.exec_payload = exec_payload;
pid = lxc_raw_clone(CLONE_PARENT, NULL); pid = lxc_raw_clone(CLONE_PARENT, NULL);
if (pid < 0) { if (pid < 0) {
SYSERROR("Failed to clone attached process"); SYSERROR("Failed to clone attached process");
shutdown(ipc_sockets[1], SHUT_RDWR); shutdown(ipc_sockets[1], SHUT_RDWR);
lxc_proc_put_context_info(init_ctx); put_attach_context(ctx);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
if (pid == 0) { if (pid == 0) {
struct attach_payload ap = {
.ipc_socket = ipc_sockets[1],
.options = options,
.ctx = ctx,
.terminal_pts_fd = terminal.pty,
.exec_function = exec_function,
.exec_payload = exec_payload,
};
if (options->attach_flags & LXC_ATTACH_TERMINAL) { if (options->attach_flags & LXC_ATTACH_TERMINAL) {
ret = lxc_terminal_signal_sigmask_safe_blocked(&terminal); ret = lxc_terminal_signal_sigmask_safe_blocked(&terminal);
if (ret < 0) { if (ret < 0) {
...@@ -1226,15 +1310,15 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1226,15 +1310,15 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
} }
} }
do_attach(&payload); /* Does not return. */
do_attach(&ap);
} }
if (options->attach_flags & LXC_ATTACH_TERMINAL) if (options->attach_flags & LXC_ATTACH_TERMINAL)
lxc_attach_terminal_close_pts(&terminal); lxc_attach_terminal_close_pts(&terminal);
/* Tell grandparent the pid of the pid of the newly created child. */ /* Tell grandparent the pid of the pid of the newly created child. */
ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid)); if (!sync_wake_pid(ipc_sockets[1], ATTACH_SYNC_PID(pid))) {
if (ret != sizeof(pid)) {
/* If this really happens here, this is very unfortunate, since /* If this really happens here, this is very unfortunate, since
* the parent will not know the pid of the attached process and * the parent will not know the pid of the attached process and
* will not be able to wait for it (and we won't either due to * will not be able to wait for it (and we won't either due to
...@@ -1242,23 +1326,22 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1242,23 +1326,22 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
* attached process will remain a zombie. * attached process will remain a zombie.
*/ */
shutdown(ipc_sockets[1], SHUT_RDWR); shutdown(ipc_sockets[1], SHUT_RDWR);
lxc_proc_put_context_info(init_ctx); put_attach_context(ctx);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
TRACE("Sending pid %d of attached process", pid); TRACE("Sending pid %d of attached process", pid);
/* The rest is in the hands of the initial and the attached process. */ /* The rest is in the hands of the initial and the attached process. */
lxc_proc_put_context_info(init_ctx); put_attach_context(ctx);
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
to_cleanup_pid = pid; to_cleanup_pid = pid;
/* close unneeded file descriptors */ /* close unneeded file descriptors */
close(ipc_sockets[1]); close_prot_errno_disarm(ipc_sockets[1]);
free_disarm(cwd); close_nsfds(ctx);
lxc_proc_close_ns_fd(init_ctx);
if (options->attach_flags & LXC_ATTACH_TERMINAL) if (options->attach_flags & LXC_ATTACH_TERMINAL)
lxc_attach_terminal_close_pts(&terminal); lxc_attach_terminal_close_pts(&terminal);
...@@ -1309,22 +1392,19 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1309,22 +1392,19 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
} }
/* Let the child process know to go ahead. */ /* Let the child process know to go ahead. */
status = 0; if (!sync_wake(ipc_sockets[0], ATTACH_SYNC_CGROUP))
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
if (ret != sizeof(status))
goto close_mainloop; goto close_mainloop;
TRACE("Told intermediate process to start initializing"); TRACE("Told intermediate process to start initializing");
/* Get pid of attached process from intermediate process. */ /* Get pid of attached process from intermediate process. */
ret = lxc_read_nointr(ipc_sockets[0], &attached_pid, sizeof(attached_pid)); if (!sync_wait_pid(ipc_sockets[0], ATTACH_SYNC_PID(&attached_pid)))
if (ret != sizeof(attached_pid))
goto close_mainloop; goto close_mainloop;
TRACE("Received pid %d of attached process in parent pid namespace", attached_pid); TRACE("Received pid %d of attached process in parent pid namespace", attached_pid);
/* Ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313. */ /* Ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313. */
if (options->stdin_fd == 0) { if (options->stdin_fd == STDIN_FILENO) {
signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN); signal(SIGQUIT, SIG_IGN);
} }
...@@ -1341,13 +1421,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1341,13 +1421,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
/* Open LSM fd and send it to child. */ /* Open LSM fd and send it to child. */
if ((options->namespaces & CLONE_NEWNS) && if ((options->namespaces & CLONE_NEWNS) &&
(options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) { (options->attach_flags & LXC_ATTACH_LSM) && ctx->lsm_label) {
__do_close int labelfd = -EBADF; __do_close int labelfd = -EBADF;
bool on_exec; bool on_exec;
ret = -1;
on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false; on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false;
labelfd = init_ctx->lsm_ops->process_label_fd_get(init_ctx->lsm_ops, labelfd = ctx->lsm_ops->process_label_fd_get(ctx->lsm_ops,
attached_pid, on_exec); attached_pid, on_exec);
if (labelfd < 0) if (labelfd < 0)
goto close_mainloop; goto close_mainloop;
...@@ -1355,9 +1434,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1355,9 +1434,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
TRACE("Opened LSM label file descriptor %d", labelfd); TRACE("Opened LSM label file descriptor %d", labelfd);
/* Send child fd of the LSM security module to write to. */ /* Send child fd of the LSM security module to write to. */
ret = lxc_abstract_unix_send_fds(ipc_sockets[0], &labelfd, 1, NULL, 0); if (!sync_wake_fd(ipc_sockets[0], ATTACH_SYNC_LSM(labelfd))) {
if (ret <= 0) {
if (ret < 0)
SYSERROR("Failed to send lsm label fd"); SYSERROR("Failed to send lsm label fd");
goto close_mainloop; goto close_mainloop;
} }
...@@ -1384,8 +1461,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1384,8 +1461,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
/* Now shut down communication with child, we're done. */ /* Now shut down communication with child, we're done. */
shutdown(ipc_sockets[0], SHUT_RDWR); shutdown(ipc_sockets[0], SHUT_RDWR);
close(ipc_sockets[0]); close_prot_errno_disarm(ipc_sockets[0]);
ipc_sockets[0] = -1;
ret_parent = 0; ret_parent = 0;
to_cleanup_pid = -1; to_cleanup_pid = -1;
...@@ -1405,7 +1481,7 @@ close_mainloop: ...@@ -1405,7 +1481,7 @@ close_mainloop:
on_error: on_error:
if (ipc_sockets[0] >= 0) { if (ipc_sockets[0] >= 0) {
shutdown(ipc_sockets[0], SHUT_RDWR); shutdown(ipc_sockets[0], SHUT_RDWR);
close(ipc_sockets[0]); close_prot_errno_disarm(ipc_sockets[0]);
} }
if (to_cleanup_pid > 0) if (to_cleanup_pid > 0)
...@@ -1416,7 +1492,7 @@ on_error: ...@@ -1416,7 +1492,7 @@ on_error:
lxc_terminal_conf_free(&terminal); lxc_terminal_conf_free(&terminal);
} }
lxc_proc_put_context_info(init_ctx); put_attach_context(ctx);
return ret_parent; return ret_parent;
} }
......
...@@ -11,16 +11,7 @@ ...@@ -11,16 +11,7 @@
#include "namespace.h" #include "namespace.h"
struct lxc_conf; struct lxc_conf;
struct lxc_container;
struct lxc_proc_context_info {
char *lsm_label;
struct lxc_container *container;
signed long personality;
unsigned long long capability_mask;
int ns_inherited;
int ns_fd[LXC_NS_MAX];
struct lsm_ops *lsm_ops;
};
__hidden extern int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, __hidden extern int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
void *exec_payload, lxc_attach_options_t *options, void *exec_payload, lxc_attach_options_t *options,
......
...@@ -124,7 +124,7 @@ typedef struct lxc_attach_options_t { ...@@ -124,7 +124,7 @@ typedef struct lxc_attach_options_t {
{ \ { \
/* .attach_flags = */ LXC_ATTACH_DEFAULT, \ /* .attach_flags = */ LXC_ATTACH_DEFAULT, \
/* .namespaces = */ -1, \ /* .namespaces = */ -1, \
/* .personality = */ -1, \ /* .personality = */ 0xffffffff, \
/* .initial_cwd = */ NULL, \ /* .initial_cwd = */ NULL, \
/* .uid = */ (uid_t)-1, \ /* .uid = */ (uid_t)-1, \
/* .gid = */ (gid_t)-1, \ /* .gid = */ (gid_t)-1, \
......
...@@ -3031,7 +3031,7 @@ signed long lxc_config_parse_arch(const char *arch) ...@@ -3031,7 +3031,7 @@ signed long lxc_config_parse_arch(const char *arch)
return pername[i].per; return pername[i].per;
#endif #endif
return -1; return LXC_ARCH_UNCHANGED;
} }
int lxc_fill_elevated_privileges(char *flaglist, int *flags) int lxc_fill_elevated_privileges(char *flaglist, int *flags)
......
...@@ -78,7 +78,12 @@ __hidden extern bool lxc_config_define_load(struct lxc_list *defines, struct lxc ...@@ -78,7 +78,12 @@ __hidden extern bool lxc_config_define_load(struct lxc_list *defines, struct lxc
__hidden extern void lxc_config_define_free(struct lxc_list *defines); __hidden extern void lxc_config_define_free(struct lxc_list *defines);
/* needed for lxc-attach */ #define LXC_ARCH_UNCHANGED 0xffffffffL
/*
* Parse personality of the container. Returns LXC_ARCH_UNCHANGED if the
* personality is not know.
* (Used during attach.)
*/
__hidden extern signed long lxc_config_parse_arch(const char *arch); __hidden extern signed long lxc_config_parse_arch(const char *arch);
__hidden extern int lxc_fill_elevated_privileges(char *flaglist, int *flags); __hidden extern int lxc_fill_elevated_privileges(char *flaglist, int *flags);
......
...@@ -21,7 +21,7 @@ __hidden extern struct lsm_ops *lsm_apparmor_ops_init(void); ...@@ -21,7 +21,7 @@ __hidden extern struct lsm_ops *lsm_apparmor_ops_init(void);
__hidden extern struct lsm_ops *lsm_selinux_ops_init(void); __hidden extern struct lsm_ops *lsm_selinux_ops_init(void);
__hidden extern struct lsm_ops *lsm_nop_ops_init(void); __hidden extern struct lsm_ops *lsm_nop_ops_init(void);
struct lsm_ops *lsm_init(void) struct lsm_ops *lsm_init_static(void)
{ {
struct lsm_ops *ops = NULL; struct lsm_ops *ops = NULL;
......
...@@ -33,6 +33,6 @@ struct lsm_ops { ...@@ -33,6 +33,6 @@ struct lsm_ops {
int (*process_label_set_at)(struct lsm_ops *ops, int label_fd, const char *label, bool on_exec); int (*process_label_set_at)(struct lsm_ops *ops, int label_fd, const char *label, bool on_exec);
}; };
__hidden extern struct lsm_ops *lsm_init(void); __hidden extern struct lsm_ops *lsm_init_static(void);
#endif /* __LXC_LSM_H */ #endif /* __LXC_LSM_H */
...@@ -293,6 +293,19 @@ ...@@ -293,6 +293,19 @@
* + * +
* \0 = 1 * \0 = 1
*/ */
#define LXC_PROC_PID_LEN \
(6 + INTTYPE_TO_STRLEN(pid_t) + 1)
/* /proc/ = 6
* +
* <pid-as-str> = INTTYPE_TO_STRLEN(pid_t)
* +
* /fd/ = 4
* +
* <fd-as-str> = INTTYPE_TO_STRLEN(int)
* +
* \0 = 1
*/
#define LXC_PROC_PID_FD_LEN \ #define LXC_PROC_PID_FD_LEN \
(6 + INTTYPE_TO_STRLEN(pid_t) + 4 + INTTYPE_TO_STRLEN(int) + 1) (6 + INTTYPE_TO_STRLEN(pid_t) + 4 + INTTYPE_TO_STRLEN(int) + 1)
......
...@@ -38,14 +38,14 @@ lxc_log_define(namespace, lxc); ...@@ -38,14 +38,14 @@ lxc_log_define(namespace, lxc);
* linux/fs/namespace.c:mntns_install(). * linux/fs/namespace.c:mntns_install().
*/ */
const struct ns_info ns_info[LXC_NS_MAX] = { const struct ns_info ns_info[LXC_NS_MAX] = {
[LXC_NS_USER] = { "user", CLONE_NEWUSER, "CLONE_NEWUSER", "LXC_USER_NS" }, [LXC_NS_USER] = { "user", "ns/user", CLONE_NEWUSER, "CLONE_NEWUSER", "LXC_USER_NS" },
[LXC_NS_MNT] = { "mnt", CLONE_NEWNS, "CLONE_NEWNS", "LXC_MNT_NS" }, [LXC_NS_MNT] = { "mnt", "ns/mnt", CLONE_NEWNS, "CLONE_NEWNS", "LXC_MNT_NS" },
[LXC_NS_PID] = { "pid", CLONE_NEWPID, "CLONE_NEWPID", "LXC_PID_NS" }, [LXC_NS_PID] = { "pid", "ns/pid", CLONE_NEWPID, "CLONE_NEWPID", "LXC_PID_NS" },
[LXC_NS_UTS] = { "uts", CLONE_NEWUTS, "CLONE_NEWUTS", "LXC_UTS_NS" }, [LXC_NS_UTS] = { "uts", "ns/uts", CLONE_NEWUTS, "CLONE_NEWUTS", "LXC_UTS_NS" },
[LXC_NS_IPC] = { "ipc", CLONE_NEWIPC, "CLONE_NEWIPC", "LXC_IPC_NS" }, [LXC_NS_IPC] = { "ipc", "ns/ipc", CLONE_NEWIPC, "CLONE_NEWIPC", "LXC_IPC_NS" },
[LXC_NS_NET] = { "net", CLONE_NEWNET, "CLONE_NEWNET", "LXC_NET_NS" }, [LXC_NS_NET] = { "net", "ns/net", CLONE_NEWNET, "CLONE_NEWNET", "LXC_NET_NS" },
[LXC_NS_CGROUP] = { "cgroup", CLONE_NEWCGROUP, "CLONE_NEWCGROUP", "LXC_CGROUP_NS" }, [LXC_NS_CGROUP] = { "cgroup", "ns/cgroup", CLONE_NEWCGROUP, "CLONE_NEWCGROUP", "LXC_CGROUP_NS" },
[LXC_NS_TIME] = { "time", CLONE_NEWTIME, "CLONE_NEWTIME", "LXC_TIME_NS" }, [LXC_NS_TIME] = { "time", "ns/time", CLONE_NEWTIME, "CLONE_NEWTIME", "LXC_TIME_NS" },
}; };
int lxc_namespace_2_cloneflag(const char *namespace) int lxc_namespace_2_cloneflag(const char *namespace)
......
...@@ -23,6 +23,7 @@ enum { ...@@ -23,6 +23,7 @@ enum {
__hidden extern const struct ns_info { __hidden extern const struct ns_info {
const char *proc_name; const char *proc_name;
const char *proc_path;
int clone_flag; int clone_flag;
const char *flag_name; const char *flag_name;
const char *env_name; const char *env_name;
......
...@@ -728,7 +728,7 @@ int lxc_init(const char *name, struct lxc_handler *handler) ...@@ -728,7 +728,7 @@ int lxc_init(const char *name, struct lxc_handler *handler)
if (status_fd < 0) if (status_fd < 0)
return log_error_errno(-1, errno, "Failed to open monitor status fd"); return log_error_errno(-1, errno, "Failed to open monitor status fd");
handler->lsm_ops = lsm_init(); handler->lsm_ops = lsm_init_static();
TRACE("Initialized LSM"); TRACE("Initialized LSM");
/* Begin by setting the state to STARTING. */ /* Begin by setting the state to STARTING. */
...@@ -1069,8 +1069,7 @@ static int do_start(void *data) ...@@ -1069,8 +1069,7 @@ static int do_start(void *data)
/* Don't leak the pinfd to the container. */ /* Don't leak the pinfd to the container. */
close_prot_errno_disarm(handler->pinfd); close_prot_errno_disarm(handler->pinfd);
ret = lxc_sync_wait_parent(handler, LXC_SYNC_STARTUP); if (!lxc_sync_wait_parent(handler, START_SYNC_STARTUP))
if (ret < 0)
goto out_warn_father; goto out_warn_father;
/* Unshare CLONE_NEWNET after CLONE_NEWUSER. See /* Unshare CLONE_NEWNET after CLONE_NEWUSER. See
...@@ -1088,8 +1087,7 @@ static int do_start(void *data) ...@@ -1088,8 +1087,7 @@ static int do_start(void *data)
/* Tell the parent task it can begin to configure the container and wait /* Tell the parent task it can begin to configure the container and wait
* for it to finish. * for it to finish.
*/ */
ret = lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE); if (!lxc_sync_barrier_parent(handler, START_SYNC_CONFIGURE))
if (ret < 0)
goto out_error; goto out_error;
if (handler->ns_clone_flags & CLONE_NEWNET) { if (handler->ns_clone_flags & CLONE_NEWNET) {
...@@ -1168,8 +1166,7 @@ static int do_start(void *data) ...@@ -1168,8 +1166,7 @@ static int do_start(void *data)
} }
/* Ask father to setup cgroups and wait for him to finish. */ /* Ask father to setup cgroups and wait for him to finish. */
ret = lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP); if (!lxc_sync_barrier_parent(handler, START_SYNC_CGROUP))
if (ret < 0)
goto out_error; goto out_error;
/* Unshare cgroup namespace after we have setup our cgroups. If we do it /* Unshare cgroup namespace after we have setup our cgroups. If we do it
...@@ -1353,8 +1350,7 @@ static int do_start(void *data) ...@@ -1353,8 +1350,7 @@ static int do_start(void *data)
} }
} }
ret = lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP_LIMITS); if (!lxc_sync_barrier_parent(handler, START_SYNC_CGROUP_LIMITS))
if (ret < 0)
goto out_warn_father; goto out_warn_father;
/* Reset the environment variables the user requested in a clear /* Reset the environment variables the user requested in a clear
...@@ -1447,7 +1443,7 @@ out_warn_father: ...@@ -1447,7 +1443,7 @@ out_warn_father:
* We want the parent to know something went wrong, so we return a * We want the parent to know something went wrong, so we return a
* special error code. * special error code.
*/ */
lxc_sync_wake_parent(handler, LXC_SYNC_ERROR); lxc_sync_wake_parent(handler, SYNC_ERROR);
out_error: out_error:
return -1; return -1;
...@@ -1630,8 +1626,7 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1630,8 +1626,7 @@ static int lxc_spawn(struct lxc_handler *handler)
share_ns = true; share_ns = true;
} }
ret = lxc_sync_init(handler); if (!lxc_sync_init(handler))
if (ret < 0)
return -1; return -1;
ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
...@@ -1790,12 +1785,10 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1790,12 +1785,10 @@ static int lxc_spawn(struct lxc_handler *handler)
} }
} }
ret = lxc_sync_wake_child(handler, LXC_SYNC_STARTUP); if (!lxc_sync_wake_child(handler, START_SYNC_STARTUP))
if (ret < 0)
goto out_delete_net; goto out_delete_net;
ret = lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE); if (!lxc_sync_wait_child(handler, START_SYNC_CONFIGURE))
if (ret < 0)
goto out_delete_net; goto out_delete_net;
if (!cgroup_ops->setup_limits_legacy(cgroup_ops, handler->conf, false)) { if (!cgroup_ops->setup_limits_legacy(cgroup_ops, handler->conf, false)) {
...@@ -1862,10 +1855,9 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1862,10 +1855,9 @@ static int lxc_spawn(struct lxc_handler *handler)
} }
/* Tell the child to continue its initialization. We'll get /* Tell the child to continue its initialization. We'll get
* LXC_SYNC_CGROUP when it is ready for us to setup cgroups. * START_SYNC_CGROUP when it is ready for us to setup cgroups.
*/ */
ret = lxc_sync_barrier_child(handler, LXC_SYNC_POST_CONFIGURE); if (!lxc_sync_barrier_child(handler, START_SYNC_POST_CONFIGURE))
if (ret < 0)
goto out_delete_net; goto out_delete_net;
if (!lxc_list_empty(&conf->limits)) { if (!lxc_list_empty(&conf->limits)) {
...@@ -1876,8 +1868,7 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1876,8 +1868,7 @@ static int lxc_spawn(struct lxc_handler *handler)
} }
} }
ret = lxc_sync_barrier_child(handler, LXC_SYNC_CGROUP_UNSHARE); if (!lxc_sync_barrier_child(handler, START_SYNC_CGROUP_UNSHARE))
if (ret < 0)
goto out_delete_net; goto out_delete_net;
/* /*
...@@ -1937,12 +1928,11 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1937,12 +1928,11 @@ static int lxc_spawn(struct lxc_handler *handler)
/* Tell the child to complete its initialization and wait for it to exec /* Tell the child to complete its initialization and wait for it to exec
* or return an error. (The child will never return * or return an error. (The child will never return
* LXC_SYNC_READY_START+1. It will either close the sync pipe, causing * START_SYNC_READY_START+1. It will either close the sync pipe, causing
* lxc_sync_barrier_child to return success, or return a different * lxc_sync_barrier_child to return success, or return a different
* value, causing us to error out). * value, causing us to error out).
*/ */
ret = lxc_sync_barrier_child(handler, LXC_SYNC_READY_START); if (!lxc_sync_barrier_child(handler, START_SYNC_READY_START))
if (ret < 0)
goto out_delete_net; goto out_delete_net;
if (handler->ns_clone_flags & CLONE_NEWNET) { if (handler->ns_clone_flags & CLONE_NEWNET) {
......
...@@ -17,101 +17,129 @@ ...@@ -17,101 +17,129 @@
lxc_log_define(sync, lxc); lxc_log_define(sync, lxc);
static int __sync_wait(int fd, int sequence) bool sync_wait(int fd, int sequence)
{ {
int sync = -1; int sync = -1;
ssize_t ret; ssize_t ret;
ret = lxc_read_nointr(fd, &sync, sizeof(sync)); ret = lxc_read_nointr(fd, &sync, sizeof(sync));
if (ret < 0) if (ret < 0)
return log_error_errno(-1, errno, "Sync wait failure"); return log_error_errno(false, errno, "Sync wait failure");
if (!ret) if (!ret)
return 0; return true;
if ((size_t)ret != sizeof(sync)) if ((size_t)ret != sizeof(sync))
return log_error(-1, "Unexpected sync size: %zu expected %zu", (size_t)ret, sizeof(sync)); return log_error(false, "Unexpected sync size: %zu expected %zu", (size_t)ret, sizeof(sync));
if (sync == LXC_SYNC_ERROR) if (sync == SYNC_ERROR)
return log_error(-1, "An error occurred in another process (expected sequence number %d)", sequence); return log_error(false, "An error occurred in another process (expected sequence number %d)", sequence);
if (sync != sequence) if (sync != sequence)
return log_error(-1, "Invalid sequence number %d. Expected sequence number %d", sync, sequence); return log_error(false, "Invalid sequence number %d. Expected sequence number %d", sync, sequence);
return 0; return true;
} }
static int __sync_wake(int fd, int sequence) bool sync_wake(int fd, int sequence)
{ {
int sync = sequence; int sync = sequence;
if (lxc_write_nointr(fd, &sync, sizeof(sync)) < 0) if (lxc_write_nointr(fd, &sync, sizeof(sync)) < 0)
return log_error_errno(-1, errno, "Sync wake failure"); return log_error_errno(false, errno, "Sync wake failure");
return 0; return true;
} }
static int __sync_barrier(int fd, int sequence) static bool __sync_barrier(int fd, int sequence)
{ {
if (__sync_wake(fd, sequence)) if (!sync_wake(fd, sequence))
return -1; return false;
return __sync_wait(fd, sequence + 1); return sync_wait(fd, sequence + 1);
} }
int lxc_sync_barrier_parent(struct lxc_handler *handler, int sequence) static inline const char *start_sync_to_string(int state)
{
switch (state) {
case START_SYNC_STARTUP:
return "startup";
case START_SYNC_CONFIGURE:
return "configure";
case START_SYNC_POST_CONFIGURE:
return "post-configure";
case START_SYNC_CGROUP:
return "cgroup";
case START_SYNC_CGROUP_UNSHARE:
return "cgroup-unshare";
case START_SYNC_CGROUP_LIMITS:
return "cgroup-limits";
case START_SYNC_READY_START:
return "ready-start";
case START_SYNC_RESTART:
return "restart";
case START_SYNC_POST_RESTART:
return "post-restart";
case SYNC_ERROR:
return "error";
default:
return "invalid sync state";
}
}
bool lxc_sync_barrier_parent(struct lxc_handler *handler, int sequence)
{ {
TRACE("Child waking parent with sequence %s and waiting for sequence %s", TRACE("Child waking parent with sequence %s and waiting for sequence %s",
sync_to_string(sequence), sync_to_string(sequence + 1)); start_sync_to_string(sequence), start_sync_to_string(sequence + 1));
return __sync_barrier(handler->sync_sock[0], sequence); return __sync_barrier(handler->sync_sock[0], sequence);
} }
int lxc_sync_barrier_child(struct lxc_handler *handler, int sequence) bool lxc_sync_barrier_child(struct lxc_handler *handler, int sequence)
{ {
TRACE("Parent waking child with sequence %s and waiting with sequence %s", TRACE("Parent waking child with sequence %s and waiting with sequence %s",
sync_to_string(sequence), sync_to_string(sequence + 1)); start_sync_to_string(sequence), start_sync_to_string(sequence + 1));
return __sync_barrier(handler->sync_sock[1], sequence); return __sync_barrier(handler->sync_sock[1], sequence);
} }
int lxc_sync_wake_parent(struct lxc_handler *handler, int sequence) bool lxc_sync_wake_parent(struct lxc_handler *handler, int sequence)
{ {
TRACE("Child waking parent with sequence %s", sync_to_string(sequence)); TRACE("Child waking parent with sequence %s", start_sync_to_string(sequence));
return __sync_wake(handler->sync_sock[0], sequence); return sync_wake(handler->sync_sock[0], sequence);
} }
int lxc_sync_wait_parent(struct lxc_handler *handler, int sequence) bool lxc_sync_wait_parent(struct lxc_handler *handler, int sequence)
{ {
TRACE("Parent waiting for child with sequence %s", sync_to_string(sequence)); TRACE("Parent waiting for child with sequence %s", start_sync_to_string(sequence));
return __sync_wait(handler->sync_sock[0], sequence); return sync_wait(handler->sync_sock[0], sequence);
} }
int lxc_sync_wait_child(struct lxc_handler *handler, int sequence) bool lxc_sync_wait_child(struct lxc_handler *handler, int sequence)
{ {
TRACE("Child waiting for parent with sequence %s", sync_to_string(sequence)); TRACE("Child waiting for parent with sequence %s", start_sync_to_string(sequence));
return __sync_wait(handler->sync_sock[1], sequence); return sync_wait(handler->sync_sock[1], sequence);
} }
int lxc_sync_wake_child(struct lxc_handler *handler, int sequence) bool lxc_sync_wake_child(struct lxc_handler *handler, int sequence)
{ {
TRACE("Child waking parent with sequence %s", sync_to_string(sequence)); TRACE("Child waking parent with sequence %s", start_sync_to_string(sequence));
return __sync_wake(handler->sync_sock[1], sequence); return sync_wake(handler->sync_sock[1], sequence);
} }
int lxc_sync_init(struct lxc_handler *handler) bool lxc_sync_init(struct lxc_handler *handler)
{ {
int ret; int ret;
ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, handler->sync_sock); ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, handler->sync_sock);
if (ret) if (ret)
return log_error_errno(-1, errno, "failed to create synchronization socketpair"); return log_error_errno(false, errno, "failed to create synchronization socketpair");
/* Be sure we don't inherit this after the exec */ /* Be sure we don't inherit this after the exec */
ret = fcntl(handler->sync_sock[0], F_SETFD, FD_CLOEXEC); ret = fcntl(handler->sync_sock[0], F_SETFD, FD_CLOEXEC);
if (ret < 0) if (ret < 0)
return log_error_errno(-1, errno, "Failed to make socket close-on-exec"); return log_error_errno(false, errno, "Failed to make socket close-on-exec");
TRACE("Initialized synchronization infrastructure"); TRACE("Initialized synchronization infrastructure");
return 0; return true;
} }
void lxc_sync_fini_child(struct lxc_handler *handler) void lxc_sync_fini_child(struct lxc_handler *handler)
......
...@@ -3,60 +3,46 @@ ...@@ -3,60 +3,46 @@
#ifndef __LXC_SYNC_H #ifndef __LXC_SYNC_H
#define __LXC_SYNC_H #define __LXC_SYNC_H
#include <stdbool.h>
#include "compiler.h" #include "compiler.h"
struct lxc_handler; struct lxc_handler;
enum { enum /* generic */ {
LXC_SYNC_STARTUP = 0, SYNC_ERROR = -1 /* Used to report errors from another process */
LXC_SYNC_CONFIGURE = 1, };
LXC_SYNC_POST_CONFIGURE = 2,
LXC_SYNC_CGROUP = 3, enum /* start */ {
LXC_SYNC_CGROUP_UNSHARE = 4, START_SYNC_STARTUP = 0,
LXC_SYNC_CGROUP_LIMITS = 5, START_SYNC_CONFIGURE = 1,
LXC_SYNC_READY_START = 6, START_SYNC_POST_CONFIGURE = 2,
LXC_SYNC_RESTART = 7, START_SYNC_CGROUP = 3,
LXC_SYNC_POST_RESTART = 8, START_SYNC_CGROUP_UNSHARE = 4,
LXC_SYNC_ERROR = -1 /* Used to report errors from another process */ START_SYNC_CGROUP_LIMITS = 5,
START_SYNC_READY_START = 6,
START_SYNC_RESTART = 7,
START_SYNC_POST_RESTART = 8,
}; };
static inline const char *sync_to_string(int state) enum /* attach */ {
{ ATTACH_SYNC_CGROUP = 0,
switch (state) { };
case LXC_SYNC_STARTUP:
return "startup"; #define ATTACH_SYNC_PID(x) (x)
case LXC_SYNC_CONFIGURE: #define ATTACH_SYNC_LSM(x) (x)
return "configure";
case LXC_SYNC_POST_CONFIGURE: __hidden extern bool lxc_sync_init(struct lxc_handler *handler);
return "post-configure";
case LXC_SYNC_CGROUP:
return "cgroup";
case LXC_SYNC_CGROUP_UNSHARE:
return "cgroup-unshare";
case LXC_SYNC_CGROUP_LIMITS:
return "cgroup-limits";
case LXC_SYNC_READY_START:
return "ready-start";
case LXC_SYNC_RESTART:
return "restart";
case LXC_SYNC_POST_RESTART:
return "post-restart";
case LXC_SYNC_ERROR:
return "error";
default:
return "invalid sync state";
}
}
__hidden extern int lxc_sync_init(struct lxc_handler *handler);
__hidden extern void lxc_sync_fini(struct lxc_handler *); __hidden extern void lxc_sync_fini(struct lxc_handler *);
__hidden extern void lxc_sync_fini_parent(struct lxc_handler *); __hidden extern void lxc_sync_fini_parent(struct lxc_handler *);
__hidden extern void lxc_sync_fini_child(struct lxc_handler *); __hidden extern void lxc_sync_fini_child(struct lxc_handler *);
__hidden extern int lxc_sync_wake_child(struct lxc_handler *, int); __hidden extern bool lxc_sync_wake_child(struct lxc_handler *, int);
__hidden extern int lxc_sync_wait_child(struct lxc_handler *, int); __hidden extern bool lxc_sync_wait_child(struct lxc_handler *, int);
__hidden extern int lxc_sync_wake_parent(struct lxc_handler *, int); __hidden extern bool lxc_sync_wake_parent(struct lxc_handler *, int);
__hidden extern int lxc_sync_wait_parent(struct lxc_handler *, int); __hidden extern bool lxc_sync_wait_parent(struct lxc_handler *, int);
__hidden extern int lxc_sync_barrier_parent(struct lxc_handler *, int); __hidden extern bool lxc_sync_barrier_parent(struct lxc_handler *, int);
__hidden extern int lxc_sync_barrier_child(struct lxc_handler *, int); __hidden extern bool lxc_sync_barrier_child(struct lxc_handler *, int);
__hidden extern bool sync_wait(int fd, int sequence);
__hidden extern bool sync_wake(int fd, int sequence);
#endif /* __LXC_SYNC_H */ #endif /* __LXC_SYNC_H */
...@@ -400,7 +400,7 @@ int main(int argc, char *argv[]) ...@@ -400,7 +400,7 @@ int main(int argc, char *argv[])
(void)strlcpy(template, P_tmpdir"/attach_XXXXXX", sizeof(template)); (void)strlcpy(template, P_tmpdir"/attach_XXXXXX", sizeof(template));
lsm_ops = lsm_init(); lsm_ops = lsm_init_static();
i = lxc_make_tmpfile(template, false); i = lxc_make_tmpfile(template, false);
if (i < 0) { if (i < 0) {
......
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