minijail: Allow skipping setting securebits when restricting caps
This change allows the user to optionally skip setting a subset of the
securebits that are automatically set when restricting caps.
Bug: 63069223
Test: $ gcc -static -xc -o securebits - << EOF
#include <stdio.h>
#include <sys/prctl.h>
int main()
{
printf("%x\n", prctl(PR_GET_SECUREBITS));
}
EOF
$ sudo ./minijail0 -c 1fffffffff --ambient ./securebits
2f
$ sudo ./minijail0 -c 1fffffffff --ambient -B 2f ./securebits
0
Change-Id: Ie247302bbbb35f04caa2066541a8c175f6c94976
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);