An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support "saved UID" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use "enable -f" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.
Reference and upstream commit:
Created bash tracking bugs for this issue:
Affects: fedora-all [bug 1778310]
The setuid() function has different behaviors depending weather it is running as root or not. In the former case (running as root) it sets all three UIDs (effective UID, real UID and saved UID), whereas in the latter case (running as non-root) it only sets the effective UID.
It is worth noting that Bash is affected by this flaw only when running as non-root user; this lowers the exposure of the vulnerability.
Also note that in order to exploit this flaw, the bash process has to call setuid() without exec()-ing any other process as in this case the saved UID would be lost. Hence the need of the bash builtin feature mentioned above.
If the shell is started with the effective UID not equal to the real UID, and the -p option is not supplied, function disable_priv_mode() attempts to drop privileges by calling setuid(). However, as discussed in Comment 2, setuid() may fail to set the saved UID.
Upstream patch simply replaces this call with setresuid(), thus making sure the saved UID is also set appropriately: