Symbolic link attack in SELinux-enabled sudoedit
On systems where SELinux is enabled, sudo’s RBAC support allows a
command to be run with a user-specified role and/or type. In order
to transition to the target SELinux security context, sudo
runs the command through the sesh
helper program. When
sudo is invoked as sudoedit
, sesh
is used to first
create the editor temporary files with the proper security context
and then, once the editor has run, to copy the edited temporary
files to their original locations.
In order for the user to have permission to edit them,
sudoedit
must change the owner of the temporary files
created by sesh
to the invoking user. After editing,
the owner is changed back to the target user to allow sesh
to copy them to the original location as the target user.
A race condition exists whereby the invoking user could replace the
temporary file with a symbolic link after the file has been edited
but before sudoedit
changes its owner back to the target
user. Winning the race allows the user to set the owner of an
arbitrary file to the target user. However, if the protected
symlinks feature is supported by the kernel and
/proc/sys/fs/protected_symlinks
is set to 1 (the default
on many systems), the attack will fail. The attack will also fail
if SELinux is in enforcing mode and the invoking user is not in an
unconfined domain.
Sudo versions 1.8.11 to 1.9.4p2 inclusive are affected when Sudo is built with SELinux support.
Vendor-provided sudo packages prior to version 1.8.11 may also be affected if they include changes backported from newer sudo releases. For example, the RHEL 6 sudo-1.8.6p3 sudo package is also vulnerable. Check with your vendor for patches or update to the latest version of sudo from sudo.ws.
This vulnerability has been assigned CVE-2021-23240 in the Common Vulnerabilities and Exposures database.
Exploiting the bug requires that Sudo be built with SELinux support,
that /proc/sys/fs/protected_symlinks
is set to 0 (disabled)
and that either SELinux is in permissive (not enforcing) mode or
the invoking user is in an unconfined domain.
In order for the user to have permission to edit them,
sudoedit
must change the owner of the temporary files
created by sesh
to the invoking user. After editing,
the owner is changed back to the target user to allow sesh
to copy them to the original location as the target user.
Because the temporary files are created by sesh
but
the owner is changed by sudoedit
, there is a race condition
between when the temporary files are created (or edited) and when the owner
on the file is changed. There are actually two race
conditions, one for each chown(2)
call. Below we will
describe exploiting the race between editing the file and setting
its owner to the target user, since that is one the invoking user
can easily win.
One simple way to exploit the bug without needing to race
sudoedit
at all is to set the EDITOR
environment
variable to a script that replaces the temporary file with a symbolic
link. For example, suppose that you wish to change the owner of
the file /home/testuser/targetfile
to root and you are
allowed to edit the file /etc/somefile
with sudoedit
(the actual file to edit is arbitrary). For the example below, the
invoking user, testuser, is not an SELinux user and thus
maps to unconfined_u. However, the exploit does not require that
the user be in an unconfined domain so long as SELinux is in
permissive mode.
$ cat > myeditor <<'EOF'
#!/bin/sh
echo replacing $1
rm $1
ln -s /home/testuser/targetfile $1
exit 0
EOF
$ chmod 755 myeditor
$ ls -l /home/testuser/targetfile
-rw-r--r--. 1 testuser testuser 0 Jan 6 13:00 /home/testuser/targetfile
$ EDITOR=`pwd`/myeditor sudoedit -r unconfined_r -t unconfined_t /etc/somefile
replacing /var/tmp/somefile.XXoNPaYb
$ ls -l /home/testuser/targetfile
-rw-r--r--. 1 root root 0 Jan 6 13:10 /home/testuser/targetfile
Exploiting the other race condition can only be done as the target user, not the invoking user, and it is limited to changing the owner of files to the invoking user.
This is a textbook example of why the protected_symlinks
feature is useful. In this particular case, it is not possible to
use mkstemp(3)
to keep the temporary file open.
If sudo is built with SELinux support,
/proc/sys/fs/protected_symlinks
is not enabled, and either
SELinux is in permissive mode or the invoking user is in an unconfined
domain, it is possible for a user with sudoedit
permissions
to change the owner of an arbitrary file to the user ID of any user
they are allowed to run sudoedit
as.
Setting /proc/sys/fs/protected_symlinks
to 1 is sufficient
to prevent exploitation of the bug. Removing the sesh binary
(usually /usr/libexec/sudo/sesh
or /usr/lib/sudo/sesh
)
will also prevent exploitation if sudo’s SELinux RBAC support is
not needed.
The bug is fixed in sudo 1.9.5.
Matthias Gerstner of the SUSE Linux security team found and analyzed the bug.