[PATCH 1/3] Don't rely on geteuid() to know when to switch back from setuid root
As pointed out by Stephen Röttger <sroettger@google.com>, in drop_privs() we only drop root in the setuid case if geteuid() is 0. Typically geteuid() == 0 means we were setuid root and have not yet switched away from it. However, it is possible to make the geteuid call fail by passing a --userns2 namespace which doesn't have 0 mapped (i.e. where geteuid() will return the owerflow uid instead). If you do this, the pid 1 process in the sandbox will continue running as host uid 0, while dropping the dumpable flag, and at this point the user can ptrace attach the process and have root permissions. We fix this by not relying on the geteuid() call to know when we need to drop root uid, but rather keep track of whether we already switched from it. Gbp-Pq: Name CVE-2020-5291.patch
This commit is contained in:
parent
28861b915c
commit
31bfd4b130
15
bubblewrap.c
15
bubblewrap.c
|
@ -834,11 +834,13 @@ switch_to_user_with_privs (void)
|
||||||
|
|
||||||
/* Call setuid() and use capset() to adjust capabilities */
|
/* Call setuid() and use capset() to adjust capabilities */
|
||||||
static void
|
static void
|
||||||
drop_privs (bool keep_requested_caps)
|
drop_privs (bool keep_requested_caps,
|
||||||
|
bool already_changed_uid)
|
||||||
{
|
{
|
||||||
assert (!keep_requested_caps || !is_privileged);
|
assert (!keep_requested_caps || !is_privileged);
|
||||||
/* Drop root uid */
|
/* Drop root uid */
|
||||||
if (geteuid () == 0 && setuid (opt_sandbox_uid) < 0)
|
if (is_privileged && !already_changed_uid &&
|
||||||
|
setuid (opt_sandbox_uid) < 0)
|
||||||
die_with_error ("unable to drop root uid");
|
die_with_error ("unable to drop root uid");
|
||||||
|
|
||||||
drop_all_caps (keep_requested_caps);
|
drop_all_caps (keep_requested_caps);
|
||||||
|
@ -2296,6 +2298,9 @@ main (int argc,
|
||||||
if (opt_userns_fd != -1 && is_privileged)
|
if (opt_userns_fd != -1 && is_privileged)
|
||||||
die ("--userns doesn't work in setuid mode");
|
die ("--userns doesn't work in setuid mode");
|
||||||
|
|
||||||
|
if (opt_userns2_fd != -1 && is_privileged)
|
||||||
|
die ("--userns2 doesn't work in setuid mode");
|
||||||
|
|
||||||
/* We have to do this if we weren't installed setuid (and we're not
|
/* We have to do this if we weren't installed setuid (and we're not
|
||||||
* root), so let's just DWIM */
|
* root), so let's just DWIM */
|
||||||
if (!is_privileged && getuid () != 0 && opt_userns_fd == -1)
|
if (!is_privileged && getuid () != 0 && opt_userns_fd == -1)
|
||||||
|
@ -2499,7 +2504,7 @@ main (int argc,
|
||||||
die_with_error ("Setting userns2 failed");
|
die_with_error ("Setting userns2 failed");
|
||||||
|
|
||||||
/* We don't need any privileges in the launcher, drop them immediately. */
|
/* We don't need any privileges in the launcher, drop them immediately. */
|
||||||
drop_privs (FALSE);
|
drop_privs (FALSE, FALSE);
|
||||||
|
|
||||||
/* Optionally bind our lifecycle to that of the parent */
|
/* Optionally bind our lifecycle to that of the parent */
|
||||||
handle_die_with_parent ();
|
handle_die_with_parent ();
|
||||||
|
@ -2674,7 +2679,7 @@ main (int argc,
|
||||||
if (child == 0)
|
if (child == 0)
|
||||||
{
|
{
|
||||||
/* Unprivileged setup process */
|
/* Unprivileged setup process */
|
||||||
drop_privs (FALSE);
|
drop_privs (FALSE, TRUE);
|
||||||
close (privsep_sockets[0]);
|
close (privsep_sockets[0]);
|
||||||
setup_newroot (opt_unshare_pid, privsep_sockets[1]);
|
setup_newroot (opt_unshare_pid, privsep_sockets[1]);
|
||||||
exit (0);
|
exit (0);
|
||||||
|
@ -2769,7 +2774,7 @@ main (int argc,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All privileged ops are done now, so drop caps we don't need */
|
/* All privileged ops are done now, so drop caps we don't need */
|
||||||
drop_privs (!is_privileged);
|
drop_privs (!is_privileged, TRUE);
|
||||||
|
|
||||||
if (opt_block_fd != -1)
|
if (opt_block_fd != -1)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue