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);
}