[lxc-devel] [PATCH] lxc-attach: elevate specific privileges

Nikola Kotur kotnick at gmail.com
Wed Nov 20 15:07:37 UTC 2013


There are scenarios in which we want to execute process with specific
privileges elevated.

An example for this might be executing a process inside the container
securely, with capabilities dropped, but not in container's cgroup so
that we can have per process restrictions inside single container.

Similar to namespaces, privileges to be elevated can be OR'd:

    lxc-attach --elevated-privileges='CAP|CGROUP' ...

Backward compatibility with previous versions is retained. In case no
privileges are specified behaviour is the same as before: all of them
are elevated.

Signed-off-by: Nikola Kotur <kotnick at gmail.com>
---
 doc/lxc-attach.sgml.in | 13 ++++++++++++-
 src/lxc/confile.c      | 37 +++++++++++++++++++++++++++++++++++++
 src/lxc/confile.h      |  2 ++
 src/lxc/lxc_attach.c   | 28 ++++++++++++++++++----------
 4 files changed, 69 insertions(+), 11 deletions(-)

diff --git a/doc/lxc-attach.sgml.in b/doc/lxc-attach.sgml.in
index 8d75c7c..133e8fd 100644
--- a/doc/lxc-attach.sgml.in
+++ b/doc/lxc-attach.sgml.in
@@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

 -->

+
 <!DOCTYPE refentry PUBLIC @docdtd@ [

 <!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
@@ -107,7 +108,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

       <varlistentry>
 	<term>
-	  <option>-e, --elevated-privileges</option>
+	  <option>
+      -e, --elevated-privileges <replaceable>privileges</replaceable>
+    </option>
 	</term>
 	<listitem>
 	  <para>
@@ -117,6 +120,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 	    <emphasis>not</emphasis> be added to the container's cgroup(s)
 	    and it will not drop its capabilities before executing.
 	  </para>
+    <para>
+      You may specify privileges, in case you do not want to elevate all of
+      them, as a pipe-separated list, e.g.
+      <replaceable>CGROUP|LSM</replaceable>. Allowed values are
+      <replaceable>CGROUP</replaceable>, <replaceable>CAP</replaceable> and
+      <replaceable>LSM</replaceable> representing cgroup, capabilities and
+      restriction privileges respectively.
+    </para>
 	  <para>
 	    <emphasis>Warning:</emphasis> This may leak privileges into the
 	    container if the command starts subprocesses that remain active
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 0e0b7e8..bbb92dd 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -1568,6 +1568,43 @@ signed long lxc_config_parse_arch(const char *arch)
 	return -1;
 }

