Allow entering a user namespace with a default mapping.

Map the current uid as root inside the namespace. This is useful
to run Minijail as a non-root user.

Also refactor uid/gid map functions to remove duplicate code.

Bug: 30691131

Change-Id: Ideef616c8c13bcbacb14b826fa2fc064701a6f69
diff --git a/libminijail.c b/libminijail.c
index e2c30c3..37fd646 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -944,36 +944,41 @@
 	return ret;
 }
 
-static void write_ugid_mappings(const struct minijail *j)
+static void write_proc_file(pid_t pid, const char *content,
+			    const char *basename)
 {
-	int fd, ret, len;
-	size_t sz;
-	char fname[32];
+	int fd, ret;
+	size_t sz, len;
+	ssize_t written;
+	char filename[32];
 
-	sz = sizeof(fname);
+	sz = sizeof(filename);
+	ret = snprintf(filename, sz, "/proc/%d/%s", pid, basename);
+	if (ret < 0 || (size_t)ret >= sz)
+		die("failed to generate %s filename", basename);
+
+	fd = open(filename, O_WRONLY | O_CLOEXEC);
+	if (fd < 0)
+		pdie("failed to open '%s'", filename);
+
+	len = strlen(content);
+	written = write(fd, content, len);
+	if (written < 0)
+		pdie("failed to write '%s'", filename);
+
+	if ((size_t)written < len)
+		die("failed to write %zu bytes to '%s'", len, filename);
+
+	close(fd);
+}
+
+static void write_ugid_maps(const struct minijail *j)
+{
 	if (j->uidmap) {
-		ret = snprintf(fname, sz, "/proc/%d/uid_map", j->initpid);
-		if (ret < 0 || (size_t)ret >= sz)
-			die("failed to write file name of uid_map");
-		fd = open(fname, O_WRONLY | O_CLOEXEC);
-		if (fd < 0)
-			pdie("failed to open '%s'", fname);
-		len = strlen(j->uidmap);
-		if (write(fd, j->uidmap, len) < len)
-			die("failed to set uid_map");
-		close(fd);
+		write_proc_file(j->initpid, j->uidmap, "uid_map");
 	}
 	if (j->gidmap) {
-		ret = snprintf(fname, sz, "/proc/%d/gid_map", j->initpid);
-		if (ret < 0 || (size_t)ret >= sz)
-			die("failed to write file name of gid_map");
-		fd = open(fname, O_WRONLY | O_CLOEXEC);
-		if (fd < 0)
-			pdie("failed to open '%s'", fname);
-		len = strlen(j->gidmap);
-		if (write(fd, j->gidmap, len) < len)
-			die("failed to set gid_map");
-		close(fd);
+		write_proc_file(j->initpid, j->gidmap, "gid_map");
 	}
 }
 
@@ -1830,7 +1835,7 @@
 	}
 
 	/*
-	 * If we want to set up a new uid/gid mapping in the user namespace,
+	 * If we want to set up a new uid/gid map in the user namespace,
 	 * or if we need to add the child process to cgroups, create the pipe(2)
 	 * to sync between parent and child.
 	 */
@@ -1918,7 +1923,7 @@
 			add_to_cgroups(j);
 
 		if (j->flags.userns)
-			write_ugid_mappings(j);
+			write_ugid_maps(j);
 
 		if (sync_child)
 			parent_setup_complete(child_sync_pipe_fds);