aboutsummaryrefslogtreecommitdiff
path: root/src/burn
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2024-03-20 23:51:53 -0700
committerRob Mensching <rob@firegiant.com>2024-03-22 11:57:27 -0700
commitfed3d69eb4da7fa2bafdd8f555ce5869c36925f7 (patch)
treecb9bd56e7a36f118da7ad44107018b86a30fbdae /src/burn
parente84b6768772c01e44dd55fb583cf78388ec7e48a (diff)
downloadwix-fed3d69eb4da7fa2bafdd8f555ce5869c36925f7.tar.gz
wix-fed3d69eb4da7fa2bafdd8f555ce5869c36925f7.tar.bz2
wix-fed3d69eb4da7fa2bafdd8f555ce5869c36925f7.zip
Protect elevated working folder from malicious data
When running elevated, Burn uses the Windows Temp folder as its working folder to prevent normal processes from tampering with the files. Windows Temp does allow non-elevated processes to write to the folder but they cannot see the files there. Unfortunately, contrary to our belief, non-elevated processes can read the files in Windows Temp by watching for directory changes. This allows a malicious process to lie in wait, watching the Windows Temp folder until a Burn process is launched elevated, then attack the working folder. Mitigate that attack by protecting the working folder to only elevated users. Managed custom actions also fall back to using the Windows Temp folder in some cases and thus can be exposed in a similar fashion as an elevated Burn process. Remove that possibility.
Diffstat (limited to 'src/burn')
-rw-r--r--src/burn/engine/ba.h1
-rw-r--r--src/burn/engine/bootstrapperapplication.cpp3
-rw-r--r--src/burn/engine/cache.cpp32
-rw-r--r--src/burn/engine/cache.h2
-rw-r--r--src/burn/engine/core.cpp6
5 files changed, 37 insertions, 7 deletions
diff --git a/src/burn/engine/ba.h b/src/burn/engine/ba.h
index c092fedf..3561805a 100644
--- a/src/burn/engine/ba.h
+++ b/src/burn/engine/ba.h
@@ -111,6 +111,7 @@ HRESULT BootstrapperApplicationInterpretExecuteResult(
111); 111);
112 112
113HRESULT BootstrapperApplicationEnsureWorkingFolder( 113HRESULT BootstrapperApplicationEnsureWorkingFolder(
114 __in BOOL fElevated,
114 __in BURN_CACHE* pCache, 115 __in BURN_CACHE* pCache,
115 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder 116 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder
116); 117);
diff --git a/src/burn/engine/bootstrapperapplication.cpp b/src/burn/engine/bootstrapperapplication.cpp
index 402f7015..947b3720 100644
--- a/src/burn/engine/bootstrapperapplication.cpp
+++ b/src/burn/engine/bootstrapperapplication.cpp
@@ -276,6 +276,7 @@ EXTERN_C HRESULT BootstrapperApplicationInterpretExecuteResult(
276} 276}
277 277
278EXTERN_C HRESULT BootstrapperApplicationEnsureWorkingFolder( 278EXTERN_C HRESULT BootstrapperApplicationEnsureWorkingFolder(
279 __in BOOL fElevated,
279 __in BURN_CACHE* pCache, 280 __in BURN_CACHE* pCache,
280 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder 281 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder
281 ) 282 )
@@ -283,7 +284,7 @@ EXTERN_C HRESULT BootstrapperApplicationEnsureWorkingFolder(
283 HRESULT hr = S_OK; 284 HRESULT hr = S_OK;
284 LPWSTR sczWorkingFolder = NULL; 285 LPWSTR sczWorkingFolder = NULL;
285 286
286 hr = CacheEnsureBaseWorkingFolder(pCache, &sczWorkingFolder); 287 hr = CacheEnsureBaseWorkingFolder(fElevated, pCache, &sczWorkingFolder);
287 ExitOnFailure(hr, "Failed to create working folder."); 288 ExitOnFailure(hr, "Failed to create working folder.");
288 289
289 hr = StrAllocFormatted(psczUserExperienceWorkingFolder, L"%ls%ls\\", sczWorkingFolder, L".ba"); 290 hr = StrAllocFormatted(psczUserExperienceWorkingFolder, L"%ls%ls\\", sczWorkingFolder, L".ba");
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp
index c0ac3ecd..358327a2 100644
--- a/src/burn/engine/cache.cpp
+++ b/src/burn/engine/cache.cpp
@@ -106,6 +106,7 @@ static HRESULT SecurePath(
106 __in LPCWSTR wzPath 106 __in LPCWSTR wzPath
107 ); 107 );
108static HRESULT CopyEngineToWorkingFolder( 108static HRESULT CopyEngineToWorkingFolder(
109 __in BOOL fElevated,
109 __in BURN_CACHE* pCache, 110 __in BURN_CACHE* pCache,
110 __in_z LPCWSTR wzSourcePath, 111 __in_z LPCWSTR wzSourcePath,
111 __in_z LPCWSTR wzWorkingFolderName, 112 __in_z LPCWSTR wzWorkingFolderName,
@@ -330,6 +331,7 @@ LExit:
330} 331}
331 332
332extern "C" HRESULT CacheEnsureBaseWorkingFolder( 333extern "C" HRESULT CacheEnsureBaseWorkingFolder(
334 __in BOOL fElevated,
333 __in BURN_CACHE* pCache, 335 __in BURN_CACHE* pCache,
334 __deref_out_z_opt LPWSTR* psczBaseWorkingFolder 336 __deref_out_z_opt LPWSTR* psczBaseWorkingFolder
335 ) 337 )
@@ -338,15 +340,32 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder(
338 340
339 HRESULT hr = S_OK; 341 HRESULT hr = S_OK;
340 LPWSTR sczPotential = NULL; 342 LPWSTR sczPotential = NULL;
343 PSECURITY_DESCRIPTOR psd = NULL;
344 LPSECURITY_ATTRIBUTES pWorkingFolderAcl = NULL;
341 345
342 if (!pCache->fInitializedBaseWorkingFolder) 346 if (!pCache->fInitializedBaseWorkingFolder)
343 { 347 {
348 // If elevated, allocate the pWorkingFolderAcl to protect the working folder to only SYSTEM and Admins.
349 if (fElevated)
350 {
351 LPCWSTR wzSddl = L"D:PAI(A;;FA;;;BA)(A;OICIIO;GA;;;BA)(A;;FA;;;SY)(A;OICIIO;GA;;;SY)";
352 if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSddl, SDDL_REVISION_1, &psd, NULL))
353 {
354 ExitWithLastError(hr, "Failed to create the security descriptor for the working folder.");
355 }
356
357 pWorkingFolderAcl = reinterpret_cast<LPSECURITY_ATTRIBUTES>(MemAlloc(sizeof(SECURITY_ATTRIBUTES), TRUE));
358 pWorkingFolderAcl->nLength = sizeof(SECURITY_ATTRIBUTES);
359 pWorkingFolderAcl->lpSecurityDescriptor = psd;
360 pWorkingFolderAcl->bInheritHandle = FALSE;
361 }
362
344 for (DWORD i = 0; i < pCache->cPotentialBaseWorkingFolders; ++i) 363 for (DWORD i = 0; i < pCache->cPotentialBaseWorkingFolders; ++i)
345 { 364 {
346 hr = PathConcatRelativeToFullyQualifiedBase(pCache->rgsczPotentialBaseWorkingFolders[i], pCache->wzGuid, &sczPotential); 365 hr = PathConcatRelativeToFullyQualifiedBase(pCache->rgsczPotentialBaseWorkingFolders[i], pCache->wzGuid, &sczPotential);
347 if (SUCCEEDED(hr)) 366 if (SUCCEEDED(hr))
348 { 367 {
349 hr = DirEnsureExists(sczPotential, NULL); 368 hr = DirEnsureExists(sczPotential, pWorkingFolderAcl);
350 if (SUCCEEDED(hr)) 369 if (SUCCEEDED(hr))
351 { 370 {
352 pCache->sczBaseWorkingFolder = sczPotential; 371 pCache->sczBaseWorkingFolder = sczPotential;
@@ -373,6 +392,11 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder(
373 } 392 }
374 393
375LExit: 394LExit:
395 ReleaseMem(pWorkingFolderAcl);
396 if (psd)
397 {
398 ::LocalFree(psd);
399 }
376 ReleaseStr(sczPotential); 400 ReleaseStr(sczPotential);
377 401
378 return hr; 402 return hr;
@@ -888,6 +912,7 @@ extern "C" HRESULT CachePreparePackage(
888} 912}
889 913
890extern "C" HRESULT CacheBundleToWorkingDirectory( 914extern "C" HRESULT CacheBundleToWorkingDirectory(
915 __in BOOL fElevated,
891 __in BURN_CACHE* pCache, 916 __in BURN_CACHE* pCache,
892 __in_z LPCWSTR wzExecutableName, 917 __in_z LPCWSTR wzExecutableName,
893 __in BURN_SECTION* pSection, 918 __in BURN_SECTION* pSection,
@@ -912,7 +937,7 @@ extern "C" HRESULT CacheBundleToWorkingDirectory(
912 } 937 }
913 else // otherwise, carry on putting the bundle in the working folder. 938 else // otherwise, carry on putting the bundle in the working folder.
914 { 939 {
915 hr = CopyEngineToWorkingFolder(pCache, sczSourcePath, BUNDLE_WORKING_FOLDER_NAME, wzExecutableName, pSection, psczEngineWorkingPath); 940 hr = CopyEngineToWorkingFolder(fElevated, pCache, sczSourcePath, BUNDLE_WORKING_FOLDER_NAME, wzExecutableName, pSection, psczEngineWorkingPath);
916 ExitOnFailure(hr, "Failed to copy engine to working folder."); 941 ExitOnFailure(hr, "Failed to copy engine to working folder.");
917 } 942 }
918 943
@@ -2063,6 +2088,7 @@ LExit:
2063 2088
2064 2089
2065static HRESULT CopyEngineToWorkingFolder( 2090static HRESULT CopyEngineToWorkingFolder(
2091 __in BOOL fElevated,
2066 __in BURN_CACHE* pCache, 2092 __in BURN_CACHE* pCache,
2067 __in_z LPCWSTR wzSourcePath, 2093 __in_z LPCWSTR wzSourcePath,
2068 __in_z LPCWSTR wzWorkingFolderName, 2094 __in_z LPCWSTR wzWorkingFolderName,
@@ -2079,7 +2105,7 @@ static HRESULT CopyEngineToWorkingFolder(
2079 LPWSTR sczPayloadSourcePath = NULL; 2105 LPWSTR sczPayloadSourcePath = NULL;
2080 LPWSTR sczPayloadTargetPath = NULL; 2106 LPWSTR sczPayloadTargetPath = NULL;
2081 2107
2082 hr = CacheEnsureBaseWorkingFolder(pCache, &sczWorkingFolder); 2108 hr = CacheEnsureBaseWorkingFolder(fElevated, pCache, &sczWorkingFolder);
2083 ExitOnFailure(hr, "Failed to create working path to copy engine."); 2109 ExitOnFailure(hr, "Failed to create working path to copy engine.");
2084 2110
2085 hr = PathConcatRelativeToFullyQualifiedBase(sczWorkingFolder, wzWorkingFolderName, &sczTargetDirectory); 2111 hr = PathConcatRelativeToFullyQualifiedBase(sczWorkingFolder, wzWorkingFolderName, &sczTargetDirectory);
diff --git a/src/burn/engine/cache.h b/src/burn/engine/cache.h
index 3f0ba749..7c4dfaa1 100644
--- a/src/burn/engine/cache.h
+++ b/src/burn/engine/cache.h
@@ -96,6 +96,7 @@ HRESULT CacheEnsureAcquisitionFolder(
96 __in BURN_CACHE* pCache 96 __in BURN_CACHE* pCache
97 ); 97 );
98HRESULT CacheEnsureBaseWorkingFolder( 98HRESULT CacheEnsureBaseWorkingFolder(
99 __in BOOL fElevated,
99 __in BURN_CACHE* pCache, 100 __in BURN_CACHE* pCache,
100 __deref_out_z_opt LPWSTR* psczBaseWorkingFolder 101 __deref_out_z_opt LPWSTR* psczBaseWorkingFolder
101 ); 102 );
@@ -171,6 +172,7 @@ HRESULT CachePreparePackage(
171 __in BURN_PACKAGE* pPackage 172 __in BURN_PACKAGE* pPackage
172 ); 173 );
173HRESULT CacheBundleToWorkingDirectory( 174HRESULT CacheBundleToWorkingDirectory(
175 __in BOOL fElvated,
174 __in BURN_CACHE* pCache, 176 __in BURN_CACHE* pCache,
175 __in_z LPCWSTR wzExecutableName, 177 __in_z LPCWSTR wzExecutableName,
176 __in BURN_SECTION* pSection, 178 __in BURN_SECTION* pSection,
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index ae74fdfd..a85e6f18 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -165,7 +165,7 @@ extern "C" HRESULT CoreInitialize(
165 if (BURN_MODE_NORMAL == pEngineState->internalCommand.mode || BURN_MODE_EMBEDDED == pEngineState->internalCommand.mode) 165 if (BURN_MODE_NORMAL == pEngineState->internalCommand.mode || BURN_MODE_EMBEDDED == pEngineState->internalCommand.mode)
166 { 166 {
167 // Extract all UX payloads to working folder. 167 // Extract all UX payloads to working folder.
168 hr = BootstrapperApplicationEnsureWorkingFolder(&pEngineState->cache, &pEngineState->userExperience.sczTempDirectory); 168 hr = BootstrapperApplicationEnsureWorkingFolder(pEngineState->internalCommand.fInitiallyElevated, &pEngineState->cache, &pEngineState->userExperience.sczTempDirectory);
169 ExitOnFailure(hr, "Failed to get unique temporary folder for bootstrapper application."); 169 ExitOnFailure(hr, "Failed to get unique temporary folder for bootstrapper application.");
170 170
171 hr = PayloadExtractUXContainer(&pEngineState->userExperience.payloads, &containerContext, pEngineState->userExperience.sczTempDirectory); 171 hr = PayloadExtractUXContainer(&pEngineState->userExperience.payloads, &containerContext, pEngineState->userExperience.sczTempDirectory);
@@ -588,7 +588,7 @@ extern "C" HRESULT CoreElevate(
588 // If the elevated companion pipe isn't created yet, let's make that happen. 588 // If the elevated companion pipe isn't created yet, let's make that happen.
589 if (!pEngineState->sczBundleEngineWorkingPath) 589 if (!pEngineState->sczBundleEngineWorkingPath)
590 { 590 {
591 hr = CacheBundleToWorkingDirectory(&pEngineState->cache, pEngineState->registration.sczExecutableName, &pEngineState->section, &pEngineState->sczBundleEngineWorkingPath); 591 hr = CacheBundleToWorkingDirectory(pEngineState->internalCommand.fInitiallyElevated, &pEngineState->cache, pEngineState->registration.sczExecutableName, &pEngineState->section, &pEngineState->sczBundleEngineWorkingPath);
592 ExitOnFailure(hr, "Failed to cache engine to working directory."); 592 ExitOnFailure(hr, "Failed to cache engine to working directory.");
593 } 593 }
594 594
@@ -697,7 +697,7 @@ extern "C" HRESULT CoreApply(
697 // Ensure the engine is cached to the working path. 697 // Ensure the engine is cached to the working path.
698 if (!pEngineState->sczBundleEngineWorkingPath) 698 if (!pEngineState->sczBundleEngineWorkingPath)
699 { 699 {
700 hr = CacheBundleToWorkingDirectory(&pEngineState->cache, pEngineState->registration.sczExecutableName, &pEngineState->section, &pEngineState->sczBundleEngineWorkingPath); 700 hr = CacheBundleToWorkingDirectory(pEngineState->internalCommand.fInitiallyElevated, &pEngineState->cache, pEngineState->registration.sczExecutableName, &pEngineState->section, &pEngineState->sczBundleEngineWorkingPath);
701 ExitOnFailure(hr, "Failed to cache engine to working directory."); 701 ExitOnFailure(hr, "Failed to cache engine to working directory.");
702 } 702 }
703 703