[lxc-devel] [lxc/master] utils: allow lxc-attach to set uid / gid

brauner on Github lxc-bot at linuxcontainers.org
Sun Sep 9 11:28:32 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180909/a8bceb1a/attachment.bin>
-------------- next part --------------
From 55dc77113a3548dae0faa22a12c5eefb368a2254 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 9 Sep 2018 12:46:00 +0200
Subject: [PATCH 1/4] utils: improve get_ns_uid() and add get_ns_gid()

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/cgroups/cgfsng.c |  2 ++
 src/lxc/macro.h          |  3 +++
 src/lxc/utils.c          | 29 ++++++++++++++++++++++++++++-
 src/lxc/utils.h          |  4 ++++
 4 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 1fe561498..c37456b92 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -1388,6 +1388,8 @@ static int chown_cgroup_wrapper(void *data)
 	}
 
 	destuid = get_ns_uid(arg->origuid);
+	if (destuid == LXC_INVALID_UID)
+		destuid = 0;
 
 	for (i = 0; arg->hierarchies[i]; i++) {
 		char *fullpath;
diff --git a/src/lxc/macro.h b/src/lxc/macro.h
index d44e2f9b1..c0a50371d 100644
--- a/src/lxc/macro.h
+++ b/src/lxc/macro.h
@@ -340,4 +340,7 @@ extern int __build_bug_on_failed;
 #define PTR_TO_INTMAX(p) ((intmax_t)((intptr_t)(p)))
 #define INTMAX_TO_PTR(u) ((void *)((intptr_t)(u)))
 
+#define LXC_INVALID_UID ((uid_t)-1)
+#define LXC_INVALID_GID ((gid_t)-1)
+
 #endif /* __LXC_MACRO_H */
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 9795b51b6..b85383a42 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -544,7 +544,34 @@ uid_t get_ns_uid(uid_t orig)
 		}
 	}
 
