Minijail: with no_new_privs, drop privileges before setting seccomp filter.
BUG=chromium-os:32619
TEST=unit
TEST=security_Minijail0, security_Minijail_seccomp, platform_CrosDisksArchive
Change-Id: I88d5e8b441871bf92f108ff4bb1db27940b51240
Reviewed-on: https://gerrit.chromium.org/gerrit/31238
Tested-by: Jorge Lucangeli Obes <jorgelo@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 4da1f66..fdf6f29 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -566,6 +566,25 @@
return 0;
}
+void drop_ugid(const struct minijail *j)
+{
+ if (j->flags.usergroups) {
+ if (initgroups(j->user, j->usergid))
+ pdie("initgroups");
+ } else {
+ /* Only attempt to clear supplemental groups if we are changing
+ * users. */
+ if ((j->uid || j->gid) && setgroups(0, NULL))
+ pdie("setgroups");
+ }
+
+ if (j->flags.gid && setresgid(j->gid, j->gid, j->gid))
+ pdie("setresgid");
+
+ if (j->flags.uid && setresuid(j->uid, j->uid, j->uid))
+ pdie("setresuid");
+}
+
void drop_caps(const struct minijail *j)
{
cap_t caps = cap_get_proc();
@@ -601,6 +620,36 @@
}
}
+void set_seccomp_filter(const struct minijail *j)
+{
+ /*
+ * Set no_new_privs. See </kernel/seccomp.c> and </kernel/sys.c>
+ * in the kernel source tree for an explanation of the parameters.
+ */
+ if (j->flags.no_new_privs) {
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
+ pdie("prctl(PR_SET_NO_NEW_PRIVS)");
+ }
+
+ /*
+ * If we're logging seccomp filter failures,
+ * install the SIGSYS handler first.
+ */
+ if (j->flags.seccomp_filter && j->flags.log_seccomp_filter) {
+ if (install_sigsys_handler())
+ pdie("install SIGSYS handler");
+ warn("logging seccomp filter failures");
+ }
+
+ /*
+ * Install the syscall filter.
+ */
+ if (j->flags.seccomp_filter) {
+ if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, j->filter_prog))
+ pdie("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
+ }
+}
+
void API minijail_enter(const struct minijail *j)
{
if (j->flags.pids)
@@ -639,55 +688,31 @@
}
/*
- * Set no_new_privs before installing seccomp filter. See
- * </kernel/seccomp.c> and </kernel/sys.c> in the kernel source tree for
- * an explanation of the parameters.
+ * If we're setting no_new_privs, we can drop privileges
+ * before setting seccomp filter. This way filter policies
+ * don't need to allow privilege-dropping syscalls.
*/
if (j->flags.no_new_privs) {
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
- pdie("prctl(PR_SET_NO_NEW_PRIVS)");
- }
+ drop_ugid(j);
+ if (j->flags.caps)
+ drop_caps(j);
- /*
- * If we're logging seccomp filter failures,
- * install the SIGSYS handler first.
- */
- if (j->flags.seccomp_filter && j->flags.log_seccomp_filter) {
- if (install_sigsys_handler())
- pdie("install SIGSYS handler");
- warn("logging seccomp filter failures");
- }
-
- /*
- * 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");
+ set_seccomp_filter(j);
} else {
- /* Only attempt to clear supplemental groups if we are changing
- * users. */
- if ((j->uid || j->gid) && setgroups(0, NULL))
- pdie("setgroups");
+ /*
+ * If we're not setting no_new_privs,
+ * we need to set seccomp filter *before* dropping privileges.
+ * WARNING: this means that filter policies *must* allow
+ * setgroups()/setresgid()/setresuid() for dropping root and
+ * capget()/capset()/prctl() for dropping caps.
+ */
+ set_seccomp_filter(j);
+
+ drop_ugid(j);
+ if (j->flags.caps)
+ drop_caps(j);
}
- if (j->flags.gid && setresgid(j->gid, j->gid, j->gid))
- pdie("setresgid");
-
- if (j->flags.uid && setresuid(j->uid, j->uid, j->uid))
- pdie("setresuid");
-
- if (j->flags.caps)
- drop_caps(j);
-
/*
* seccomp has to come last since it cuts off all the other
* privilege-dropping syscalls :)