macOS: search system directories before /usr/local/bin for binaries (#1790)

On macOS, Process::FindSystemBinary() searched /usr/local/bin first, so a
user-writable /usr/local/bin (the default on Homebrew installs) could
shadow system tools.

This resolver is also used to locate privileged binaries during privilege
elevation: CoreService.cpp resolves "sudo" (and "true") through it both
when probing for an active sudo session and when launching the elevated
helper, and the admin password is written to that sudo process's stdin.
On a typical Homebrew install /usr/local is owned by the (non-root) user,
so a planted /usr/local/bin/sudo would be selected ahead of /usr/bin/sudo
and could capture the admin password, leading to privilege escalation.

Reorder the macOS list to {/usr/bin, /bin, /usr/sbin, /sbin,
/usr/local/bin} so system locations always win. The binaries actually
resolved through this function on macOS (sudo, true, fsck, the terminal
helper used for filesystem checks and its dependencies, and non-APFS
formatters) live in system directories, so /usr/local/bin is kept only as
a last-resort fallback and can no longer shadow them. (diskutil, hdiutil
and newfs_apfs are invoked via absolute paths and were never affected.)

Co-authored-by: Damian Rickard <damian@rickard.us>
This commit is contained in:
damianrickard
2026-06-21 20:05:29 -04:00
committed by GitHub
parent e6eb1d9f57
commit 3e231010dc
+8 -2
View File
@@ -44,9 +44,15 @@ namespace VeraCrypt
return "";
}
// Default system directories to search for executables
// Default system directories to search for executables.
// On macOS, system locations are searched before /usr/local/bin so that
// a user-writable /usr/local/bin (the default on Homebrew installs)
// cannot shadow system tools. This matters because this resolver is
// also used for privileged binaries such as sudo during elevation
// (see CoreService.cpp); a planted /usr/local/bin/sudo would otherwise
// receive the admin password.
#ifdef TC_MACOSX
const char* defaultDirs[] = {"/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"};
const char* defaultDirs[] = {"/usr/bin", "/bin", "/usr/sbin", "/sbin", "/usr/local/bin"};
#elif TC_FREEBSD
const char* defaultDirs[] = {"/sbin", "/bin", "/usr/sbin", "/usr/bin", "/usr/local/sbin", "/usr/local/bin"};
#elif TC_OPENBSD