aboutsummaryrefslogtreecommitdiff
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 14:25:14 -0700
commit75a8c75d4e02ea219008dc5af7d03869291d61f7 (patch)
treec51a05a3cb878de83a2043e24a4641bddd181495
parent2e5960b575881567a8807e6b8b9c513138b19742 (diff)
downloadwix-75a8c75d4e02ea219008dc5af7d03869291d61f7.tar.gz
wix-75a8c75d4e02ea219008dc5af7d03869291d61f7.tar.bz2
wix-75a8c75d4e02ea219008dc5af7d03869291d61f7.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.
-rw-r--r--src/burn/engine/cache.cpp35
-rw-r--r--src/burn/engine/cache.h3
-rw-r--r--src/burn/engine/core.cpp10
-rw-r--r--src/burn/engine/engine.cpp2
-rw-r--r--src/burn/engine/userexperience.cpp3
-rw-r--r--src/burn/engine/userexperience.h1
-rw-r--r--src/dtf/SfxCA/SfxUtil.cpp32
7 files changed, 49 insertions, 37 deletions
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp
index 251cd24b..119200ec 100644
--- a/src/burn/engine/cache.cpp
+++ b/src/burn/engine/cache.cpp
@@ -107,6 +107,7 @@ static HRESULT SecurePath(
107 __in LPCWSTR wzPath 107 __in LPCWSTR wzPath
108 ); 108 );
109static HRESULT CopyEngineToWorkingFolder( 109static HRESULT CopyEngineToWorkingFolder(
110 __in BOOL fElevated,
110 __in BURN_CACHE* pCache, 111 __in BURN_CACHE* pCache,
111 __in_z LPCWSTR wzSourcePath, 112 __in_z LPCWSTR wzSourcePath,
112 __in_z LPCWSTR wzWorkingFolderName, 113 __in_z LPCWSTR wzWorkingFolderName,
@@ -342,6 +343,7 @@ LExit:
342} 343}
343 344
344extern "C" HRESULT CacheEnsureBaseWorkingFolder( 345extern "C" HRESULT CacheEnsureBaseWorkingFolder(
346 __in BOOL fElevated,
345 __in BURN_CACHE* pCache, 347 __in BURN_CACHE* pCache,
346 __deref_out_z_opt LPWSTR* psczBaseWorkingFolder 348 __deref_out_z_opt LPWSTR* psczBaseWorkingFolder
347 ) 349 )
@@ -350,15 +352,32 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder(
350 352
351 HRESULT hr = S_OK; 353 HRESULT hr = S_OK;
352 LPWSTR sczPotential = NULL; 354 LPWSTR sczPotential = NULL;
355 PSECURITY_DESCRIPTOR psd = NULL;
356 LPSECURITY_ATTRIBUTES pWorkingFolderAcl = NULL;
353 357
354 if (!pCache->fInitializedBaseWorkingFolder) 358 if (!pCache->fInitializedBaseWorkingFolder)
355 { 359 {
360 // If elevated, allocate the pWorkingFolderAcl to protect the working folder to only SYSTEM and Admins.
361 if (fElevated)
362 {
363 LPCWSTR wzSddl = L"D:PAI(A;;FA;;;BA)(A;OICIIO;GA;;;BA)(A;;FA;;;SY)(A;OICIIO;GA;;;SY)";
364 if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSddl, SDDL_REVISION_1, &psd, NULL))
365 {
366 ExitWithLastError(hr, "Failed to create the security descriptor for the working folder.");
367 }
368
369 pWorkingFolderAcl = reinterpret_cast<LPSECURITY_ATTRIBUTES>(MemAlloc(sizeof(SECURITY_ATTRIBUTES), TRUE));
370 pWorkingFolderAcl->nLength = sizeof(SECURITY_ATTRIBUTES);
371 pWorkingFolderAcl->lpSecurityDescriptor = psd;
372 pWorkingFolderAcl->bInheritHandle = FALSE;
373 }
374
356 for (DWORD i = 0; i < pCache->cPotentialBaseWorkingFolders; ++i) 375 for (DWORD i = 0; i < pCache->cPotentialBaseWorkingFolders; ++i)
357 { 376 {
358 hr = PathConcatRelativeToFullyQualifiedBase(pCache->rgsczPotentialBaseWorkingFolders[i], pCache->wzGuid, &sczPotential); 377 hr = PathConcatRelativeToFullyQualifiedBase(pCache->rgsczPotentialBaseWorkingFolders[i], pCache->wzGuid, &sczPotential);
359 if (SUCCEEDED(hr)) 378 if (SUCCEEDED(hr))
360 { 379 {
361 hr = DirEnsureExists(sczPotential, NULL); 380 hr = DirEnsureExists(sczPotential, pWorkingFolderAcl);
362 if (SUCCEEDED(hr)) 381 if (SUCCEEDED(hr))
363 { 382 {
364 pCache->sczBaseWorkingFolder = sczPotential; 383 pCache->sczBaseWorkingFolder = sczPotential;
@@ -385,6 +404,11 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder(
385 } 404 }
386 405
387LExit: 406LExit:
407 ReleaseMem(pWorkingFolderAcl);
408 if (psd)
409 {
410 ::LocalFree(psd);
411 }
388 ReleaseStr(sczPotential); 412 ReleaseStr(sczPotential);
389 413
390 return hr; 414 return hr;
@@ -900,6 +924,7 @@ extern "C" HRESULT CachePreparePackage(
900} 924}
901 925
902extern "C" HRESULT CacheBundleToCleanRoom( 926extern "C" HRESULT CacheBundleToCleanRoom(
927 __in BOOL fElevated,
903 __in BURN_CACHE* pCache, 928 __in BURN_CACHE* pCache,
904 __in BURN_SECTION* pSection, 929 __in BURN_SECTION* pSection,
905 __deref_out_z_opt LPWSTR* psczCleanRoomBundlePath 930 __deref_out_z_opt LPWSTR* psczCleanRoomBundlePath
@@ -914,7 +939,7 @@ extern "C" HRESULT CacheBundleToCleanRoom(
914 939
915 wzExecutableName = PathFile(sczSourcePath); 940 wzExecutableName = PathFile(sczSourcePath);
916 941
917 hr = CopyEngineToWorkingFolder(pCache, sczSourcePath, BUNDLE_CLEAN_ROOM_WORKING_FOLDER_NAME, wzExecutableName, pSection, psczCleanRoomBundlePath); 942 hr = CopyEngineToWorkingFolder(fElevated, pCache, sczSourcePath, BUNDLE_CLEAN_ROOM_WORKING_FOLDER_NAME, wzExecutableName, pSection, psczCleanRoomBundlePath);
918 ExitOnFailure(hr, "Failed to cache bundle to clean room."); 943 ExitOnFailure(hr, "Failed to cache bundle to clean room.");
919 944
920LExit: 945LExit:
@@ -924,6 +949,7 @@ LExit:
924} 949}
925 950
926extern "C" HRESULT CacheBundleToWorkingDirectory( 951extern "C" HRESULT CacheBundleToWorkingDirectory(
952 __in BOOL fElevated,
927 __in BURN_CACHE* pCache, 953 __in BURN_CACHE* pCache,
928 __in_z LPCWSTR wzExecutableName, 954 __in_z LPCWSTR wzExecutableName,
929 __in BURN_SECTION* pSection, 955 __in BURN_SECTION* pSection,
@@ -948,7 +974,7 @@ extern "C" HRESULT CacheBundleToWorkingDirectory(
948 } 974 }
949 else // otherwise, carry on putting the bundle in the working folder. 975 else // otherwise, carry on putting the bundle in the working folder.
950 { 976 {
951 hr = CopyEngineToWorkingFolder(pCache, sczSourcePath, BUNDLE_WORKING_FOLDER_NAME, wzExecutableName, pSection, psczEngineWorkingPath); 977 hr = CopyEngineToWorkingFolder(fElevated, pCache, sczSourcePath, BUNDLE_WORKING_FOLDER_NAME, wzExecutableName, pSection, psczEngineWorkingPath);
952 ExitOnFailure(hr, "Failed to copy engine to working folder."); 978 ExitOnFailure(hr, "Failed to copy engine to working folder.");
953 } 979 }
954 980
@@ -2099,6 +2125,7 @@ LExit:
2099 2125
2100 2126
2101static HRESULT CopyEngineToWorkingFolder( 2127static HRESULT CopyEngineToWorkingFolder(
2128 __in BOOL fElevated,
2102 __in BURN_CACHE* pCache, 2129 __in BURN_CACHE* pCache,
2103 __in_z LPCWSTR wzSourcePath, 2130 __in_z LPCWSTR wzSourcePath,
2104 __in_z LPCWSTR wzWorkingFolderName, 2131 __in_z LPCWSTR wzWorkingFolderName,
@@ -2115,7 +2142,7 @@ static HRESULT CopyEngineToWorkingFolder(
2115 LPWSTR sczPayloadSourcePath = NULL; 2142 LPWSTR sczPayloadSourcePath = NULL;
2116 LPWSTR sczPayloadTargetPath = NULL; 2143 LPWSTR sczPayloadTargetPath = NULL;
2117 2144
2118 hr = CacheEnsureBaseWorkingFolder(pCache, &sczWorkingFolder); 2145 hr = CacheEnsureBaseWorkingFolder(fElevated, pCache, &sczWorkingFolder);
2119 ExitOnFailure(hr, "Failed to create working path to copy engine."); 2146 ExitOnFailure(hr, "Failed to create working path to copy engine.");
2120 2147
2121 hr = PathConcatRelativeToFullyQualifiedBase(sczWorkingFolder, wzWorkingFolderName, &sczTargetDirectory); 2148 hr = PathConcatRelativeToFullyQualifiedBase(sczWorkingFolder, wzWorkingFolderName, &sczTargetDirectory);
diff --git a/src/burn/engine/cache.h b/src/burn/engine/cache.h
index cc28166e..1ad5d96c 100644
--- a/src/burn/engine/cache.h
+++ b/src/burn/engine/cache.h
@@ -97,6 +97,7 @@ HRESULT CacheEnsureAcquisitionFolder(
97 __in BURN_CACHE* pCache 97 __in BURN_CACHE* pCache
98 ); 98 );
99HRESULT CacheEnsureBaseWorkingFolder( 99HRESULT CacheEnsureBaseWorkingFolder(
100 __in BOOL fElevated,
100 __in BURN_CACHE* pCache, 101 __in BURN_CACHE* pCache,
101 __deref_out_z_opt LPWSTR* psczBaseWorkingFolder 102 __deref_out_z_opt LPWSTR* psczBaseWorkingFolder
102 ); 103 );
@@ -172,11 +173,13 @@ HRESULT CachePreparePackage(
172 __in BURN_PACKAGE* pPackage 173 __in BURN_PACKAGE* pPackage
173 ); 174 );
174HRESULT CacheBundleToCleanRoom( 175HRESULT CacheBundleToCleanRoom(
176 __in BOOL fElevated,
175 __in BURN_CACHE* pCache, 177 __in BURN_CACHE* pCache,
176 __in BURN_SECTION* pSection, 178 __in BURN_SECTION* pSection,
177 __deref_out_z_opt LPWSTR* psczCleanRoomBundlePath 179 __deref_out_z_opt LPWSTR* psczCleanRoomBundlePath
178 ); 180 );
179HRESULT CacheBundleToWorkingDirectory( 181HRESULT CacheBundleToWorkingDirectory(
182 __in BOOL fElvated,
180 __in BURN_CACHE* pCache, 183 __in BURN_CACHE* pCache,
181 __in_z LPCWSTR wzExecutableName, 184 __in_z LPCWSTR wzExecutableName,
182 __in BURN_SECTION* pSection, 185 __in BURN_SECTION* pSection,
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index 8903b5b2..2d8a76dd 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -182,7 +182,7 @@ extern "C" HRESULT CoreInitialize(
182 if (BURN_MODE_NORMAL == pEngineState->internalCommand.mode || BURN_MODE_EMBEDDED == pEngineState->internalCommand.mode) 182 if (BURN_MODE_NORMAL == pEngineState->internalCommand.mode || BURN_MODE_EMBEDDED == pEngineState->internalCommand.mode)
183 { 183 {
184 // Extract all UX payloads to working folder. 184 // Extract all UX payloads to working folder.
185 hr = UserExperienceEnsureWorkingFolder(&pEngineState->cache, &pEngineState->userExperience.sczTempDirectory); 185 hr = UserExperienceEnsureWorkingFolder(pEngineState->internalCommand.fInitiallyElevated, &pEngineState->cache, &pEngineState->userExperience.sczTempDirectory);
186 ExitOnFailure(hr, "Failed to get unique temporary folder for bootstrapper application."); 186 ExitOnFailure(hr, "Failed to get unique temporary folder for bootstrapper application.");
187 187
188 hr = PayloadExtractUXContainer(&pEngineState->userExperience.payloads, &containerContext, pEngineState->userExperience.sczTempDirectory); 188 hr = PayloadExtractUXContainer(&pEngineState->userExperience.payloads, &containerContext, pEngineState->userExperience.sczTempDirectory);
@@ -227,7 +227,7 @@ extern "C" HRESULT CoreInitializeConstants(
227 hr = StrAllocString(&pRegistration->sczBundlePackageAncestors, pRegistration->sczId, 0); 227 hr = StrAllocString(&pRegistration->sczBundlePackageAncestors, pRegistration->sczId, 0);
228 ExitOnFailure(hr, "Failed to copy self to bundle package ancestors."); 228 ExitOnFailure(hr, "Failed to copy self to bundle package ancestors.");
229 } 229 }
230 230
231 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) 231 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
232 { 232 {
233 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i; 233 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i;
@@ -605,7 +605,7 @@ extern "C" HRESULT CoreElevate(
605 // If the elevated companion pipe isn't created yet, let's make that happen. 605 // If the elevated companion pipe isn't created yet, let's make that happen.
606 if (!pEngineState->sczBundleEngineWorkingPath) 606 if (!pEngineState->sczBundleEngineWorkingPath)
607 { 607 {
608 hr = CacheBundleToWorkingDirectory(&pEngineState->cache, pEngineState->registration.sczExecutableName, &pEngineState->section, &pEngineState->sczBundleEngineWorkingPath); 608 hr = CacheBundleToWorkingDirectory(pEngineState->internalCommand.fInitiallyElevated, &pEngineState->cache, pEngineState->registration.sczExecutableName, &pEngineState->section, &pEngineState->sczBundleEngineWorkingPath);
609 ExitOnFailure(hr, "Failed to cache engine to working directory."); 609 ExitOnFailure(hr, "Failed to cache engine to working directory.");
610 } 610 }
611 611
@@ -714,7 +714,7 @@ extern "C" HRESULT CoreApply(
714 // Ensure the engine is cached to the working path. 714 // Ensure the engine is cached to the working path.
715 if (!pEngineState->sczBundleEngineWorkingPath) 715 if (!pEngineState->sczBundleEngineWorkingPath)
716 { 716 {
717 hr = CacheBundleToWorkingDirectory(&pEngineState->cache, pEngineState->registration.sczExecutableName, &pEngineState->section, &pEngineState->sczBundleEngineWorkingPath); 717 hr = CacheBundleToWorkingDirectory(pEngineState->internalCommand.fInitiallyElevated, &pEngineState->cache, pEngineState->registration.sczExecutableName, &pEngineState->section, &pEngineState->sczBundleEngineWorkingPath);
718 ExitOnFailure(hr, "Failed to cache engine to working directory."); 718 ExitOnFailure(hr, "Failed to cache engine to working directory.");
719 } 719 }
720 720
@@ -2285,7 +2285,7 @@ static HRESULT DetectPackage(
2285{ 2285{
2286 HRESULT hr = S_OK; 2286 HRESULT hr = S_OK;
2287 BOOL fBegan = FALSE; 2287 BOOL fBegan = FALSE;
2288 2288
2289 fBegan = TRUE; 2289 fBegan = TRUE;
2290 hr = UserExperienceOnDetectPackageBegin(&pEngineState->userExperience, pPackage->sczId); 2290 hr = UserExperienceOnDetectPackageBegin(&pEngineState->userExperience, pPackage->sczId);
2291 ExitOnRootFailure(hr, "BA aborted detect package begin."); 2291 ExitOnRootFailure(hr, "BA aborted detect package begin.");
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp
index b093ec9b..79e6aab4 100644
--- a/src/burn/engine/engine.cpp
+++ b/src/burn/engine/engine.cpp
@@ -525,7 +525,7 @@ static HRESULT RunUntrusted(
525 } 525 }
526 else 526 else
527 { 527 {
528 hr = CacheBundleToCleanRoom(&pEngineState->cache, &pEngineState->section, &sczCachedCleanRoomBundlePath); 528 hr = CacheBundleToCleanRoom(pEngineState->internalCommand.fInitiallyElevated, &pEngineState->cache, &pEngineState->section, &sczCachedCleanRoomBundlePath);
529 ExitOnFailure(hr, "Failed to cache to clean room."); 529 ExitOnFailure(hr, "Failed to cache to clean room.");
530 530
531 wzCleanRoomBundlePath = sczCachedCleanRoomBundlePath; 531 wzCleanRoomBundlePath = sczCachedCleanRoomBundlePath;
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp
index 372ca901..65414a92 100644
--- a/src/burn/engine/userexperience.cpp
+++ b/src/burn/engine/userexperience.cpp
@@ -169,6 +169,7 @@ extern "C" HRESULT UserExperienceUnload(
169} 169}
170 170
171extern "C" HRESULT UserExperienceEnsureWorkingFolder( 171extern "C" HRESULT UserExperienceEnsureWorkingFolder(
172 __in BOOL fElevated,
172 __in BURN_CACHE* pCache, 173 __in BURN_CACHE* pCache,
173 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder 174 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder
174 ) 175 )
@@ -176,7 +177,7 @@ extern "C" HRESULT UserExperienceEnsureWorkingFolder(
176 HRESULT hr = S_OK; 177 HRESULT hr = S_OK;
177 LPWSTR sczWorkingFolder = NULL; 178 LPWSTR sczWorkingFolder = NULL;
178 179
179 hr = CacheEnsureBaseWorkingFolder(pCache, &sczWorkingFolder); 180 hr = CacheEnsureBaseWorkingFolder(fElevated, pCache, &sczWorkingFolder);
180 ExitOnFailure(hr, "Failed to create working folder."); 181 ExitOnFailure(hr, "Failed to create working folder.");
181 182
182 hr = StrAllocFormatted(psczUserExperienceWorkingFolder, L"%ls%ls\\", sczWorkingFolder, L".ba"); 183 hr = StrAllocFormatted(psczUserExperienceWorkingFolder, L"%ls%ls\\", sczWorkingFolder, L".ba");
diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h
index 4f15c5d7..6256b8be 100644
--- a/src/burn/engine/userexperience.h
+++ b/src/burn/engine/userexperience.h
@@ -64,6 +64,7 @@ HRESULT UserExperienceUnload(
64 __in BOOL fReload 64 __in BOOL fReload
65 ); 65 );
66HRESULT UserExperienceEnsureWorkingFolder( 66HRESULT UserExperienceEnsureWorkingFolder(
67 __in BOOL fElevated,
67 __in BURN_CACHE* pCache, 68 __in BURN_CACHE* pCache,
68 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder 69 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder
69 ); 70 );
diff --git a/src/dtf/SfxCA/SfxUtil.cpp b/src/dtf/SfxCA/SfxUtil.cpp
index 2e6b0555..32dc6e04 100644
--- a/src/dtf/SfxCA/SfxUtil.cpp
+++ b/src/dtf/SfxCA/SfxUtil.cpp
@@ -164,38 +164,18 @@ bool ExtractToTempDirectory(__in MSIHANDLE hSession, __in HMODULE hModule,
164 StringCchCopy(szTempDir, cchTempDirBuf, szModule); 164 StringCchCopy(szTempDir, cchTempDirBuf, szModule);
165 StringCchCat(szTempDir, cchTempDirBuf, L"-"); 165 StringCchCat(szTempDir, cchTempDirBuf, L"-");
166 166
167 BOOL fCreatedDirectory = FALSE;
167 DWORD cchTempDir = (DWORD) wcslen(szTempDir); 168 DWORD cchTempDir = (DWORD) wcslen(szTempDir);
168 for (int i = 0; DirectoryExists(szTempDir); i++) 169 for (int i = 0; i < 10000 && !fCreatedDirectory; i++)
169 { 170 {
170 swprintf_s(szTempDir + cchTempDir, cchTempDirBuf - cchTempDir, L"%d", i); 171 swprintf_s(szTempDir + cchTempDir, cchTempDirBuf - cchTempDir, L"%d", i);
172 fCreatedDirectory = ::CreateDirectory(szTempDir, NULL);
171 } 173 }
172 174
173 if (!CreateDirectory(szTempDir, NULL)) 175 if (!fCreatedDirectory)
174 { 176 {
175 cchCopied = GetTempPath(cchTempDirBuf, szTempDir); 177 Log(hSession, L"Failed to create temp directory. Error code %d", ::GetLastError());
176 if (cchCopied == 0 || cchCopied >= cchTempDirBuf) 178 return false;
177 {
178 Log(hSession, L"Failed to get temp directory. Error code %d", GetLastError());
179 return false;
180 }
181
182 wchar_t* szModuleName = wcsrchr(szModule, L'\\');
183 if (szModuleName == NULL) szModuleName = szModule;
184 else szModuleName = szModuleName + 1;
185 StringCchCat(szTempDir, cchTempDirBuf, szModuleName);
186 StringCchCat(szTempDir, cchTempDirBuf, L"-");
187
188 cchTempDir = (DWORD) wcslen(szTempDir);
189 for (int i = 0; DirectoryExists(szTempDir); i++)
190 {
191 swprintf_s(szTempDir + cchTempDir, cchTempDirBuf - cchTempDir, L"%d", i);
192 }
193
194 if (!CreateDirectory(szTempDir, NULL))
195 {
196 Log(hSession, L"Failed to create temp directory. Error code %d", GetLastError());
197 return false;
198 }
199 } 179 }
200 180
201 Log(hSession, L"Extracting custom action to temporary directory: %s\\", szTempDir); 181 Log(hSession, L"Extracting custom action to temporary directory: %s\\", szTempDir);