Add API for PR_SET_NO_NEW_PRIVS and set seccomp filter before dropping root.
BUG=chromium-os:27878
TEST=minijail_unittest, syscall_filter_unittest
TEST=security_Minijail0
TEST=security_Minijail_seccomp
Change-Id: I78495fda8c14ca5b4f398806eb564b0756876735
Reviewed-on: https://gerrit.chromium.org/gerrit/21545
Tested-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: Will Drewry <wad@chromium.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Commit-Ready: Jorge Lucangeli Obes <jorgelo@chromium.org>
diff --git a/libminijail.c b/libminijail.c
index 78cfbc1..2b66042 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -6,6 +6,7 @@
#define _BSD_SOURCE
#define _GNU_SOURCE
+
#include <asm/unistd.h>
#include <ctype.h>
#include <errno.h>
@@ -40,7 +41,7 @@
/* Until these are reliably available in linux/prctl.h */
#ifndef PR_SET_SECCOMP
-# define PR_SET_SECCOMP 22
+# define PR_SET_SECCOMP 22
#endif
/* For seccomp_filter using BPF. */
@@ -80,6 +81,7 @@
int readonly:1;
int usergroups:1;
int ptrace:1;
+ int no_new_privs:1;
int seccomp_filter:1;
int chroot:1;
} flags;
@@ -185,6 +187,11 @@
j->flags.seccomp = 1;
}
+void API minijail_no_new_privs(struct minijail *j)
+{
+ j->flags.no_new_privs = 1;
+}
+
void API minijail_use_seccomp_filter(struct minijail *j)
{
/* TODO(jorgelo): re-enable this when the seccomp BPF merge is done. */
@@ -641,6 +648,26 @@
pdie("prctl(PR_SET_SECUREBITS)");
}
+ /*
+ * Set no_new_privs before installing seccomp filter.
+ * TODO(jorgelo): document call to PR_SET_NO_NEW_PRIVS.
+ */
+ if (j->flags.no_new_privs) {
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
+ pdie("prctl(PR_SET_NO_NEW_PRIVS)");
+ }
+
+ /*
+ * Install seccomp filter before dropping root and caps.
+ * WARNING: this means that filter policies *must* allow
+ * setgroups()/setresgid()/setresuid() for dropping root and
+ * capget()/capset()/prctl() for dropping caps.
+ */
+ if (j->flags.seccomp_filter) {
+ if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, j->filter_prog))
+ pdie("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
+ }
+
if (j->flags.usergroups) {
if (initgroups(j->user, j->usergid))
pdie("initgroups");
@@ -664,16 +691,6 @@
* seccomp has to come last since it cuts off all the other
* privilege-dropping syscalls :)
*/
- if (j->flags.seccomp_filter) {
- /* TODO(jorgelo): document call to PR_SET_NO_NEW_PRIVS. */
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
- pdie("prctl(PR_SET_NO_NEW_PRIVS)");
- }
- if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, j->filter_prog)) {
- pdie("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
- }
- }
-
if (j->flags.seccomp && prctl(PR_SET_SECCOMP, 1))
pdie("prctl(PR_SET_SECCOMP)");
}
@@ -896,8 +913,11 @@
int st;
if (waitpid(j->initpid, &st, 0) < 0)
return -errno;
- if (!WIFEXITED(st))
+ if (!WIFEXITED(st)) {
+ if (WIFSIGNALED(st))
+ warn("child process received signal %d", WTERMSIG(st));
return MINIJAIL_ERR_JAIL;
+ }
return WEXITSTATUS(st);
}
diff --git a/libminijail.h b/libminijail.h
index 2f4ed7e..b1c425c 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -43,13 +43,10 @@
/* Does not take ownership of |group|. */
int minijail_change_group(struct minijail *j, const char *group);
void minijail_use_seccomp(struct minijail *j);
+void minijail_no_new_privs(struct minijail *j);
void minijail_use_seccomp_filter(struct minijail *j);
void minijail_force_seccomp_filter(struct minijail *j);
void minijail_parse_seccomp_filters(struct minijail *j, const char *path);
-int minijail_add_seccomp_filter(struct minijail *j, int nr,
- const char *filter);
-void minijail_use_seccomp_bpf(struct minijail *j);
-void minijail_parse_seccomp_bpf(struct minijail *j, const char *path);
void minijail_use_caps(struct minijail *j, uint64_t capmask);
void minijail_namespace_vfs(struct minijail *j);
/* Implies namespace_vfs and remount_readonly */
diff --git a/minijail0.c b/minijail0.c
index 524ac7f..2403100 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -69,9 +69,9 @@
static void usage(const char *progn)
{
- printf("Usage: %s [-Ghprsv] [-b <src>,<dest>[,<writeable>]] [-c <caps>] "
- "[-C <dir>] [-g <group>] [-S <file>] [-u <user>] <program> "
- "[args...]\n"
+ printf("Usage: %s [-Ghnprsv] [-b <src>,<dest>[,<writeable>]] "
+ "[-c <caps>] [-C <dir>] [-g <group>] [-S <file>] [-u <user>] "
+ "<program> [args...]\n"
" -b: binds <src> to <dest> in chroot. Multiple "
"instances allowed\n"
" -c <caps>: restrict caps to <caps>\n"
@@ -80,6 +80,7 @@
" -g <group>: change gid to <group>\n"
" -h: help (this message)\n"
" -H: seccomp filter help message\n"
+ " -n: set no_new_privs\n"
" -p: use pid namespace (implies -vr)\n"
" -r: remount /proc readonly (implies -v)\n"
" -s: use seccomp\n"
@@ -108,7 +109,7 @@
int opt;
int use_seccomp_filter = 0;
int dry_run = 1;
- while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:vrGhHpF")) != -1) {
+ while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:vrGhHnpF")) != -1) {
switch (opt) {
case 'u':
set_user(j, optarg);
@@ -116,6 +117,8 @@
case 'g':
set_group(j, optarg);
break;
+ case 'n':
+ minijail_no_new_privs(j);
case 's':
minijail_use_seccomp(j);
break;