release-request-b6f2d5b3-a3d6-410f-b58f-c85ba8187177-for-git_oc-mr1-release-4173087 snap-temp-L93200000081515229

Change-Id: Ie39dcf8a1e16a14f6849d02b9ed013b11141ee26
diff --git a/libminijail.c b/libminijail.c
index 6381c30..4d61b0d 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -166,6 +166,7 @@
 	size_t cgroup_count;
 	struct minijail_rlimit rlimits[MAX_RLIMITS];
 	size_t rlimit_count;
+	uint64_t securebits_skip_mask;
 };
 
 /*
@@ -434,6 +435,12 @@
 	j->flags.new_session_keyring = 1;
 }
 
+void API minijail_skip_setting_securebits(struct minijail *j,
+					  uint64_t securebits_skip_mask)
+{
+	j->securebits_skip_mask = securebits_skip_mask;
+}
+
 void API minijail_skip_remount_private(struct minijail *j)
 {
 	j->flags.skip_remount_private = 1;
@@ -1726,7 +1733,7 @@
 		if (prctl(PR_SET_KEEPCAPS, 1))
 			pdie("prctl(PR_SET_KEEPCAPS) failed");
 
-		if (lock_securebits() < 0) {
+		if (lock_securebits(j->securebits_skip_mask) < 0) {
 			pdie("locking securebits failed");
 		}
 	}
diff --git a/libminijail.h b/libminijail.h
index bad8407..ff06348 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -64,6 +64,8 @@
 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);
+void minijail_skip_setting_securebits(struct minijail *j,
+				      uint64_t securebits_skip_mask);
 
 /*
  * This option is *dangerous* as it negates most of the functionality of
diff --git a/minijail0.c b/minijail0.c
index fb98163..6cc5efa 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -48,6 +48,18 @@
 	}
 }
 
+static void skip_securebits(struct minijail *j, const char *arg)
+{
+	uint64_t securebits_skip_mask;
+	char *end = NULL;
+	securebits_skip_mask = strtoull(arg, &end, 16);
+	if (*end) {
+		fprintf(stderr, "Invalid securebit mask: '%s'\n", arg);
+		exit(1);
+	}
+	minijail_skip_setting_securebits(j, securebits_skip_mask);
+}
+
 static void use_caps(struct minijail *j, const char *arg)
 {
 	uint64_t caps;
@@ -137,6 +149,9 @@
 	       "  -a <table>:   Use alternate syscall table <table>.\n"
 	       "  -b:           Bind <src> to <dest> in chroot.\n"
 	       "                Multiple instances allowed.\n"
+	       "  -B <mask>     Skip setting securebits in <mask> when restricting capabilities (-c).\n"
+	       "                By default, SECURE_NOROOT, SECURE_NO_SETUID_FIXUP, and \n"
+	       "                SECURE_KEEP_CAPS (together with their respective locks) are set.\n"
 	       "  -k:           Mount <src> at <dest> in chroot.\n"
 	       "                <flags> and <data> can be specified as in mount(2).\n"
 	       "                Multiple instances allowed.\n"
@@ -229,7 +244,7 @@
 	const char *filter_path;
 
 	const char *optstring =
-	    "+u:g:sS:c:C:P:b:V:f:m::M::k:a:e::R:T:vrGhHinNplLt::IUKwyYz";
+	    "+u:g:sS:c:C:P:b:B:V:f:m::M::k:a:e::R:T:vrGhHinNplLt::IUKwyYz";
 	int longoption_index = 0;
 	/* clang-format off */
 	const struct option long_options[] = {
@@ -288,6 +303,9 @@
 			add_binding(j, optarg);
 			binding = 1;
 			break;
+		case 'B':
+			skip_securebits(j, optarg);
+			break;
 		case 'c':
 			caps = 1;
 			use_caps(j, optarg);
diff --git a/system.c b/system.c
index 49f8915..9373e87 100644
--- a/system.c
+++ b/system.c
@@ -51,7 +51,7 @@
 _Static_assert(SECURE_ALL_BITS == 0x55, "SECURE_ALL_BITS == 0x55.");
 #endif
 
-int lock_securebits(void)
+int lock_securebits(uint64_t skip_mask)
 {
 	/*
 	 * Ambient capabilities can only be raised if they're already present
@@ -59,9 +59,12 @@
 	 * need to lock the NO_CAP_AMBIENT_RAISE securebit, since we are already
 	 * configuring the permitted and inheritable set.
 	 */
-	int securebits_ret =
-	    prctl(PR_SET_SECUREBITS,
-		  SECURE_BITS_NO_AMBIENT | SECURE_LOCKS_NO_AMBIENT);
+	uint64_t securebits =
+	    (SECURE_BITS_NO_AMBIENT | SECURE_LOCKS_NO_AMBIENT) & ~skip_mask;
+	if (!securebits) {
+		return 0;
+	}
+	int securebits_ret = prctl(PR_SET_SECUREBITS, securebits);
 	if (securebits_ret < 0) {
 		pwarn("prctl(PR_SET_SECUREBITS) failed");
 		return -1;
diff --git a/system.h b/system.h
index 6f1be49..6b7da8b 100644
--- a/system.h
+++ b/system.h
@@ -48,7 +48,7 @@
 #define PR_CAP_AMBIENT_CLEAR_ALL 4
 #endif
 
-int lock_securebits(void);
+int lock_securebits(uint64_t skip_mask);
 
 unsigned int get_last_valid_cap(void);
 int cap_ambient_supported(void);