Add minijail_fork

Provide a method to fork and jail a child process. This is useful for
users that would normally call fork followed by minijail_enter in the
child. However this allows for user and pid namespaces to be set up by
the clone call in minijail_run_internal.

Change-Id: Ib7dc11e7c783eda93b899ef4b782846061d113d4
Signed-off-by: Dylan Reid <dgreid@chromium.org>
diff --git a/libminijail.c b/libminijail.c
index a38e89b..f2a937b 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -2052,14 +2052,17 @@
 /*
  * Structure that specifies how to start a minijail.
  *
- * filename - The program to exec in the child.
- * argv - Arguments for the child program.
+ * filename - The program to exec in the child. Required if `exec_in_child` = 1.
+ * argv - Arguments for the child program. Required if `exec_in_child` = 1.
  * use_preload - If true use LD_PRELOAD.
+ * exec_in_child - If true, run `filename`. Otherwise, the child will return to
+ *     the caller.
  */
 struct minijail_run_config {
 	const char *filename;
 	char *const *argv;
 	int use_preload;
+	int exec_in_child;
 };
 
 /*
@@ -2089,6 +2092,7 @@
 		.filename = filename,
 		.argv = argv,
 		.use_preload = true,
+		.exec_in_child = true,
 	};
 	struct minijail_run_status status = {};
 	return minijail_run_internal(j, &config, &status);
@@ -2101,6 +2105,7 @@
 		.filename = filename,
 		.argv = argv,
 		.use_preload = true,
+		.exec_in_child = true,
 	};
 	struct minijail_run_status status = {
 		.pchild_pid = pchild_pid,
@@ -2115,6 +2120,7 @@
 		.filename = filename,
 		.argv = argv,
 		.use_preload = true,
+		.exec_in_child = true,
 	};
 	struct minijail_run_status status = {
 		.pstdin_fd = pstdin_fd,
@@ -2130,6 +2136,7 @@
 		.filename = filename,
 		.argv = argv,
 		.use_preload = true,
+		.exec_in_child = true,
 	};
 	struct minijail_run_status status = {
 		.pstdin_fd = pstdin_fd,
@@ -2147,6 +2154,7 @@
 		.filename = filename,
 		.argv = argv,
 		.use_preload = false,
+		.exec_in_child = true,
 	};
 	struct minijail_run_status status = {};
 	return minijail_run_internal(j, &config, &status);
@@ -2164,6 +2172,7 @@
 		.filename = filename,
 		.argv = argv,
 		.use_preload = false,
+		.exec_in_child = true,
 	};
 	struct minijail_run_status status = {
 		.pstdin_fd = pstdin_fd,
@@ -2174,6 +2183,13 @@
 	return minijail_run_internal(j, &config, &status);
 }
 
+pid_t API minijail_fork(struct minijail *j)
+{
+	struct minijail_run_config config = {};
+	struct minijail_run_status status = {};
+	return minijail_run_internal(j, &config, &status);
+}
+
 static int minijail_run_internal(struct minijail *j,
 				 const struct minijail_run_config *config,
 				 struct minijail_run_status *status_out)
@@ -2197,6 +2213,11 @@
 	int use_preload = config->use_preload;
 
 	if (use_preload) {
+		if (j->hooks_head != NULL)
+			die("Minijail hooks are not supported with LD_PRELOAD");
+		if (!config->exec_in_child)
+			die("minijail_fork is not supported with LD_PRELOAD");
+
 		oldenv = getenv(kLdPreloadEnvVar);
 		if (oldenv) {
 			oldenv_copy = strdup(oldenv);
@@ -2216,10 +2237,6 @@
 		}
 	}
 
-	if (use_preload && j->hooks_head != NULL) {
-		die("Minijail hooks are not supported with LD_PRELOAD");
-	}
-
 	/*
 	 * Make the process group ID of this process equal to its PID.
 	 * In the non-interactive case (e.g. when the parent process is started
@@ -2413,6 +2430,12 @@
 			*status_out->pstderr_fd =
 				setup_pipe_end(stderr_fds, 0 /* read end */);
 
+		/*
+		 * If forking return the child pid, in the normal exec case
+		 * return 0 for success.
+		 */
+		if (!config->exec_in_child)
+			return child_pid;
 		return 0;
 	}
 	/* Child process. */
@@ -2530,10 +2553,15 @@
 		 */
 		j->flags.pids = 0;
 	}
-	/* Jail this process, then execve(2) the target. */
+
+	/*
+	 * Jail this process.
+	 * If forking, return.
+	 * If not, execve(2) the target.
+	 */
 	minijail_enter(j);
 
-	if (pid_namespace && do_init) {
+	if (config->exec_in_child && pid_namespace && do_init) {
 		/*
 		 * pid namespace: this process will become init inside the new
 		 * namespace. We don't want all programs we might exec to have
@@ -2558,6 +2586,9 @@
 
 	run_hooks_or_die(j, MINIJAIL_HOOK_EVENT_PRE_EXECVE);
 
+	if (!config->exec_in_child)
+		return 0;
+
 	/*
 	 * If we aren't pid-namespaced, or the jailed program asked to be init:
 	 *   calling process