diff options
-rw-r--r-- | src/lxc/lxc_attach.c | 115 |
1 files changed, 102 insertions, 13 deletions
diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c index c8643d1..3571b09 100644 --- a/src/lxc/lxc_attach.c +++ b/src/lxc/lxc_attach.c @@ -29,19 +29,45 @@ #include <sys/param.h> #include <sys/types.h> #include <sys/wait.h> +#include <sys/personality.h> #include "attach.h" #include "commands.h" #include "arguments.h" #include "caps.h" +#include "attach.h" +#include "confile.h" +#include "start.h" +#include "sync.h" #include "log.h" lxc_log_define(lxc_attach_ui, lxc); static const struct option my_longopts[] = { + {"elevated-privileges", no_argument, 0, 'e'}, + {"arch", required_argument, 0, 'a'}, LXC_COMMON_OPTIONS }; +static int elevated_privileges = 0; +static signed long new_personality = -1; + +static int my_parser(struct lxc_arguments* args, int c, char* arg) +{ + switch (c) { + case 'e': elevated_privileges = 1; break; + case 'a': + new_personality = lxc_config_parse_arch(arg); + if (new_personality < 0) { + lxc_error(args, "invalid architecture specified: %s", arg); + return -1; + } + break; + } + + return 0; +} + static struct lxc_arguments my_args = { .progname = "lxc-attach", .help = "\ @@ -50,17 +76,26 @@ static struct lxc_arguments my_args = { Execute the specified command - enter the container NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n", + -n, --name=NAME NAME for name of the container\n\ + -e, --elevated-privileges\n\ + Use elevated privileges (capabilities, cgroup\n\ + restrictions) instead of those of the container.\n\ + WARNING: This may leak privleges into the container.\n\ + Use with care.\n\ + -a, --arch=ARCH Use ARCH for program instead of container's own\n\ + architecture.\n", .options = my_longopts, - .parser = NULL, + .parser = my_parser, .checker = NULL, }; int main(int argc, char *argv[], char *envp[]) { int ret; - pid_t pid; + pid_t pid, init_pid; struct passwd *passwd; + struct lxc_proc_context_info *init_ctx; + struct lxc_handler *handler; uid_t uid; char *curdir; @@ -77,24 +112,25 @@ int main(int argc, char *argv[], char *envp[]) if (ret) return ret; - pid = get_init_pid(my_args.name); - if (pid < 0) { + init_pid = get_init_pid(my_args.name); + if (init_pid < 0) { ERROR("failed to get the init pid"); return -1; } - curdir = get_current_dir_name(); - - ret = lxc_attach_to_ns(pid); - if (ret < 0) { - ERROR("failed to enter the namespace"); + init_ctx = lxc_proc_get_context_info(init_pid); + if (!init_ctx) { + ERROR("failed to get context of the init process, pid = %d", init_pid); return -1; } - if (curdir && chdir(curdir)) - WARN("could not change directory to '%s'", curdir); + /* hack: we need sync.h infrastructure - and that needs a handler */ + handler = calloc(1, sizeof(*handler)); - free(curdir); + if (lxc_sync_init(handler)) { + ERROR("failed to initialize synchronization socket"); + return -1; + } pid = fork(); @@ -106,6 +142,23 @@ int main(int argc, char *argv[], char *envp[]) if (pid) { int status; + lxc_sync_fini_child(handler); + + /* wait until the child has done configuring itself before + * we put it in a cgroup that potentially limits these + * possibilities */ + if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE)) + return -1; + + if (!elevated_privileges && lxc_attach_proc_to_cgroups(pid, init_ctx)) + return -1; + + /* tell the child we are done initializing */ + if (lxc_sync_wake_child(handler, LXC_SYNC_POST_CONFIGURE)) + return -1; + + lxc_sync_fini(handler); + again: if (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) @@ -121,6 +174,42 @@ int main(int argc, char *argv[], char *envp[]) } if (!pid) { + lxc_sync_fini_parent(handler); + + curdir = get_current_dir_name(); + + ret = lxc_attach_to_ns(init_pid); + if (ret < 0) { + ERROR("failed to enter the namespace"); + return -1; + } + + if (curdir && chdir(curdir)) + WARN("could not change directory to '%s'", curdir); + + free(curdir); + + if (new_personality < 0) + new_personality = init_ctx->personality; + + if (personality(new_personality) == -1) { + ERROR("could not ensure correct architecture: %s", + strerror(errno)); + return -1; + } + + if (!elevated_privileges && lxc_attach_drop_privs(init_ctx)) { + ERROR("could not drop privileges"); + return -1; + } + + /* tell parent we are done setting up the container and wait + * until we have been put in the container's cgroup, if + * applicable */ + if (lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE)) + return -1; + + lxc_sync_fini(handler); if (my_args.argc) { execve(my_args.argv[0], my_args.argv, envp); |