[lxc-devel] [PATCH 8/9] lxc-attach: Drop privileges when attaching to container unless requested otherwise

Christian Seiler christian at iwakd.de
Thu Feb 9 14:33:14 UTC 2012


lxc-attach will now put the process that is attached to the container into
the correct cgroups corresponding to the container, set the correct
personality and drop the privileges.

The information is extracted from entries in /proc of the init process of
the container. Note that this relies on the (reasonable) assumption that the
init process does not in fact drop additional capabilities from its bounding
set.

Additionally, 2 command line options are added to lxc-attach: One to prevent
the capabilities from being dropped and the process from being put into the
cgroup (-e, --elevated-privileges) and a second one to explicitly state the
architecture which the process will see, (-a, --arch) which defaults to the
container's current architecture.
---
 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);
-- 
1.7.2.5





More information about the lxc-devel mailing list