Snap for 5611628 from 9b41e654d3dd9d35d3d353848a7ddf315786b544 to sdk-release

Change-Id: Ia0038ddc1f62fba1ae6dc5834a7fec1c85aa432d
diff --git a/libminijail.c b/libminijail.c
index ee9b9a0..a5e4073 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -163,6 +163,7 @@
 		int close_open_fds : 1;
 		int new_session_keyring : 1;
 		int forward_signals : 1;
+		int setsid : 1;
 	} flags;
 	uid_t uid;
 	gid_t gid;
@@ -237,6 +238,7 @@
 	j->flags.pid_file = 0;
 	j->flags.cgroups = 0;
 	j->flags.forward_signals = 0;
+	j->flags.setsid = 0;
 	j->remount_mode = 0;
 }
 
@@ -733,6 +735,11 @@
 	return 0;
 }
 
+int API minijail_create_session(struct minijail *j) {
+	j->flags.setsid = 1;
+	return 0;
+}
+
 int API minijail_mount_with_data(struct minijail *j, const char *src,
 				 const char *dest, const char *type,
 				 unsigned long flags, const char *data)
@@ -2930,15 +2937,15 @@
 	}
 
 	/*
-	 * If any of stdin, stdout, or stderr are TTYs, create a new session.
-	 * This prevents the jailed process from using the TIOCSTI ioctl
-	 * to push characters into the parent process terminal's input buffer,
-	 * therefore escaping the jail.
+	 * If any of stdin, stdout, or stderr are TTYs, or setsid flag is
+	 * set, create a new session. This prevents the jailed process from
+	 * using the TIOCSTI ioctl to push characters into the parent process
+	 * terminal's input buffer, therefore escaping the jail.
 	 *
 	 * Since it has just forked, the child will not be a process group
 	 * leader, and this call to setsid() should always succeed.
 	 */
-	if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO) ||
+	if (j->flags.setsid || isatty(STDIN_FILENO) || isatty(STDOUT_FILENO) ||
 	    isatty(STDERR_FILENO)) {
 		if (setsid() < 0) {
 			pdie("setsid() failed");
diff --git a/libminijail.h b/libminijail.h
index 0853c17..2ea5ad8 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -160,6 +160,9 @@
  */
 int minijail_forward_signals(struct minijail *j);
 
+/* The jailed child process should call setsid() to create a new session. */
+int minijail_create_session(struct minijail *j);
+
 /*
  * minijail_enter_chroot: enables chroot() restriction for @j
  * @j   minijail to apply restriction to
diff --git a/libminijail_unittest.cc b/libminijail_unittest.cc
index 8ba331a..d6896bf 100644
--- a/libminijail_unittest.cc
+++ b/libminijail_unittest.cc
@@ -877,3 +877,47 @@
   ASSERT_EQ(-EINVAL, parse_size(&size, "-1G"));
   ASSERT_EQ(-EINVAL, parse_size(&size, "; /bin/rm -- "));
 }
+
+void TestCreateSession(bool create_session) {
+  int status;
+  int pipe_fds[2];
+  pid_t child_pid;
+  pid_t parent_sid = getsid(0);
+  ssize_t pid_size = sizeof(pid_t);
+
+  ScopedMinijail j(minijail_new());
+  // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
+  // a new session because of that.
+  minijail_close_open_fds(j.get());
+
+  if (create_session)
+    minijail_create_session(j.get());
+
+  ASSERT_EQ(pipe(pipe_fds), 0);
+  minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
+
+  child_pid = minijail_fork(j.get());
+  ASSERT_GE(child_pid, 0);
+  if (child_pid == 0) {
+    pid_t sid_in_parent;
+    ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
+    if (create_session)
+      ASSERT_NE(sid_in_parent, getsid(0));
+    else
+      ASSERT_EQ(sid_in_parent, getsid(0));
+    exit(0);
+  }
+
+  EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
+  waitpid(child_pid, &status, 0);
+  ASSERT_TRUE(WIFEXITED(status));
+  EXPECT_EQ(WEXITSTATUS(status), 0);
+}
+
+TEST(Test, default_no_new_session) {
+  TestCreateSession(/*create_session=*/false);
+}
+
+TEST(Test, create_new_session) {
+  TestCreateSession(/*create_session=*/true);
+}