Security: Fix Local privilege escalation via DLL hijack#46145
Security: Fix Local privilege escalation via DLL hijack#46145
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens per-machine custom install locations to mitigate a local privilege escalation vector where permissive inherited ACLs allow non-admin users to plant DLLs in a directory that is added to PATH.
Changes:
- Adds a new deferred, non-impersonated MSI custom action to secure the install folder ACL for per-machine installs outside Program Files.
- Implements ACL templating based on Program Files and reapplies hardened ACLs across the existing install tree during upgrade/repair.
- Wires the new custom action into the WiX installer sequencing for per-machine scenarios.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| installer/PowerToysSetupVNext/Product.wxs | Schedules the new SecureInstallFolderAcl custom action and its property setup for per-machine installs. |
| installer/PowerToysSetupCustomActionsVNext/pch.h | Adds ACL API header include needed for the new security logic. |
| installer/PowerToysSetupCustomActionsVNext/CustomAction.def | Exports the new custom action entrypoint for MSI to invoke. |
| installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp | Implements the install-folder ACL hardening + recursive re-ACL logic. |
| installFolderPath = std::filesystem::path(installationFolder); | ||
| normalizedInstallFolder = NormalizePathForComparison(installFolderPath); | ||
|
|
||
| programFilesPath = GetKnownFolderPath(FOLDERID_ProgramFiles); | ||
| if (!programFilesPath) | ||
| { | ||
| hr = E_FAIL; | ||
| ExitOnFailure(hr, "Failed to resolve Program Files folder."); | ||
| } | ||
|
|
||
| isUnderProgramFiles = IsSameOrUnderPath(normalizedInstallFolder, NormalizePathForComparison(*programFilesPath)); | ||
| if (const auto programFilesX86Path = GetKnownFolderPath(FOLDERID_ProgramFilesX86)) | ||
| { | ||
| isUnderProgramFiles = isUnderProgramFiles || IsSameOrUnderPath(normalizedInstallFolder, NormalizePathForComparison(*programFilesX86Path)); | ||
| } | ||
|
|
||
| if (isUnderProgramFiles) | ||
| { | ||
| WcaLog(LOGMSG_STANDARD, "SecureInstallFolderAclCA: Install folder already resides under Program Files. No ACL changes required."); | ||
| goto LExit; | ||
| } | ||
|
|
||
| { | ||
| std::error_code errorCode; | ||
| std::filesystem::create_directories(installFolderPath, errorCode); | ||
| if (errorCode) | ||
| { | ||
| hr = HRESULT_FROM_WIN32(errorCode.value()); | ||
| ExitOnFailure(hr, "Failed to create install folder before ACL hardening."); | ||
| } | ||
| } | ||
|
|
||
| hr = GetPathDacl(*programFilesPath, &programFilesDacl, &programFilesSecurityDescriptor); | ||
| ExitOnFailure(hr, "Failed to read Program Files DACL."); | ||
|
|
||
| hr = SetProtectedPathDacl(installFolderPath.native(), programFilesDacl); | ||
| ExitOnFailure(hr, "Failed to apply Program Files DACL to install folder."); | ||
|
|
There was a problem hiding this comment.
path parent = normalized.parent_path();
if (parent.empty() || parent == normalized.root_path())
{
return false;
}
I'm not sure whether this needs to be called out, so this is a great review, and will enforce something other than the suggest
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…nto dev/vanzue/fix-sec
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
DHowett
left a comment
There was a problem hiding this comment.
why does this require hundreds of lines of custom action code? does WiX not support ACLs?
Summary of the Pull Request
Attack vector:
The fix is to:
Hardening the PowerToys install leaf directory for per-machine custom installs using the effective DACL model of Program Files, with inheritance protection enabled to prevent permissive ACLs from parent directories such as C:\ from propagating.
During upgrade or repair, we will also reapply the hardened ACLs to existing install contents so that previously insecure custom installs are corrected, not just newly installed instances.
PR Checklist
Detailed Description of the Pull Request / Additional comments
Validation Steps Performed