Skip to content

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

Open
damianrickard wants to merge 1 commit into
veracrypt:masterfrom
damianrickard:fix/macos-system-binary-search-order
Open

macOS: search system directories before /usr/local/bin for binaries#1790
damianrickard wants to merge 1 commit into
veracrypt:masterfrom
damianrickard:fix/macos-system-binary-search-order

Conversation

@damianrickard

@damianrickard damianrickard commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Summary

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

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.

Fix

Reorder the macOS search list so system locations always win:

-const char* defaultDirs[] = {"/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"};
+const char* defaultDirs[] = {"/usr/bin", "/bin", "/usr/sbin", "/sbin", "/usr/local/bin"};

/usr/local/bin is kept only as a last-resort fallback and can no longer shadow the system tools.

Affected resolver users

The binaries actually resolved through FindSystemBinary() on macOS are sudo, true, fsck, the terminal helper used for filesystem checks (and its dependencies), and non-APFS formatters — all of which live in system directories.

diskutil, hdiutil, and newfs_apfs are invoked via absolute paths and were never affected by the search order; they're mentioned only as context for what VeraCrypt runs on macOS.

Notes

@idrassi

idrassi commented Jun 21, 2026

Copy link
Copy Markdown
Member

Thank you for reporting this, the homebrew issue warrant such change.

But I have one reservation: the added comment says the other platforms already keep /usr/local last, but the Linux #else branch currently searches /usr/local/sbin and /usr/local/bin first.

Could you please adjust that comment and commit wording to make the statement macOS specific?
Also, some examples in the PR description such as diskutil, hdiutil, and APFS newfs_apfs are currently called via absolute paths, so the concrete affected resolver users are mainly sudo, true, umount, fsck terminal helpers, and non-APFS formatters.

With this wording fixed, I can merge it.

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.)
@damianrickard damianrickard force-pushed the fix/macos-system-binary-search-order branch from c0a3c38 to 31f9e69 Compare June 21, 2026 15:05
@damianrickard

Copy link
Copy Markdown
Contributor Author

Thanks, both points are fair.

You're right that the Linux branch searches /usr/local/sbin and /usr/local/bin first, so the "other platforms keep /usr/local last" claim was inaccurate. I've reworded the code comment and the commit message to be macOS-specific and dropped that claim.

I've also corrected the affected-binary list: diskutil, hdiutil, and newfs_apfs are invoked via absolute paths and were never affected. The binaries actually resolved through FindSystemBinary() on macOS are sudo, true, fsck, the terminal helper used for filesystem checks (and its dependencies), and non-APFS formatters. The commit message and PR description now reflect this.

Force-pushed the single-commit update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants