Symbolic link attack in SELinux-enabled sudoedit

Release Date:

January 11, 2021

Summary:

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 affected:

Sudo versions 1.8.11 to 1.9.4p2 inclusive are affected when Sudo is built with SELinux support.

CVE ID:

This vulnerability has been assigned CVE-2021-23240 in the Common Vulnerabilities and Exposures database.

Details:

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.

Impact:

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.

Workaround:

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.

Fix:

The bug is fixed in sudo 1.9.5.

Credit:

Matthias Gerstner of the SUSE Linux security team found and analyzed the bug.