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
AC_MSG_ERROR([Sorry, your compiler is too old - please upgrade it])
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
LT_INIT
AC_SUBST([LIBTOOL_DEPS])
......@@ -731,10 +743,6 @@ AC_CHECK_TYPES([struct rtnl_link_stats64], [], [], [[#include <linux/if_link.h>]
AX_PTHREAD
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.
LXC_CHECK_TLS
......
......@@ -11,16 +11,7 @@
#include "namespace.h"
struct lxc_conf;
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;
};
struct lxc_container;
__hidden extern int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
void *exec_payload, lxc_attach_options_t *options,
......
......@@ -124,7 +124,7 @@ typedef struct lxc_attach_options_t {
{ \
/* .attach_flags = */ LXC_ATTACH_DEFAULT, \
/* .namespaces = */ -1, \
/* .personality = */ -1, \
/* .personality = */ 0xffffffff, \
/* .initial_cwd = */ NULL, \
/* .uid = */ (uid_t)-1, \
/* .gid = */ (gid_t)-1, \
......
......@@ -3031,7 +3031,7 @@ signed long lxc_config_parse_arch(const char *arch)
return pername[i].per;
#endif
return -1;
return LXC_ARCH_UNCHANGED;
}
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
__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 int lxc_fill_elevated_privileges(char *flaglist, int *flags);
......
......@@ -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_nop_ops_init(void);
struct lsm_ops *lsm_init(void)
struct lsm_ops *lsm_init_static(void)
{
struct lsm_ops *ops = NULL;
......
......@@ -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);
};
__hidden extern struct lsm_ops *lsm_init(void);
__hidden extern struct lsm_ops *lsm_init_static(void);
#endif /* __LXC_LSM_H */
......@@ -293,6 +293,19 @@
* +
* \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 \
(6 + INTTYPE_TO_STRLEN(pid_t) + 4 + INTTYPE_TO_STRLEN(int) + 1)
......
......@@ -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)
......
......@@ -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;
......
......@@ -728,7 +728,7 @@ int lxc_init(const char *name, struct lxc_handler *handler)
if (status_fd < 0)
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");
/* Begin by setting the state to STARTING. */
......@@ -1069,8 +1069,7 @@ static int do_start(void *data)
/* Don't leak the pinfd to the container. */
close_prot_errno_disarm(handler->pinfd);
ret = lxc_sync_wait_parent(handler, LXC_SYNC_STARTUP);
if (ret < 0)
if (!lxc_sync_wait_parent(handler, START_SYNC_STARTUP))
goto out_warn_father;
/* Unshare CLONE_NEWNET after CLONE_NEWUSER. See
......@@ -1088,8 +1087,7 @@ static int do_start(void *data)
/* Tell the parent task it can begin to configure the container and wait
* for it to finish.
*/
ret = lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE);
if (ret < 0)
if (!lxc_sync_barrier_parent(handler, START_SYNC_CONFIGURE))
goto out_error;
if (handler->ns_clone_flags & CLONE_NEWNET) {
......@@ -1168,8 +1166,7 @@ static int do_start(void *data)
}
/* Ask father to setup cgroups and wait for him to finish. */
ret = lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP);
if (ret < 0)
if (!lxc_sync_barrier_parent(handler, START_SYNC_CGROUP))
goto out_error;
/* Unshare cgroup namespace after we have setup our cgroups. If we do it
......@@ -1353,8 +1350,7 @@ static int do_start(void *data)
}
}
ret = lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP_LIMITS);
if (ret < 0)
if (!lxc_sync_barrier_parent(handler, START_SYNC_CGROUP_LIMITS))
goto out_warn_father;
/* Reset the environment variables the user requested in a clear
......@@ -1447,7 +1443,7 @@ out_warn_father:
* We want the parent to know something went wrong, so we return a
* special error code.
*/
lxc_sync_wake_parent(handler, LXC_SYNC_ERROR);
lxc_sync_wake_parent(handler, SYNC_ERROR);
out_error:
return -1;
......@@ -1630,8 +1626,7 @@ static int lxc_spawn(struct lxc_handler *handler)
share_ns = true;
}
ret = lxc_sync_init(handler);
if (ret < 0)
if (!lxc_sync_init(handler))
return -1;
ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
......@@ -1790,12 +1785,10 @@ static int lxc_spawn(struct lxc_handler *handler)
}
}
ret = lxc_sync_wake_child(handler, LXC_SYNC_STARTUP);
if (ret < 0)
if (!lxc_sync_wake_child(handler, START_SYNC_STARTUP))
goto out_delete_net;
ret = lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE);
if (ret < 0)
if (!lxc_sync_wait_child(handler, START_SYNC_CONFIGURE))
goto out_delete_net;
if (!cgroup_ops->setup_limits_legacy(cgroup_ops, handler->conf, false)) {
......@@ -1862,10 +1855,9 @@ static int lxc_spawn(struct lxc_handler *handler)
}
/* 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 (ret < 0)
if (!lxc_sync_barrier_child(handler, START_SYNC_POST_CONFIGURE))
goto out_delete_net;
if (!lxc_list_empty(&conf->limits)) {
......@@ -1876,8 +1868,7 @@ static int lxc_spawn(struct lxc_handler *handler)
}
}
ret = lxc_sync_barrier_child(handler, LXC_SYNC_CGROUP_UNSHARE);
if (ret < 0)
if (!lxc_sync_barrier_child(handler, START_SYNC_CGROUP_UNSHARE))
goto out_delete_net;
/*
......@@ -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
* 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
* value, causing us to error out).
*/
ret = lxc_sync_barrier_child(handler, LXC_SYNC_READY_START);
if (ret < 0)
if (!lxc_sync_barrier_child(handler, START_SYNC_READY_START))
goto out_delete_net;
if (handler->ns_clone_flags & CLONE_NEWNET) {
......
......@@ -17,101 +17,129 @@
lxc_log_define(sync, lxc);
static int __sync_wait(int fd, int sequence)
bool sync_wait(int fd, int sequence)
{
int sync = -1;
ssize_t ret;
ret = lxc_read_nointr(fd, &sync, sizeof(sync));
if (ret < 0)
return log_error_errno(-1, errno, "Sync wait failure");
return log_error_errno(false, errno, "Sync wait failure");
if (!ret)
return 0;
return true;
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)
return log_error(-1, "An error occurred in another process (expected sequence number %d)", sequence);
if (sync == SYNC_ERROR)
return log_error(false, "An error occurred in another process (expected sequence number %d)", 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;
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))
return -1;
if (!sync_wake(fd, sequence))
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",
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);
}
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",
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);
}
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));
return __sync_wake(handler->sync_sock[0], sequence);
TRACE("Child waking parent with sequence %s", start_sync_to_string(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));
return __sync_wait(handler->sync_sock[0], sequence);
TRACE("Parent waiting for child with sequence %s", start_sync_to_string(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));
return __sync_wait(handler->sync_sock[1], sequence);
TRACE("Child waiting for parent with sequence %s", start_sync_to_string(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));
return __sync_wake(handler->sync_sock[1], sequence);
TRACE("Child waking parent with sequence %s", start_sync_to_string(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;
ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, handler->sync_sock);
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 */
ret = fcntl(handler->sync_sock[0], F_SETFD, FD_CLOEXEC);
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");
return 0;
return true;
}
void lxc_sync_fini_child(struct lxc_handler *handler)
......
......@@ -3,60 +3,46 @@
#ifndef __LXC_SYNC_H
#define __LXC_SYNC_H
#include <stdbool.h>
#include "compiler.h"
struct lxc_handler;
enum {
LXC_SYNC_STARTUP = 0,
LXC_SYNC_CONFIGURE = 1,
LXC_SYNC_POST_CONFIGURE = 2,
LXC_SYNC_CGROUP = 3,
LXC_SYNC_CGROUP_UNSHARE = 4,
LXC_SYNC_CGROUP_LIMITS = 5,
LXC_SYNC_READY_START = 6,
LXC_SYNC_RESTART = 7,
LXC_SYNC_POST_RESTART = 8,
LXC_SYNC_ERROR = -1 /* Used to report errors from another process */
enum /* generic */ {
SYNC_ERROR = -1 /* Used to report errors from another process */
};
enum /* start */ {
START_SYNC_STARTUP = 0,
START_SYNC_CONFIGURE = 1,
START_SYNC_POST_CONFIGURE = 2,
START_SYNC_CGROUP = 3,
START_SYNC_CGROUP_UNSHARE = 4,
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)
{
switch (state) {
case LXC_SYNC_STARTUP:
return "startup";
case LXC_SYNC_CONFIGURE:
return "configure";
case LXC_SYNC_POST_CONFIGURE:
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);
enum /* attach */ {
ATTACH_SYNC_CGROUP = 0,
};
#define ATTACH_SYNC_PID(x) (x)
#define ATTACH_SYNC_LSM(x) (x)
__hidden extern bool lxc_sync_init(struct lxc_handler *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_child(struct lxc_handler *);
__hidden extern int lxc_sync_wake_child(struct lxc_handler *, int);
__hidden extern int lxc_sync_wait_child(struct lxc_handler *, int);
__hidden extern int lxc_sync_wake_parent(struct lxc_handler *, int);
__hidden extern int lxc_sync_wait_parent(struct lxc_handler *, int);
__hidden extern int lxc_sync_barrier_parent(struct lxc_handler *, int);
__hidden extern int lxc_sync_barrier_child(struct lxc_handler *, int);
__hidden extern bool lxc_sync_wake_child(struct lxc_handler *, int);
__hidden extern bool lxc_sync_wait_child(struct lxc_handler *, int);
__hidden extern bool lxc_sync_wake_parent(struct lxc_handler *, int);
__hidden extern bool lxc_sync_wait_parent(struct lxc_handler *, int);
__hidden extern bool lxc_sync_barrier_parent(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 */
......@@ -400,7 +400,7 @@ int main(int argc, char *argv[])
(void)strlcpy(template, P_tmpdir"/attach_XXXXXX", sizeof(template));
lsm_ops = lsm_init();
lsm_ops = lsm_init_static();
i = lxc_make_tmpfile(template, false);
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