Allow entering a user namespace with a default gid mapping.

https://android-review.googlesource.com/253910 added functionality to
enter a user namespace with a default uid mapping. This CL completes
that with a default gid mapping.

This is useful when using user namespaces to gain root inside a
namespace. Note that setting the gid map as a non-root user requires
disabling the setgroups(2) system call by writing "deny" to
/proc/[pid]/setgroups.

Eventually we might expose disabling setgroups(2) as a command-line
option, but there's no need to do it now.

Bug: 30691131
Test: Using minijail0:
$ ./minijail0 -m /usr/bin/id
uid=0(root) gid=65534(nogroup) groups=0(root),65534(nogroup)
$ ./minijail0 -m -M /usr/bin/id
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)

Change-Id: I8f91bc43516a47df7bbf12a121cf658e89861aa0
diff --git a/libminijail.c b/libminijail.c
index 597fef2..5513b19 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -133,6 +133,7 @@
 		int enter_net:1;
 		int ns_cgroups:1;
 		int userns:1;
+		int disable_setgroups:1;
 		int seccomp:1;
 		int remount_proc_ro:1;
 		int no_new_privs:1;
@@ -463,6 +464,11 @@
 	j->flags.userns = 1;
 }
 
+void API minijail_namespace_user_disable_setgroups(struct minijail *j)
+{
+	j->flags.disable_setgroups = 1;
+}
+
 int API minijail_uidmap(struct minijail *j, const char *uidmap)
 {
 	j->uidmap = strdup(uidmap);
@@ -1263,6 +1269,9 @@
 {
 	if (j->uidmap && write_proc_file(j->initpid, j->uidmap, "uid_map") != 0)
 		kill_child_and_die(j, "failed to write uid_map");
+	if (j->gidmap && j->flags.disable_setgroups &&
+	    write_proc_file(j->initpid, "deny", "setgroups") != 0)
+		kill_child_and_die(j, "failed to disable setgroups(2)");
 	if (j->gidmap && write_proc_file(j->initpid, j->gidmap, "gid_map") != 0)
 		kill_child_and_die(j, "failed to write gid_map");
 }
diff --git a/libminijail.h b/libminijail.h
index 98d5009..ae829d9 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -75,6 +75,7 @@
  */
 void minijail_namespace_pids(struct minijail *j);
 void minijail_namespace_user(struct minijail *j);
+void minijail_namespace_user_disable_setgroups(struct minijail *j);
 int minijail_uidmap(struct minijail *j, const char *uidmap);
 int minijail_gidmap(struct minijail *j, const char *gidmap);
 void minijail_remount_proc_readonly(struct minijail *j);
diff --git a/minijail0.c b/minijail0.c
index dbe1797..48e1d07 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -195,7 +195,7 @@
 		return 1;
 
 	const char *optstring =
-	    "u:g:sS:c:C:P:b:V:f:m::M:k:a:e::T:vrGhHinNplLtIUKY";
+	    "u:g:sS:c:C:P:b:V:f:m::M::k:a:e::T:vrGhHinNplLtIUKY";
 	while ((opt = getopt(argc, argv, optstring)) != -1) {
 		switch (opt) {
 		case 'u':
@@ -341,10 +341,27 @@
 		case 'M':
 			minijail_namespace_user(j);
 			minijail_namespace_pids(j);
-			if (0 != minijail_gidmap(j, optarg)) {
+
+			if (optarg) {
+				map = strdup(optarg);
+			} else {
+				/*
+				 * If no map is passed, map the current gid to
+				 * root.
+				 * This means that we're likely *not* running as
+				 * root, so we also have to disable
+				 * setgroups(2) to be able to set the gid map.
+				 * See http://man7.org/linux/man-pages/man7/user_namespaces.7.html
+				 */
+				minijail_namespace_user_disable_setgroups(j);
+
+				map = build_idmap(0, getgid());
+			}
+			if (0 != minijail_gidmap(j, map)) {
 				fprintf(stderr, "Could not set gid map.\n");
 				exit(1);
 			}
+			free(map);
 			break;
 		case 'a':
 			if (0 != minijail_use_alt_syscall(j, optarg)) {