aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine
diff options
context:
space:
mode:
authorNir Bar <nir.bar@panel-sw.co.il>2025-04-03 09:26:20 +0300
committerRob Mensching <rob@firegiant.com>2025-06-18 15:48:22 -0700
commit9af6ee7031536ccb91fc2eb2f8521a0ac286db2c (patch)
treec8965e4218450b3b9e02bb129d702dbb83adb8de /src/burn/engine
parent358bcc821c098a9ade94cca948056ec3d528a2bb (diff)
downloadwix-9af6ee7031536ccb91fc2eb2f8521a0ac286db2c.tar.gz
wix-9af6ee7031536ccb91fc2eb2f8521a0ac286db2c.tar.bz2
wix-9af6ee7031536ccb91fc2eb2f8521a0ac286db2c.zip
Support launching rundll32.exe as a safe executable if the dll it loads is in a secure location
Diffstat (limited to 'src/burn/engine')
-rw-r--r--src/burn/engine/approvedexe.cpp105
-rw-r--r--src/burn/engine/approvedexe.h4
-rw-r--r--src/burn/engine/bundlepackageengine.cpp2
-rw-r--r--src/burn/engine/elevation.cpp2
-rw-r--r--src/burn/engine/exeengine.cpp29
5 files changed, 125 insertions, 17 deletions
diff --git a/src/burn/engine/approvedexe.cpp b/src/burn/engine/approvedexe.cpp
index 28b26d6d..383ee7fa 100644
--- a/src/burn/engine/approvedexe.cpp
+++ b/src/burn/engine/approvedexe.cpp
@@ -3,6 +3,13 @@
3#include "precomp.h" 3#include "precomp.h"
4 4
5 5
6// internal function declarations
7
8static HRESULT IsRunDll32(
9 __in BURN_VARIABLES* pVariables,
10 __in LPCWSTR wzExecutablePath
11 );
12
6// function definitions 13// function definitions
7 14
8extern "C" HRESULT ApprovedExesParseFromXml( 15extern "C" HRESULT ApprovedExesParseFromXml(
@@ -221,12 +228,15 @@ LExit:
221extern "C" HRESULT ApprovedExesVerifySecureLocation( 228extern "C" HRESULT ApprovedExesVerifySecureLocation(
222 __in BURN_CACHE* pCache, 229 __in BURN_CACHE* pCache,
223 __in BURN_VARIABLES* pVariables, 230 __in BURN_VARIABLES* pVariables,
224 __in LPCWSTR wzExecutablePath 231 __in LPCWSTR wzExecutablePath,
232 __in int argc,
233 __in LPCWSTR* argv
225 ) 234 )
226{ 235{
227 HRESULT hr = S_OK; 236 HRESULT hr = S_OK;
228 LPWSTR scz = NULL; 237 LPWSTR scz = NULL;
229 LPWSTR sczSecondary = NULL; 238 LPWSTR sczSecondary = NULL;
239 LPWSTR sczRunDll32Param = NULL;
230 240
231 const LPCWSTR vrgSecureFolderVariables[] = { 241 const LPCWSTR vrgSecureFolderVariables[] = {
232 L"ProgramFiles64Folder", 242 L"ProgramFiles64Folder",
@@ -273,11 +283,104 @@ extern "C" HRESULT ApprovedExesVerifySecureLocation(
273 ExitFunction(); 283 ExitFunction();
274 } 284 }
275 285
286 // Test if executable is rundll32.exe, and it's target is in a secure location
287 // Example for CUDA UninstallString: "C:\WINDOWS\SysWOW64\RunDll32.EXE" "C:\Program Files\NVIDIA Corporation\Installer2\InstallerCore\NVI2.DLL",UninstallPackage CUDAToolkit_12.8
288 if (argc && argv && argv[0] && *argv[0])
289 {
290 hr = IsRunDll32(pVariables, wzExecutablePath);
291 ExitOnFailure(hr, "Failed to test whether executable is rundll32");
292
293 if (hr == S_OK)
294 {
295 LPCWSTR szComma = wcschr(argv[0], L',');
296 if (szComma && *szComma)
297 {
298 hr = StrAllocString(&sczRunDll32Param, argv[0], szComma - argv[0]);
299 ExitOnFailure(hr, "Failed to allocate string");
300 }
301 else
302 {
303 hr = StrAllocString(&sczRunDll32Param, argv[0], 0);
304 ExitOnFailure(hr, "Failed to allocate string");
305 }
306
307 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczRunDll32Param, 0, NULL);
308 ExitOnFailure(hr, "Failed to test whether rundll32's parameter, '%ls', is in a secure location", sczRunDll32Param);
309 if (hr == S_OK)
310 {
311 ExitFunction();
312 }
313 }
314 }
315
276 hr = S_FALSE; 316 hr = S_FALSE;
277 317
278LExit: 318LExit:
279 ReleaseStr(scz); 319 ReleaseStr(scz);
280 ReleaseStr(sczSecondary); 320 ReleaseStr(sczSecondary);
321 ReleaseStr(sczRunDll32Param);
322
323 return hr;
324}
325
326static HRESULT IsRunDll32(
327 __in BURN_VARIABLES* pVariables,
328 __in LPCWSTR wzExecutablePath
329 )
330{
331 HRESULT hr = S_OK;
332 LPWSTR sczFolder = NULL;
333 LPWSTR sczFullPath = NULL;
334 BOOL fEqual = FALSE;
335
336 hr = VariableGetString(pVariables, L"SystemFolder", &sczFolder);
337 ExitOnFailure(hr, "Failed to get the variable: SystemFolder");
338
339 hr = PathConcat(sczFolder, L"rundll32.exe", &sczFullPath);
340 ExitOnFailure(hr, "Failed to combine paths");
341
342 hr = PathCompareCanonicalized(wzExecutablePath, sczFullPath, &fEqual);
343 ExitOnFailure(hr, "Failed to compare paths");
344 if (fEqual)
345 {
346 hr = S_OK;
347 ExitFunction();
348 }
349
350 hr = VariableGetString(pVariables, L"System64Folder", &sczFolder);
351 ExitOnFailure(hr, "Failed to get the variable: System64Folder");
352
353 hr = PathConcat(sczFolder, L"rundll32.exe", &sczFullPath);
354 ExitOnFailure(hr, "Failed to combine paths");
355
356 hr = PathCompareCanonicalized(wzExecutablePath, sczFullPath, &fEqual);
357 ExitOnFailure(hr, "Failed to compare paths");
358 if (fEqual)
359 {
360 hr = S_OK;
361 ExitFunction();
362 }
363
364 // Sysnative
365 hr = PathSystemWindowsSubdirectory(L"SysNative\\", &sczFolder);
366 ExitOnFailure(hr, "Failed to append SysNative directory.");
367
368 hr = PathConcat(sczFolder, L"rundll32.exe", &sczFullPath);
369 ExitOnFailure(hr, "Failed to combine paths");
370
371 hr = PathCompareCanonicalized(wzExecutablePath, sczFullPath, &fEqual);
372 ExitOnFailure(hr, "Failed to compare paths");
373 if (fEqual)
374 {
375 hr = S_OK;
376 ExitFunction();
377 }
378
379 hr = S_FALSE;
380
381LExit:
382 ReleaseStr(sczFolder);
383 ReleaseStr(sczFullPath);
281 384
282 return hr; 385 return hr;
283} 386}
diff --git a/src/burn/engine/approvedexe.h b/src/burn/engine/approvedexe.h
index 7a68c174..0f441485 100644
--- a/src/burn/engine/approvedexe.h
+++ b/src/burn/engine/approvedexe.h
@@ -58,7 +58,9 @@ HRESULT ApprovedExesLaunch(
58HRESULT ApprovedExesVerifySecureLocation( 58HRESULT ApprovedExesVerifySecureLocation(
59 __in BURN_CACHE* pCache, 59 __in BURN_CACHE* pCache,
60 __in BURN_VARIABLES* pVariables, 60 __in BURN_VARIABLES* pVariables,
61 __in LPCWSTR wzExecutablePath 61 __in LPCWSTR wzExecutablePath,
62 __in int argc,
63 __in LPCWSTR* argv
62 ); 64 );
63 65
64 66
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp
index 574317e1..db433918 100644
--- a/src/burn/engine/bundlepackageengine.cpp
+++ b/src/burn/engine/bundlepackageengine.cpp
@@ -817,7 +817,7 @@ static HRESULT ExecuteBundle(
817 817
818 if (pPackage->fPerMachine) 818 if (pPackage->fPerMachine)
819 { 819 {
820 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath); 820 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath, argcArp - 1, (argcArp > 1) ? const_cast<LPCWSTR*>(argvArp + 1) : NULL);
821 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath); 821 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath);
822 if (S_FALSE == hr) 822 if (S_FALSE == hr)
823 { 823 {
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp
index 90e9db01..f208efc9 100644
--- a/src/burn/engine/elevation.cpp
+++ b/src/burn/engine/elevation.cpp
@@ -3876,7 +3876,7 @@ static HRESULT OnLaunchApprovedExe(
3876 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath); 3876 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath);
3877 ExitOnFailure(hr, "Failed to read the value for the approved exe path."); 3877 ExitOnFailure(hr, "Failed to read the value for the approved exe path.");
3878 3878
3879 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, pLaunchApprovedExe->sczExecutablePath); 3879 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, pLaunchApprovedExe->sczExecutablePath, 0, NULL);
3880 ExitOnFailure(hr, "Failed to verify the executable path is in a secure location: %ls", pLaunchApprovedExe->sczExecutablePath); 3880 ExitOnFailure(hr, "Failed to verify the executable path is in a secure location: %ls", pLaunchApprovedExe->sczExecutablePath);
3881 if (S_FALSE == hr) 3881 if (S_FALSE == hr)
3882 { 3882 {
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp
index 85168943..3a2816dd 100644
--- a/src/burn/engine/exeengine.cpp
+++ b/src/burn/engine/exeengine.cpp
@@ -489,29 +489,30 @@ extern "C" HRESULT ExeEngineExecutePackage(
489 } 489 }
490 else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action) 490 else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action)
491 { 491 {
492 ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "%hs is null.", pPackage->Exe.fArpUseUninstallString ? "UninstallString" : "QuietUninstallString"); 492 LPCWSTR szRegName = pPackage->Exe.fArpUseUninstallString ? L"UninstallString" : L"QuietUninstallString";
493 ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "%ls is null.", szRegName);
493 494
494 hr = AppParseCommandLine(sczArpUninstallString, &argcArp, &argvArp); 495 hr = AppParseCommandLine(sczArpUninstallString, &argcArp, &argvArp);
495 ExitOnFailure(hr, "Failed to parse QuietUninstallString: %ls.", sczArpUninstallString); 496 ExitOnFailure(hr, "Failed to parse %ls: %ls.", szRegName, sczArpUninstallString);
496 497
497 ExitOnNull(argcArp, hr, E_INVALIDARG, "QuietUninstallString must contain an executable path."); 498 ExitOnNull(argcArp, hr, E_INVALIDARG, "%ls must contain an executable path.", szRegName);
498 499
499 hr = StrAllocString(&sczExecutablePath, argvArp[0], 0); 500 hr = StrAllocString(&sczExecutablePath, argvArp[0], 0);
500 ExitOnFailure(hr, "Failed to copy executable path."); 501 ExitOnFailure(hr, "Failed to copy executable path.");
501 502
502 if (pPackage->fPerMachine) 503 if (pPackage->fPerMachine)
503 { 504 {
504 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath); 505 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath, argcArp - 1, (argcArp > 1) ? const_cast<LPCWSTR*>(argvArp + 1) : NULL);
505 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath); 506 ExitOnFailure(hr, "Failed to verify the %ls executable path is in a secure location: %ls", szRegName, sczExecutablePath);
506 if (S_FALSE == hr) 507 if (S_FALSE == hr)
507 { 508 {
508 LogStringLine(REPORT_STANDARD, "The QuietUninstallString executable path is not in a secure location: %ls", sczExecutablePath); 509 LogStringLine(REPORT_STANDARD, "The %ls executable path is not in a secure location: %ls", szRegName, sczExecutablePath);
509 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)); 510 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
510 } 511 }
511 } 512 }
512 513
513 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); 514 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory);
514 ExitOnFailure(hr, "Failed to get parent directory for QuietUninstallString executable path: %ls", sczExecutablePath); 515 ExitOnFailure(hr, "Failed to get parent directory for %ls executable path: %ls", szRegName, sczExecutablePath);
515 } 516 }
516 else 517 else
517 { 518 {
@@ -587,13 +588,15 @@ extern "C" HRESULT ExeEngineExecutePackage(
587 } 588 }
588 589
589 // build base command 590 // build base command
590 hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath); 591 if (sczArpUninstallString && *sczArpUninstallString)
591 ExitOnFailure(hr, "Failed to allocate base command."); 592 {
592 593 hr = StrAllocString(&sczBaseCommand, sczArpUninstallString, 0);
593 for (int i = 1; i < argcArp; ++i) 594 ExitOnFailure(hr, "Failed to allocate base command.");
595 }
596 else
594 { 597 {
595 hr = AppAppendCommandLineArgument(&sczBaseCommand, argvArp[i]); 598 hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath);
596 ExitOnFailure(hr, "Failed to append argument from ARP."); 599 ExitOnFailure(hr, "Failed to allocate base command.");
597 } 600 }
598 601
599 if (pPackage->Exe.fBundle) 602 if (pPackage->Exe.fBundle)