Allow mounting of a tmpfs /tmp in the chroot

Added the -t option to minijail so a tmpfs can be used
in the chroot

BUG=chromium:356246
TEST=Tested with autotest security_Minijail0
CQ-DEPEND=CL:201147

Change-Id: I660629a8b8fa1c2bf4fc59d2499ff806aa280449
Reviewed-on: https://chromium-review.googlesource.com/201133
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Tested-by: Lee Campbell <leecam@chromium.org>
Commit-Queue: Lee Campbell <leecam@chromium.org>
diff --git a/libminijail.c b/libminijail.c
index fee657d..90fd4a7 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -85,6 +85,7 @@
 		int seccomp_filter:1;
 		int log_seccomp_filter:1;
 		int chroot:1;
+		int mount_tmp:1;
 	} flags;
 	uid_t uid;
 	gid_t gid;
@@ -286,6 +287,11 @@
 	return 0;
 }
 
+void API minijail_mount_tmp(struct minijail *j)
+{
+	j->flags.mount_tmp = 1;
+}
+
 int API minijail_bind(struct minijail *j, const char *src, const char *dest,
                       int writeable) {
 	struct binding *b;
@@ -576,6 +582,11 @@
 	return 0;
 }
 
+int mount_tmp(void)
+{
+	return mount("none", "/tmp", "tmpfs", 0, "size=128M,mode=777");
+}
+
 int remount_readonly(void)
 {
 	const char *kProcPath = "/proc";
@@ -747,6 +758,9 @@
 	if (j->flags.chroot && enter_chroot(j))
 		pdie("chroot");
 
+	if (j->flags.chroot && j->flags.mount_tmp && mount_tmp())
+		pdie("mount_tmp");
+
 	if (j->flags.readonly && remount_readonly())
 		pdie("remount");
 
diff --git a/libminijail.h b/libminijail.h
index 0d5e15a..211b6fc 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -70,6 +70,11 @@
  */
 int minijail_enter_chroot(struct minijail *j, const char *dir);
 
+/* minijail_mount_tmp: enables mounting of a tmpfs filesystem on /tmp.
+ * As be rules of bind mounts, /tmp must exist in chroot.
+ */
+void minijail_mount_tmp(struct minijail *j);
+
 /* minijail_bind: bind-mounts @src into @j as @dest, optionally writeable
  * @j         minijail to bind inside
  * @src       source to bind
diff --git a/minijail0.1 b/minijail0.1
index d9c880a..1d85385 100644
--- a/minijail0.1
+++ b/minijail0.1
@@ -17,6 +17,11 @@
 \fB-C <dir>\fR
 Change root (using chroot(2)) to <dir>.
 .TP
+\fB-t\fR
+Mounts a tmpfs filesystem on /tmp. /tmp must exist in the chroot.
+This must be used with -C. The default filesystem has a max size of 128M
+and has standard /tmp permissions (777).
+.TP
 \fB-g\fR, this allows a program to have access to only certain parts of root's
 default privileges while running as another user and group ID altogether. Note
 that these capabilities are not inherited by subprocesses of the process given
diff --git a/minijail0.c b/minijail0.c
index e857ea4..82f67c1 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -74,14 +74,15 @@
 {
 	size_t i;
 
-	printf("Usage: %s [-Ghinprsv] [-b <src>,<dest>[,<writeable>]] "
+	printf("Usage: %s [-Ghinprsvt] [-b <src>,<dest>[,<writeable>]] "
 	       "[-c <caps>] [-C <dir>] [-g <group>] [-S <file>] [-u <user>] "
 	       "<program> [args...]\n"
 	       "  -b:         binds <src> to <dest> in chroot. Multiple "
 	       "instances allowed\n"
 	       "  -c <caps>:  restrict caps to <caps>\n"
 	       "  -C <dir>:   chroot to <dir>\n"
-	       "  -e          enter a network namespace\n"
+	       "  -t:         mount tmpfs at /tmp inside chroot\n"
+	       "  -e:         enter a network namespace\n"
 	       "  -G:         inherit secondary groups from uid\n"
 	       "  -g <group>: change gid to <group>\n"
 	       "  -h:         help (this message)\n"
@@ -120,9 +121,11 @@
 {
 	int opt;
 	int use_pid_ns = 0;
+	int chroot = 0;
+	int mount_tmp = 0;
 	if (argc > 1 && argv[1][0] != '-')
 		return 1;
-	while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:vrGhHinpLe")) != -1) {
+	while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:vrGhHinpLet")) != -1) {
 		switch (opt) {
 		case 'u':
 			set_user(j, optarg);
@@ -150,7 +153,13 @@
 			use_caps(j, optarg);
 			break;
 		case 'C':
-			minijail_enter_chroot(j, optarg);
+			if (0 != minijail_enter_chroot(j, optarg))
+				exit(1);
+			chroot = 1;
+			break;
+		case 't':
+			minijail_mount_tmp(j);
+			mount_tmp = 1;
 			break;
 		case 'v':
 			minijail_namespace_vfs(j);
@@ -165,7 +174,7 @@
 			if (*exit_immediately) {
 				fprintf(stderr,
 					"Could not enter pid namespace because "
-					"'-i' was specified.");
+					"'-i' was specified.\n");
 				exit(1);
 			}
 			use_pid_ns = 1;
@@ -178,7 +187,7 @@
 			if (use_pid_ns) {
 				fprintf(stderr,
 					"Could not disable init loop because "
-					"'-p' was specified.");
+					"'-p' was specified.\n");
 				exit(1);
 			}
 			*exit_immediately = 1;
@@ -191,13 +200,21 @@
 			exit(1);
 		}
 		if (optind < argc && argv[optind][0] != '-')
-			return optind;
+			break;
 	}
 
 	if (argc == optind) {
 		usage(argv[0]);
 		exit(1);
 	}
+
+	if (mount_tmp && !chroot) {
+		fprintf(stderr,
+		        "Could not mount tmpfs at /tmp "
+		        "because '-C' was not specified.\n");
+		exit(1);
+	}
+
 	return optind;
 }