-	nsid = 0;
+	nsid = LXC_INVALID_UID;
+
+found:
+	fclose(f);
+	free(line);
+	return nsid;
+}
+
+gid_t get_ns_gid(gid_t orig)
+{
+	char *line = NULL;
+	size_t sz = 0;
+	gid_t nsid, hostid, range;
+	FILE *f = fopen("/proc/self/gid_map", "r");
+	if (!f)
+		return 0;
+
+	while (getline(&line, &sz, f) != -1) {
+		if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
+			continue;
+
+		if (hostid <= orig && hostid + range > orig) {
+			nsid += orig - hostid;
+			goto found;
+		}
+	}
+
+	nsid = LXC_INVALID_GID;
 
 found:
 	fclose(f);
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index f2d802991..51cfe4c85 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -328,6 +328,10 @@ inline static bool am_host_unpriv(void)
  * parse /proc/self/uid_map to find what @orig maps to
  */
 extern uid_t get_ns_uid(uid_t orig);
+/*
+ * parse /proc/self/gid_map to find what @orig maps to
+ */
+extern gid_t get_ns_gid(gid_t orig);
 
 extern bool dir_exists(const char *path);
 

From f3d8a9144b507380132474896d13c5f27ec8e2a3 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 9 Sep 2018 13:11:21 +0200
Subject: [PATCH 2/4] utils: improve lxc_switch_uid_gid()

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/utils.c | 26 +++++++++++++++++---------
 src/lxc/utils.h |  4 +++-
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index b85383a42..ff02bba96 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1353,19 +1353,27 @@ int lxc_preserve_ns(const int pid, const char *ns)
 
 int lxc_switch_uid_gid(uid_t uid, gid_t gid)
 {
-	if (setgid(gid) < 0) {
-		SYSERROR("Failed to switch to gid %d.", gid);
-		return -errno;
+	int ret = 0;
+
+	if (gid != LXC_INVALID_GID) {
+		ret = setgid(gid);
+		if (ret < 0) {
+			SYSERROR("Failed to switch to gid %d", gid);
+			return -1;
+		}
+		NOTICE("Switched to gid %d", gid);
 	}
-	NOTICE("Switched to gid %d.", gid);
 
-	if (setuid(uid) < 0) {
-		SYSERROR("Failed to switch to uid %d.", uid);
-		return -errno;
+	if (uid != LXC_INVALID_UID) {
+		ret = setuid(uid);
+		if (ret < 0) {
+			SYSERROR("Failed to switch to uid %d", uid);
+			return -1;
+		}
+		NOTICE("Switched to uid %d", uid);
 	}
-	NOTICE("Switched to uid %d.", uid);
 
-	return 0;
+	return ret;
 }
 
 /* Simple covenience function which enables uniform logging. */
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 51cfe4c85..947b15e16 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -358,7 +358,9 @@ extern int lxc_preserve_ns(const int pid, const char *ns);
 /* Check whether a signal is blocked by a process. */
 extern bool task_blocks_signal(pid_t pid, int signal);
 
-/* Switch to a new uid and gid. */
+/* Switch to a new uid and gid.
+ * If LXC_INVALID_{G,U}ID is passed then the set{g,u}id() will not be called.
+ */
 extern int lxc_switch_uid_gid(uid_t uid, gid_t gid);
 extern int lxc_setgroups(int size, gid_t list[]);
 

From ce47a6de0ac7901796a918cb9fda209f462b2c60 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 9 Sep 2018 13:20:14 +0200
Subject: [PATCH 3/4] attach: handle id switching smarter

For setup, switch to the most privileged ids we can find. That is either
nsuid 0 if a mapping has been established if not switch to the ids the
init running in the container was started with.
After setup, switch to the actual requested ids.

Closes #2591.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/attach.c | 51 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 87f14398f..a2c11242d 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -749,6 +749,8 @@ static int attach_child_main(struct attach_clone_payload *payload)
 	int fd, lsm_fd, ret;
 	uid_t new_uid;
 	gid_t new_gid;
+	uid_t ns_root_uid = 0;
+	gid_t ns_root_gid = 0;
 	lxc_attach_options_t* options = payload->options;
 	struct lxc_proc_context_info* init_ctx = payload->init_ctx;
 	bool needs_lsm = (options->namespaces & CLONE_NEWNS) &&
@@ -836,25 +838,29 @@ static int attach_child_main(struct attach_clone_payload *payload)
 			goto on_error;
 	}
 
-	/* Set {u,g}id. */
-	new_uid = 0;
-	new_gid = 0;
+	if (options->namespaces & CLONE_NEWUSER) {
+		/* Check whether nsuid 0 has a mapping. */
+		ns_root_uid = get_ns_uid(0);
 
-	/* Ignore errors, we will fall back to root in that case (/proc was not
-	 * mounted etc.).
-	 */
-	if (options->namespaces & CLONE_NEWUSER)
-		lxc_attach_get_init_uidgid(&new_uid, &new_gid);
+		/* Check whether nsgid 0 has a mapping. */
+		ns_root_gid = get_ns_gid(0);
 
-	if (options->uid != (uid_t)-1)
-		new_uid = options->uid;
+		/* If there's no mapping for nsuid 0 try to retrieve the nsuid
+		 * init was started with.
+		 */
+		if (ns_root_uid == LXC_INVALID_UID)
+			lxc_attach_get_init_uidgid(&ns_root_uid, &ns_root_gid);
 
-	if (options->gid != (gid_t)-1)
-		new_gid = options->gid;
+		if (ns_root_uid == LXC_INVALID_UID) {
+			errno = EINVAL;
+			SYSERROR("Failed to find valid namespace uid mapping");
+			goto on_error;
+		}
 
-	/* Try to set the {u,g}id combination. */
-	if (new_uid != 0 || new_gid != 0 || options->namespaces & CLONE_NEWUSER) {
-		ret = lxc_switch_uid_gid(new_uid, new_gid);
+		if (ns_root_gid == LXC_INVALID_GID)
+			ns_root_gid = LXC_INVALID_GID;
+
+		ret = lxc_switch_uid_gid(ns_root_uid, ns_root_gid);
 		if (ret < 0)
 			goto on_error;
 	}
@@ -863,6 +869,17 @@ static int attach_child_main(struct attach_clone_payload *payload)
 	if (ret < 0 && errno != EPERM)
 		goto on_error;
 
+	/* Set {u,g}id. */
+	if (options->uid != LXC_INVALID_UID)
+		new_uid = options->uid;
+	else
+		new_uid = ns_root_uid;
+
+	if (options->gid != LXC_INVALID_GID)
+		new_gid = options->gid;
+	else
+		new_gid = ns_root_gid;
+
 	if ((init_ctx->container && init_ctx->container->lxc_conf &&
 	     init_ctx->container->lxc_conf->no_new_privs) ||
 	    (options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) {
@@ -952,6 +969,10 @@ static int attach_child_main(struct attach_clone_payload *payload)
 		TRACE("Prepared terminal file descriptor %d", payload->terminal_slave_fd);
 	}
 
+	ret = lxc_switch_uid_gid(new_uid, new_gid);
+	if (ret < 0)
+		goto on_error;
+
 	/* We're done, so we can now do whatever the user intended us to do. */
 	_exit(payload->exec_function(payload->exec_payload));
 

From 29d2818dcfc026e462c71fcdbd613a40f9aebbe2 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 9 Sep 2018 13:22:58 +0200
Subject: [PATCH 4/4] tools/lxc-attach: add -u and -g arguments

This lets users specify uids and gids to switch to.

Closes #2591.

Signed-off-by: Disassembler disassembler at dasm.cz
[christian.brauner at ubuntu.com: adapt commit message]
---
 doc/lxc-attach.sgml.in     | 26 ++++++++++++++++++++++++++
 doc/lxc-execute.sgml.in    | 26 ++++++++++++++++++++++++++
 src/lxc/tools/lxc_attach.c | 20 ++++++++++++++++++++
 3 files changed, 72 insertions(+)

diff --git a/doc/lxc-attach.sgml.in b/doc/lxc-attach.sgml.in
index 713a30e7f..14fa77d79 100644
--- a/doc/lxc-attach.sgml.in
+++ b/doc/lxc-attach.sgml.in
@@ -60,6 +60,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <arg choice="opt">--clear-env</arg>
       <arg choice="opt">-v, --set-var <replaceable>variable</replaceable></arg>
       <arg choice="opt">--keep-var <replaceable>variable</replaceable></arg>
+      <arg choice="opt">-u, --uid <replaceable>uid</replaceable></arg>
+      <arg choice="opt">-g, --gid <replaceable>gid</replaceable></arg>
       <arg choice="opt">-- <replaceable>command</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -282,6 +284,30 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 	</listitem>
       </varlistentry>
 
+      <varlistentry>
+	<term>
+	  <option>--u, --uid <replaceable>uid</replaceable></option>
+	</term>
+	<listitem>
+	  <para>
+	    Executes the <replaceable>command</replaceable> with user ID
+	   <replaceable>uid</replaceable> inside the container.
+	  </para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>
+	  <option>--g, --gid <replaceable>gid</replaceable></option>
+	</term>
+	<listitem>
+	  <para>
+	    Executes the <replaceable>command</replaceable> with group ID
+	   <replaceable>gid</replaceable> inside the container.
+	  </para>
+	</listitem>
+      </varlistentry>
+
      </variablelist>
 
   </refsect1>
diff --git a/doc/lxc-execute.sgml.in b/doc/lxc-execute.sgml.in
index 20814348d..8b249b329 100644
--- a/doc/lxc-execute.sgml.in
+++ b/doc/lxc-execute.sgml.in
@@ -53,6 +53,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <arg choice="opt">-d</arg>
       <arg choice="opt">-f <replaceable>config_file</replaceable></arg>
       <arg choice="opt">-s KEY=VAL</arg>
+      <arg choice="opt">-u, --uid <replaceable>uid</replaceable></arg>
+      <arg choice="opt">-g, --gid <replaceable>gid</replaceable></arg>
       <arg choice="opt">-- <replaceable>command</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -139,6 +141,30 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 	</listitem>
       </varlistentry>
 
+      <varlistentry>
+	<term>
+	  <option>--u, --uid <replaceable>uid</replaceable></option>
+	</term>
+	<listitem>
+	  <para>
+	    Executes the <replaceable>command</replaceable> with user ID
+	   <replaceable>uid</replaceable> inside the container.
+	  </para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>
+	  <option>--g, --gid <replaceable>gid</replaceable></option>
+	</term>
+	<listitem>
+	  <para>
+	    Executes the <replaceable>command</replaceable> with group ID
+	   <replaceable>gid</replaceable> inside the container.
+	  </para>
+	</listitem>
+      </varlistentry>
+
       <varlistentry>
 	<term><option>--</option></term>
 	<listitem>
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index e98f0a056..ae3b24cb0 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -72,6 +72,8 @@ static const struct option my_longopts[] = {
 	{"set-var", required_argument, 0, 'v'},
 	{"pty-log", required_argument, 0, 'L'},
 	{"rcfile", required_argument, 0, 'f'},
+	{"uid", required_argument, 0, 'u'},
+	{"gid", required_argument, 0, 'g'},
 	LXC_COMMON_OPTIONS
 };
 
@@ -122,6 +124,8 @@ Options :\n\
                     multiple times.\n\
   -f, --rcfile=FILE\n\
                     Load configuration file FILE\n\
+  -u, --uid=UID     Execute COMMAND with UID inside the container\n\
+  -g, --gid=GID     Execute COMMAND with GID inside the container\n\
 ",
 	.options      = my_longopts,
 	.parser       = my_parser,
@@ -187,6 +191,14 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
 	case 'f':
 		args->rcfile = arg;
 		break;
+	case 'u':
+		if (lxc_safe_uint(arg, &args->uid) < 0)
+			return -1;
+		break;
+	case 'g':
+		if (lxc_safe_uint(arg, &args->gid) < 0)
+			return -1;
+		break;
 	}
 
 	return 0;
@@ -333,6 +345,14 @@ int main(int argc, char *argv[])
 			goto out;
 	}
 
+	if (my_args.uid) {
+		attach_options.uid = my_args.uid;
+	}
+
+	if (my_args.gid) {
+		attach_options.gid = my_args.gid;
+	}
+
 	if (command.program)
 		ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
 	else


More information about the lxc-devel mailing list