allow specifying larger /tmp tmpfs mounts

Extract the size string-parsing and overflow-checking wrapper into util.c.

Test: New unit tests.
Change-Id: I31ba2f1a77217a2f13cda078e5e6a80104fbcd32
Signed-off-by: Martin Pelikán <mpel@google.com>
diff --git a/libminijail.c b/libminijail.c
index aa789cd..4690c6b 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -175,6 +175,7 @@
 	struct mountpoint *mounts_head;
 	struct mountpoint *mounts_tail;
 	size_t mounts_count;
+	size_t tmpfs_size;
 	char *cgroups[MAX_CGROUPS];
 	size_t cgroup_count;
 };
@@ -597,8 +598,19 @@
 	return strdup(path_inside_chroot);
 }
 
+size_t minijail_get_tmpfs_size(const struct minijail *j)
+{
+	return j->tmpfs_size;
+}
+
 void API minijail_mount_tmp(struct minijail *j)
 {
+	minijail_mount_tmp_size(j, 64 * 1024 * 1024);
+}
+
+void API minijail_mount_tmp_size(struct minijail *j, size_t size)
+{
+	j->tmpfs_size = size;
 	j->flags.mount_tmp = 1;
 }
 
@@ -1236,10 +1248,21 @@
 	return 0;
 }
 
-static int mount_tmp(void)
+static int mount_tmp(const struct minijail *j)
 {
+	const char fmt[] = "size=%zu,mode=1777";
+	/* Count for the user storing ULLONG_MAX literally + extra space. */
+	char data[sizeof(fmt) + sizeof("18446744073709551615ULL")];
+	int ret;
+
+	ret = snprintf(data, sizeof(data), fmt, j->tmpfs_size);
+
+	if (ret <= 0)
+		pdie("tmpfs size spec error");
+	else if ((size_t)ret >= sizeof(data))
+		pdie("tmpfs size spec too large");
 	return mount("none", "/tmp", "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID,
-	             "size=64M,mode=1777");
+		     data);
 }
 
 static int remount_proc_readonly(const struct minijail *j)
@@ -1630,7 +1653,7 @@
 	if (j->flags.pivot_root && enter_pivot_root(j))
 		pdie("pivot_root");
 
-	if (j->flags.mount_tmp && mount_tmp())
+	if (j->flags.mount_tmp && mount_tmp(j))
 		pdie("mount_tmp");
 
 	if (j->flags.remount_proc_ro && remount_proc_readonly(j))