Add a flag to drop access to the session keyring

Now that chrome os is moving over to ext4 based directory encryption, the
encryption keys are stored in the session keyring.  Applications that don't need
to access the encrypted user data directory don't need access to this keyring.
Add a flag for applications to drop access to the session keyring when they
don't need it.

Bug: crbug.com/682419
TEST=autotest in a later CL

Change-Id: I3cb8f120d9f4891d9a13f7fe342b0388e9975605
Signed-off-by: Chirantan Ekbote <chirantan@google.com>
diff --git a/libminijail.c b/libminijail.c
index 4690c6b..d005803 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -105,6 +105,9 @@
 
 #define MAX_CGROUPS 10 /* 10 different controllers supported by Linux. */
 
+/* Keyctl commands. */
+#define KEYCTL_JOIN_SESSION_KEYRING 1
+
 struct mountpoint {
 	char *src;
 	char *dest;
@@ -153,6 +156,7 @@
 		int alt_syscall : 1;
 		int reset_signal_mask : 1;
 		int close_open_fds : 1;
+		int new_session_keyring : 1;
 	} flags;
 	uid_t uid;
 	gid_t gid;
@@ -435,6 +439,11 @@
 	j->flags.enter_vfs = 1;
 }
 
+void API minijail_new_session_keyring(struct minijail *j)
+{
+	j->flags.new_session_keyring = 1;
+}
+
 void API minijail_skip_remount_private(struct minijail *j)
 {
 	j->flags.skip_remount_private = 1;
@@ -1647,6 +1656,11 @@
 	if (j->flags.ns_cgroups && unshare(CLONE_NEWCGROUP))
 		pdie("unshare(CLONE_NEWCGROUP) failed");
 
+	if (j->flags.new_session_keyring) {
+		if (syscall(SYS_keyctl, KEYCTL_JOIN_SESSION_KEYRING, NULL) < 0)
+			pdie("keyctl(KEYCTL_JOIN_SESSION_KEYRING) failed");
+	}
+
 	if (j->flags.chroot && enter_chroot(j))
 		pdie("chroot");
 
diff --git a/libminijail.h b/libminijail.h
index 14aeece..2bf3024 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -61,6 +61,8 @@
 void minijail_reset_signal_mask(struct minijail *j);
 void minijail_namespace_vfs(struct minijail *j);
 void minijail_namespace_enter_vfs(struct minijail *j, const char *ns_path);
+void minijail_new_session_keyring(struct minijail *j);
+
 /*
  * This option is *dangerous* as it negates most of the functionality of
  * minijail_namespace_vfs(). You very likely don't need this.
diff --git a/minijail0.1 b/minijail0.1
index cdc3083..e186fef 100644
--- a/minijail0.1
+++ b/minijail0.1
@@ -138,6 +138,10 @@
 \fB-V <file>\fR
 Enter the VFS namespace specified by \fIfile\fR.
 .TP
+\fB-w\fR
+Create and join a new anonymous session keyring.  See \fBkeyrings\fR(7) for more
+details.
+.TP
 \fB-y\fR
 Keep the current user's supplementary groups.
 .TP
diff --git a/minijail0.c b/minijail0.c
index bfb5671..12537c3 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -175,6 +175,7 @@
 	       "  -U:         Enter new user namespace (implies -p).\n"
 	       "  -v:         Enter new mount namespace.\n"
 	       "  -V <file>:  Enter specified mount namespace.\n"
+	       "  -w:         Create and join a new anonymous session keyring.\n"
 	       "  -Y:         Synchronize seccomp filters across thread group.\n");
 	/* clang-format on */
 }
@@ -206,7 +207,7 @@
 		return 1;
 
 	const char *optstring =
-	    "u:g:sS:c:C:P:b:V:f:m::M::k:a:e::T:vrGhHinNplLt::IUKyY";
+	    "u:g:sS:c:C:P:b:V:f:m::M::k:a:e::T:vrGhHinNplLt::IUKwyY";
 	while ((opt = getopt(argc, argv, optstring)) != -1) {
 		switch (opt) {
 		case 'u':
@@ -413,6 +414,9 @@
 				exit(1);
 			}
 			break;
+		case 'w':
+			minijail_new_session_keyring(j);
+			break;
 		case 'Y':
 			minijail_set_seccomp_filter_tsync(j);
 			break;