Merge "Compile 'minijail0' on Brillo/Android."
diff --git a/libminijail.c b/libminijail.c
index b42ac72..0806d17 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -110,6 +110,7 @@
 		int mount_tmp:1;
 		int do_init:1;
 		int pid_file:1;
+		int cgroups:1;
 		int alt_syscall:1;
 		int reset_signal_mask:1;
 	} flags;
@@ -150,6 +151,7 @@
 	j->flags.pids = 0;
 	j->flags.do_init = 0;
 	j->flags.pid_file = 0;
+	j->flags.cgroups = 0;
 }
 
 /*
@@ -272,9 +274,9 @@
 		return -ENOMEM;
 	getpwnam_r(user, &pw, buf, sz, &ppw);
 	/*
-	 * We're safe to free the buffer here. The strings inside pw point
-	 * inside buf, but we don't use any of them; this leaves the pointers
-	 * dangling but it's safe. ppw points at pw if getpwnam_r succeeded.
+	 * We're safe to free the buffer here. The strings inside |pw| point
+	 * inside |buf|, but we don't use any of them; this leaves the pointers
+	 * dangling but it's safe. |ppw| points at |pw| if getpwnam_r(3) succeeded.
 	 */
 	free(buf);
 	/* getpwnam_r(3) does *not* set errno when |ppw| is NULL. */
@@ -542,6 +544,7 @@
 	if (!j->cgroups[j->cgroup_count])
 		return -ENOMEM;
 	j->cgroup_count++;
+	j->flags.cgroups = 1;
 	return 0;
 }
 
@@ -990,14 +993,14 @@
 	char *dest;
 	int remount_ro = 0;
 
-	/* dest has a leading "/" */
+	/* |dest| has a leading "/". */
 	if (asprintf(&dest, "%s%s", j->chrootdir, m->dest) < 0)
 		return -ENOMEM;
 
 	/*
-	 * R/O bind mounts have to be remounted since bind and ro can't both be
-	 * specified in the original bind mount. Remount R/O after the initial
-	 * mount.
+	 * R/O bind mounts have to be remounted since 'bind' and 'ro'
+	 * can't both be specified in the original bind mount.
+	 * Remount R/O after the initial mount.
 	 */
 	if ((m->flags & MS_BIND) && (m->flags & MS_RDONLY)) {
 		remount_ro = 1;
@@ -1129,7 +1132,7 @@
 	write_pid_to_path(j->initpid, j->pid_file_path);
 }
 
-static void assign_cgroups(const struct minijail *j)
+static void add_to_cgroups(const struct minijail *j)
 {
 	size_t i;
 
@@ -1341,6 +1344,9 @@
 		pdie("unshare(net)");
 	}
 
+	if (j->mounts_head && !(j->flags.chroot || j->flags.pivot_root))
+		die("can't bind-mount without chroot or pivot_root");
+
 	if (j->flags.chroot && enter_chroot(j))
 		pdie("chroot");
 
@@ -1633,7 +1639,7 @@
 
 	if (!use_preload) {
 		if (j->flags.caps)
-			die("Capabilities are not supported without "
+			die("capabilities are not supported without "
 			    "LD_PRELOAD");
 	}
 
@@ -1688,9 +1694,10 @@
 
 	/*
 	 * If we want to set up a new uid/gid mapping in the user namespace,
-	 * create the pipe(2) to sync between parent and child.
+	 * or if we need to add the child process to cgroups, create the pipe(2)
+	 * to sync between parent and child.
 	 */
-	if (j->flags.userns || j->cgroup_count) {
+	if (j->flags.userns || j->flags.cgroups) {
 		sync_child = 1;
 		if (pipe(child_sync_pipe_fds))
 			return -EFAULT;
@@ -1770,7 +1777,8 @@
 		if (j->flags.pid_file)
 			write_pid_file(j);
 
-		assign_cgroups(j);
+		if (j->flags.cgroups)
+			add_to_cgroups(j);
 
 		if (j->flags.userns)
 			write_ugid_mappings(j);
diff --git a/minijail0.c b/minijail0.c
index 442934c..9b7260d 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -67,7 +67,7 @@
 		exit(1);
 	}
 	if (minijail_bind(j, src, dest, flags ? atoi(flags) : 0)) {
-		fprintf(stderr, "Bind failure.\n");
+		fprintf(stderr, "minijail_bind failed.\n");
 		exit(1);
 	}
 }
@@ -161,6 +161,7 @@
 {
 	int opt;
 	int use_seccomp_filter = 0;
+	int binding = 0;
 	int pivot_root = 0, chroot = 0;
 	const size_t path_max = 4096;
 	const char *filter_path;
@@ -185,8 +186,7 @@
 		case 'S':
 			minijail_use_seccomp_filter(j);
 			if (strlen(optarg) >= path_max) {
-				fprintf(stderr,
-					"Filter path is too long.\n");
+				fprintf(stderr, "Filter path is too long.\n");
 				exit(1);
 			}
 			filter_path = strndup(optarg, path_max);
@@ -205,6 +205,7 @@
 			break;
 		case 'b':
 			add_binding(j, optarg);
+			binding = 1;
 			break;
 		case 'c':
 			use_caps(j, optarg);
@@ -212,7 +213,7 @@
 		case 'C':
 			if (pivot_root) {
 				fprintf(stderr, "Could not set chroot because "
-				                "'-P' was specified.\n");
+						"'-P' was specified.\n");
 				exit(1);
 			}
 			if (0 != minijail_enter_chroot(j, optarg)) {
@@ -226,8 +227,9 @@
 			break;
 		case 'P':
 			if (chroot) {
-				fprintf(stderr, "Could not set pivot_root because "
-				                "'-C' was specified.\n");
+				fprintf(stderr,
+					"Could not set pivot_root because "
+					"'-C' was specified.\n");
 				exit(1);
 			}
 			if (0 != minijail_enter_pivot_root(j, optarg)) {
@@ -239,7 +241,8 @@
 			break;
 		case 'f':
 			if (0 != minijail_write_pid_file(j, optarg)) {
-				fprintf(stderr, "Could not prepare pid file path.\n");
+				fprintf(stderr,
+					"Could not prepare pid file path.\n");
 				exit(1);
 			}
 			break;
@@ -285,7 +288,7 @@
 			minijail_namespace_user(j);
 			minijail_namespace_pids(j);
 			if (0 != minijail_uidmap(j, optarg)) {
-				fprintf(stderr, "Could not set uidmap\n");
+				fprintf(stderr, "Could not set uidmap.\n");
 				exit(1);
 			}
 			break;
@@ -293,13 +296,14 @@
 			minijail_namespace_user(j);
 			minijail_namespace_pids(j);
 			if (0 != minijail_gidmap(j, optarg)) {
-				fprintf(stderr, "Could not set gidmap\n");
+				fprintf(stderr, "Could not set gidmap.\n");
 				exit(1);
 			}
 			break;
 		case 'a':
 			if (0 != minijail_use_alt_syscall(j, optarg)) {
-				fprintf(stderr, "Could not set alt-syscall table\n");
+				fprintf(stderr,
+					"Could not set alt-syscall table.\n");
 				exit(1);
 			}
 			break;
@@ -311,6 +315,13 @@
 			break;
 	}
 
+	/* Only allow bind mounts when entering a chroot or using pivot_root. */
+	if (binding && !(chroot || pivot_root)) {
+		fprintf(stderr, "Can't add bind mounts without chroot or"
+				" pivot_root.\n");
+		exit(1);
+	}
+
 	/*
 	 * We parse seccomp filters here to make sure we've collected all
 	 * cmdline options.