macOS: native authentication via an SMJobBless privileged helper#1792
Open
damianrickard wants to merge 1 commit into
Open
macOS: native authentication via an SMJobBless privileged helper#1792damianrickard wants to merge 1 commit into
damianrickard wants to merge 1 commit into
Conversation
On macOS, VeraCrypt elevated privileges through the common Unix path: it prompted for the administrator password in its own dialog and started the core service via "sudo". This replaces that with a code-signed launchd privileged helper installed via SMJobBless, so the OS shows its standard authentication dialog and VeraCrypt never handles the administrator password. Closes veracrypt#1437. Linux/FreeBSD are unchanged. Design (reuses the existing root entry point): - A thin, self-contained helper (PrivilegedHelper/Helper.cpp) exposes one privileged Mach service. On request it validates the connecting client's code signature (audit token -> SecCode -> designated requirement) and the client-supplied app binary, then socketpair()/fork()/execs "<app> --core-service" as root and returns one socket end over XPC. - The returned descriptor is wrapped into the existing Service streams and fed the same {0,0x11,0x22} sync code, so ProcessElevatedRequests() / ProcessRequests() and all CoreServiceRequest serialization and validation are unchanged. - The SMJobBless install and XPC connection run in the main application process (CoreService::SendRequest), not in the unprivileged core service: the latter is a fork()ed child that never calls exec(), where the Authorization / XPC / ServiceManagement frameworks cannot run. Security: - SMJobBless install gate matches the app's SMPrivilegedExecutables against the helper signature and the helper's SMAuthorizedClients against the app. - Native auth via AuthorizationCopyRights(kSMRightBlessPrivilegedHelper). - Per-connection client code-signature check inside the helper. - The helper only execs a binary that is a root-owned regular file inside a non-user-writable ".app/Contents/MacOS" tree (every path component is verified root-owned and not group/other-writable, admin-group write allowed only outside the bundle), with the opened descriptor pinned and re-checked immediately before exec. macOS has no fexecve() and rejects exec via /dev/fd, so this trusted-location requirement is what closes the validate/exec race rather than executing the descriptor directly. - The elevated SetFileOwner and the APFS formatter now share one device-node validator (lstat-based; rejects symlinks; requires a block/char device). Build / packaging: - Link the app with Security/ServiceManagement/CoreFoundation; the Blocks/XPC client glue is isolated in PrivilegedHelperClient.mm. - Main.make builds the helper, embeds it at Contents/Library/LaunchServices, and signs it inside-out before the app. Signing identity and Team ID are build-overridable (defaults pin the IDRIX project identity); the Team ID is templated into the code-signing requirement strings and the generated plists are regenerated on every build so a Team ID change always takes effect. - notarize.sh signs/verifies the nested helper; a macOS uninstaller removes the helper and its LaunchDaemon.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1437.
On macOS, VeraCrypt elevated privileges through the common Unix path: it prompted for the administrator password in its own dialog and started the core service via
sudo— hence the single password field, with VeraCrypt handling the admin password directly.This PR replaces that on macOS with a code-signed launchd privileged helper installed via
SMJobBless. The OS now shows its standard authentication dialog, and VeraCrypt never handles the administrator password. Linux/FreeBSD are unchanged.Design (reuses the existing root entry point)
src/PrivilegedHelper/Helper.cpp) exposes one privileged Mach service. On request it:SecCode→ designated requirement), andsocketpair()/fork()/execs"<app> --core-service"as root and returns one socket end over XPC.ServiceInputStream/ServiceOutputStreamand fed the same{0,0x11,0x22}sync code, soProcessElevatedRequests()/ProcessRequests()and allCoreServiceRequestserialization and validation are unchanged.SMJobBlessinstall and XPC connection run in the main application process (CoreService::SendRequest), not in the unprivileged core service. The latter is afork()ed child that neverexec()s, where the Authorization/XPC/ServiceManagement frameworks cannot run.Security model
SMJobBlessverifies the app'sSMPrivilegedExecutablesrequirement against the helper's signature, and the helper'sSMAuthorizedClientsrequirement against the app's signature (reciprocal, code-signature-pinned).AuthorizationCopyRights(kSMRightBlessPrivilegedHelper)..app/Contents/MacOStree — every path component is verified root-owned and not group/other-writable (admin-group write is allowed only outside the bundle, e.g./Applications), and the opened descriptor's inode is pinned and re-checked immediately beforeexec. Because macOS has nofexecve()and rejects exec via/dev/fd, this trusted-location requirement is what closes the validate-vs-exec race rather than executing the descriptor directly.SetFileOwnerand the APFS formatter now share one device-node validator (lstat-based; rejects symlinks; requires an actual block/character device) instead of a lexical path check.Build / packaging
Security/ServiceManagement/CoreFoundation; the Blocks/XPC client glue is isolated inPrivilegedHelperClient.mm(Objective-C++).Main.makebuilds the helper, embeds it atContents/Library/LaunchServices/, and signs it inside-out before the app.VC_OSX_SIGN_IDENTITY,VC_OSX_TEAM_ID); committed defaults pin the project (IDRIX) identity, the Team ID is templated into the code-signing requirement strings, and the generated helper plists are regenerated on every build so a Team-ID change always takes effect.notarize.shsigns/verifies the nested helper; a macOS uninstaller (veracrypt-uninstall.sh) removes the helper and its LaunchDaemon.Notes for review
.pkgto/Applications, which is root-owned) to elevate — running it directly from a user-writable location or a mounted DMG will not. This is intentional (don't grant root to a user-writable binary), but it differs from the oldsudopath, which elevated from anywhere.sudopath's responsible process is alsoVeraCrypt.app). This is not a new requirement, and since the signed release keeps theorg.idrix.VeraCryptidentity, an existing user's FDA grant carries over to the helper-spawned core service.SMJobBless(deprecated in 13 but fully functional). If you'd prefer to require macOS 13+ and use the modernSMAppServiceinstead, that's a contained follow-up — I didn't want to bundle a minimum-OS bump into this PR.Testing
Built and verified locally on Apple Silicon (macOS, FUSE-T):
SMJobBlessinstall shows the native auth dialog; reciprocal signing requirements verified withcodesign -Rand a successful install./Library/PrivilegedHelperTools/, LaunchDaemon loads, per-connection client validation works./Applicationsinstall.