+int lxc_fill_elevated_privileges(char *flaglist, int *flags)
+{
+	char *token, *saveptr = NULL;
+	int i, aflag;
+	struct { const char *token; int flag; } all_privs[] = {
+		{ "CGROUP",		LXC_ATTACH_MOVE_TO_CGROUP 	},
+		{ "CAP",		LXC_ATTACH_DROP_CAPABILITIES 	},
+		{ "LSM",		LXC_ATTACH_LSM_EXEC 		},
+		{ NULL, 0 }
+	};
+
+	if (!flaglist) {
+		/* for the sake of backward compatibility, drop all privileges
+		   if none is specified */
+		for (i = 0; all_privs[i].token; i++) {
+	                *flags |= all_privs[i].flag;
+		}
+		return 0;
+	}
+
+	token = strtok_r(flaglist, "|", &saveptr);
+	while (token) {
+		aflag = -1;
+		for (i = 0; all_privs[i].token; i++) {
+			if (!strcmp(all_privs[i].token, token))
+				aflag = all_privs[i].flag;
+		}
+		if (aflag < 0)
+			return -1;
+
+		*flags |= aflag;
+
+		token = strtok_r(NULL, "|", &saveptr);
+	}
+	return 0;
+}
+
 static int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
 {
 	if (!retv)
diff --git a/src/lxc/confile.h b/src/lxc/confile.h
index 9d12071..eb7a8c2 100644
--- a/src/lxc/confile.h
+++ b/src/lxc/confile.h
@@ -22,6 +22,7 @@
  */

 #include <stdio.h>
+#include "attach_options.h"

 #ifndef _confile_h
 #define _confile_h
@@ -47,6 +48,7 @@ extern int lxc_config_define_load(struct lxc_list *defines,

 /* needed for lxc-attach */
 extern signed long lxc_config_parse_arch(const char *arch);
+extern int lxc_fill_elevated_privileges(char *flaglist, int *flags);

 extern int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv, int inlen);
 extern int lxc_clear_config_item(struct lxc_conf *c, const char *key);
diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
index b49771b..6744c05 100644
--- a/src/lxc/lxc_attach.c
+++ b/src/lxc/lxc_attach.c
@@ -38,7 +38,7 @@
 lxc_log_define(lxc_attach_ui, lxc);

 static const struct option my_longopts[] = {
-	{"elevated-privileges", no_argument, 0, 'e'},
+	{"elevated-privileges", optional_argument, 0, 'e'},
 	{"arch", required_argument, 0, 'a'},
 	{"namespaces", required_argument, 0, 's'},
 	{"remount-sys-proc", no_argument, 0, 'R'},
@@ -87,7 +87,11 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 	int ret;

 	switch (c) {
-	case 'e': elevated_privileges = 1; break;
+	case 'e':
+		ret = lxc_fill_elevated_privileges(arg, &elevated_privileges);
+		if (ret)
+			return -1;
+		break;
 	case 'R': remount_sys_proc = 1; break;
 	case 'a':
 		new_personality = lxc_config_parse_arch(arg);
@@ -102,7 +106,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 		if (ret)
 			return -1;
 		/* -s implies -e */
-		elevated_privileges = 1;
+		lxc_fill_elevated_privileges(NULL, &elevated_privileges);
 		break;
         case 500: /* clear-env */
                 env_policy = LXC_ATTACH_CLEAR_ENV;
@@ -138,9 +142,12 @@ Execute the specified COMMAND - enter the container NAME\n\
 \n\
 Options :\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\
+  -e, --elevated-privileges=PRIVILEGES\n\
+                    Use elevated privileges instead of those of the\n\
+                    container. If you don't specify privileges to be\n\
+                    elevated as OR'd list: CAP, CGROUP and LSM (capabilities,\n\
+                    cgroup and restrictions, respectively) then all of them\n\
+                    will be elevated.\n\
                     WARNING: This may leak privileges into the container.\n\
                     Use with care.\n\
   -a, --arch=ARCH   Use ARCH for program instead of container's own\n\
@@ -148,9 +155,10 @@ Options :\n\
   -s, --namespaces=FLAGS\n\
                     Don't attach to all the namespaces of the container\n\
                     but just to the following OR'd list of flags:\n\
-                    MOUNT, PID, UTSNAME, IPC, USER or NETWORK\n\
-                    WARNING: Using -s implies -e, it may therefore\n\
-                    leak privileges into the container. Use with care.\n\
+                    MOUNT, PID, UTSNAME, IPC, USER or NETWORK.\n\
+                    WARNING: Using -s implies -e with all privileges\n\
+                    elevated, it may therefore leak privileges into the\n\
+                    container. Use with care.\n\
   -R, --remount-sys-proc\n\
                     Remount /sys and /proc if not attaching to the\n\
                     mount namespace when using -s in order to properly\n\
@@ -199,7 +207,7 @@ int main(int argc, char *argv[])
 	if (remount_sys_proc)
 		attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
 	if (elevated_privileges)
-		attach_options.attach_flags &= ~(LXC_ATTACH_MOVE_TO_CGROUP | LXC_ATTACH_DROP_CAPABILITIES | LXC_ATTACH_LSM_EXEC);
+		attach_options.attach_flags &= ~(elevated_privileges);
 	attach_options.namespaces = namespace_flags;
 	attach_options.personality = new_personality;
 	attach_options.env_policy = env_policy;
--
1.8.4.2





More information about the lxc-devel mailing list