aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
-rw-r--r--src/burn/test/BurnUnitTest/ApprovedExeTest.cpp312
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj1
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters5
-rw-r--r--src/burn/test/BurnUnitTest/precomp.h1
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs14
10 files changed, 450 insertions, 25 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)
diff --git a/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp b/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp
new file mode 100644
index 00000000..da51f1f8
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp
@@ -0,0 +1,312 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15 using namespace System;
16 using namespace System::IO;
17 using namespace Xunit;
18
19 public ref class ApprovedExeTest : BurnUnitTest
20 {
21 public:
22 ApprovedExeTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
23 {
24 }
25
26 [Fact]
27 void ApprovedExesVerifyPFilesTest()
28 {
29 HRESULT hr = S_OK;
30 BURN_CACHE cache = { };
31 BURN_ENGINE_COMMAND internalCommand = { };
32 BURN_VARIABLES variables = { };
33 LPWSTR scz = NULL;
34 LPWSTR scz2 = NULL;
35
36 try
37 {
38 hr = VariableInitialize(&variables);
39 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
40
41 hr = CacheInitialize(&cache, &internalCommand);
42 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
43
44 hr = VariableGetString(&variables, L"ProgramFilesFolder", &scz);
45 NativeAssert::Succeeded(hr, "Failed to get variable ProgramFilesFolder.");
46
47 hr = PathConcat(scz, L"a.exe", &scz2);
48 NativeAssert::Succeeded(hr, "Failed to combine paths");
49
50 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 0, NULL);
51 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFilesFolder");
52 Assert::True((hr == S_OK), "Path under ProgramFilesFolder was expected to be safe");
53 }
54 finally
55 {
56 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
57 ReleaseStr(scz);
58 ReleaseStr(scz2);
59
60 CacheUninitialize(&cache);
61 VariablesUninitialize(&variables);
62 }
63 }
64
65 [Fact]
66 void ApprovedExesVerifyPFilesWithRelativeTest()
67 {
68 HRESULT hr = S_OK;
69 BURN_CACHE cache = { };
70 BURN_ENGINE_COMMAND internalCommand = { };
71 BURN_VARIABLES variables = { };
72 LPWSTR scz = NULL;
73 LPWSTR scz2 = NULL;
74
75 try
76 {
77 hr = VariableInitialize(&variables);
78 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
79
80 hr = CacheInitialize(&cache, &internalCommand);
81 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
82 cache.fPerMachineCacheRootVerified = TRUE;
83 cache.fOriginalPerMachineCacheRootVerified = TRUE;
84
85 hr = VariableGetString(&variables, L"ProgramFilesFolder", &scz);
86 NativeAssert::Succeeded(hr, "Failed to get variable ProgramFilesFolder.");
87
88 hr = PathConcat(scz, L"..\\a.exe", &scz2);
89 NativeAssert::Succeeded(hr, "Failed to combine paths");
90
91 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 0, NULL);
92 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFilesFolder");
93 Assert::True((hr == S_FALSE), "Path pretending to be under ProgramFilesFolder was expected to be unsafe");
94 }
95 finally
96 {
97 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
98 ReleaseStr(scz);
99 ReleaseStr(scz2);
100
101 CacheUninitialize(&cache);
102 VariablesUninitialize(&variables);
103 }
104 }
105
106 [Fact]
107 void ApprovedExesVerifyPFiles64Test()
108 {
109 HRESULT hr = S_OK;
110 BURN_CACHE cache = { };
111 BURN_ENGINE_COMMAND internalCommand = { };
112 BURN_VARIABLES variables = { };
113 LPWSTR scz = NULL;
114 LPWSTR scz2 = NULL;
115
116 try
117 {
118 hr = VariableInitialize(&variables);
119 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
120
121 hr = CacheInitialize(&cache, &internalCommand);
122 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
123
124 hr = VariableGetString(&variables, L"ProgramFiles64Folder", &scz);
125 NativeAssert::Succeeded(hr, "Failed to get variable ProgramFiles64Folder.");
126
127 hr = PathConcat(scz, L"a.exe", &scz2);
128 NativeAssert::Succeeded(hr, "Failed to combine paths");
129
130 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 0, NULL);
131 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder");
132 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe");
133 }
134 finally
135 {
136 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
137 ReleaseStr(scz);
138 ReleaseStr(scz2);
139
140 CacheUninitialize(&cache);
141 VariablesUninitialize(&variables);
142 }
143 }
144
145 [Fact]
146 void ApprovedExesVerifySys64FolderTest()
147 {
148 HRESULT hr = S_OK;
149 BURN_CACHE cache = { };
150 BURN_ENGINE_COMMAND internalCommand = { };
151 BURN_VARIABLES variables = { };
152 LPWSTR scz = NULL;
153 LPWSTR scz2 = NULL;
154
155 try
156 {
157 hr = VariableInitialize(&variables);
158 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
159
160 hr = CacheInitialize(&cache, &internalCommand);
161 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
162 cache.fPerMachineCacheRootVerified = TRUE;
163 cache.fOriginalPerMachineCacheRootVerified = TRUE;
164
165 hr = VariableGetString(&variables, L"System64Folder", &scz);
166 NativeAssert::Succeeded(hr, "Failed to get variable System64Folder.");
167
168 hr = PathConcat(scz, L"a.exe", &scz2);
169 NativeAssert::Succeeded(hr, "Failed to combine paths");
170
171 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 0, NULL);
172 NativeAssert::Succeeded(hr, "Failed to test secure location under System64Folder");
173 Assert::True((hr == S_FALSE), "Path under System64Folder was expected to be unsafe");
174 }
175 finally
176 {
177 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
178 ReleaseStr(scz);
179 ReleaseStr(scz2);
180
181 CacheUninitialize(&cache);
182 VariablesUninitialize(&variables);
183 }
184 }
185
186 [Fact]
187 void ApprovedExesVerifySys64Rundll32UnsafeTest()
188 {
189 HRESULT hr = S_OK;
190 BURN_CACHE cache = { };
191 BURN_ENGINE_COMMAND internalCommand = { };
192 BURN_VARIABLES variables = { };
193 LPWSTR scz = NULL;
194 LPWSTR scz2 = NULL;
195 LPWSTR szArgs = NULL;
196
197 try
198 {
199 hr = VariableInitialize(&variables);
200 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
201
202 hr = CacheInitialize(&cache, &internalCommand);
203 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
204 cache.fPerMachineCacheRootVerified = TRUE;
205 cache.fOriginalPerMachineCacheRootVerified = TRUE;
206
207 hr = VariableGetString(&variables, L"System64Folder", &scz);
208 NativeAssert::Succeeded(hr, "Failed to get variable System64Folder.");
209
210 hr = PathConcat(scz, L"rundll32.exe", &scz2);
211 NativeAssert::Succeeded(hr, "Failed to combine paths");
212
213 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz2));
214 NativeAssert::Succeeded(hr, "Failed to test secure location under System64Folder");
215 Assert::True((hr == S_FALSE), "Path under System64Folder was expected to be unsafe for rundll32 target");
216 }
217 finally
218 {
219 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
220 ReleaseStr(scz);
221 ReleaseStr(scz2);
222 ReleaseStr(szArgs);
223
224 CacheUninitialize(&cache);
225 VariablesUninitialize(&variables);
226 }
227 }
228
229 [Fact]
230 void ApprovedExesVerifySys64Rundll32SafeTest()
231 {
232 HRESULT hr = S_OK;
233 BURN_CACHE cache = { };
234 BURN_ENGINE_COMMAND internalCommand = { };
235 BURN_VARIABLES variables = { };
236 LPWSTR scz = NULL;
237 LPWSTR scz2 = NULL;
238 LPWSTR scz3 = NULL;
239
240 try
241 {
242 hr = VariableInitialize(&variables);
243 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
244
245 hr = CacheInitialize(&cache, &internalCommand);
246 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
247 cache.fPerMachineCacheRootVerified = TRUE;
248 cache.fOriginalPerMachineCacheRootVerified = TRUE;
249
250 // System64Folder
251 hr = VariableGetString(&variables, L"System64Folder", &scz);
252 NativeAssert::Succeeded(hr, "Failed to get variable System64Folder.");
253
254 hr = PathConcat(scz, L"rundll32.exe", &scz2);
255 NativeAssert::Succeeded(hr, "Failed to combine paths");
256
257 hr = VariableGetString(&variables, L"ProgramFiles64Folder", &scz);
258 NativeAssert::Succeeded(hr, "Failed to get variable ProgramFiles64Folder.");
259
260 hr = PathConcat(scz, L"a.dll", &scz3);
261 NativeAssert::Succeeded(hr, "Failed to combine paths");
262
263 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz3));
264 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder for System64Folder/rundll32 target");
265 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe for System64Folder/rundll32 target");
266
267 hr = PathConcat(scz, L"a.dll,somthing else", &scz3);
268 NativeAssert::Succeeded(hr, "Failed to combine paths");
269
270 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz3));
271 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder for rundll32 target");
272 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe for System64Folder/rundll32 target");
273
274 // SystemFolder
275 hr = VariableGetString(&variables, L"SystemFolder", &scz);
276 NativeAssert::Succeeded(hr, "Failed to get variable System64Folder.");
277
278 hr = PathConcat(scz, L"rundll32.exe", &scz2);
279 NativeAssert::Succeeded(hr, "Failed to combine paths");
280
281 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz3));
282 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder for SystemFolder/rundll32 target");
283 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe for SystemFolder/rundll32 target");
284
285 // Sysnative
286 hr = PathSystemWindowsSubdirectory(L"SysNative\\", &scz);
287 NativeAssert::Succeeded(hr, "Failed to get SysNative Folder.");
288
289 hr = PathConcat(scz, L"rundll32.exe", &scz2);
290 NativeAssert::Succeeded(hr, "Failed to combine paths");
291
292 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz3));
293 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder for Sysnative/rundll32 target");
294 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe for Sysnative/rundll32 target");
295 }
296 finally
297 {
298 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
299 ReleaseStr(scz);
300 ReleaseStr(scz2);
301 ReleaseStr(scz3);
302
303 CacheUninitialize(&cache);
304 VariablesUninitialize(&variables);
305 }
306 }
307 };
308}
309}
310}
311}
312}
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
index 331d237b..63d089e4 100644
--- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
@@ -45,6 +45,7 @@
45 45
46 <ItemGroup> 46 <ItemGroup>
47 <ClCompile Include="AssemblyInfo.cpp" /> 47 <ClCompile Include="AssemblyInfo.cpp" />
48 <ClCompile Include="ApprovedExeTest.cpp" />
48 <ClCompile Include="CacheTest.cpp" /> 49 <ClCompile Include="CacheTest.cpp" />
49 <ClCompile Include="ElevationTest.cpp" /> 50 <ClCompile Include="ElevationTest.cpp" />
50 <ClCompile Include="EmbeddedTest.cpp" /> 51 <ClCompile Include="EmbeddedTest.cpp" />
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters
index 82725436..59aea6e9 100644
--- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters
@@ -66,6 +66,9 @@
66 <ClCompile Include="VariantTest.cpp"> 66 <ClCompile Include="VariantTest.cpp">
67 <Filter>Source Files</Filter> 67 <Filter>Source Files</Filter>
68 </ClCompile> 68 </ClCompile>
69 <ClCompile Include="ApprovedExeTest.cpp">
70 <Filter>Source Files</Filter>
71 </ClCompile>
69 </ItemGroup> 72 </ItemGroup>
70 <ItemGroup> 73 <ItemGroup>
71 <ClInclude Include="BurnTestException.h"> 74 <ClInclude Include="BurnTestException.h">
@@ -95,4 +98,4 @@
95 <Filter>Resource Files</Filter> 98 <Filter>Resource Files</Filter>
96 </ResourceCompile> 99 </ResourceCompile>
97 </ItemGroup> 100 </ItemGroup>
98</Project> \ No newline at end of file 101</Project>
diff --git a/src/burn/test/BurnUnitTest/precomp.h b/src/burn/test/BurnUnitTest/precomp.h
index f07f5968..ec6fb7d1 100644
--- a/src/burn/test/BurnUnitTest/precomp.h
+++ b/src/burn/test/BurnUnitTest/precomp.h
@@ -74,6 +74,7 @@
74#include "splashscreen.h" 74#include "splashscreen.h"
75#include "detect.h" 75#include "detect.h"
76#include "externalengine.h" 76#include "externalengine.h"
77#include "approvedexe.h"
77 78
78#include "engine.version.h" 79#include "engine.version.h"
79 80
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs
index a7438564..e7c7ee5b 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs
@@ -30,7 +30,7 @@ namespace WixToolsetTest.BurnE2E
30 perMachineArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache(); 30 perMachineArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
31 arpEntryExePackage.VerifyRegistered(false); 31 arpEntryExePackage.VerifyRegistered(false);
32 32
33 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); 33 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}\""));
34 } 34 }
35 35
36 [RuntimeFact] 36 [RuntimeFact]
@@ -52,7 +52,7 @@ namespace WixToolsetTest.BurnE2E
52 perMachineArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache(); 52 perMachineArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
53 arpEntryExePackage.VerifyRegistered(false); 53 arpEntryExePackage.VerifyRegistered(false);
54 54
55 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); 55 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}\""));
56 } 56 }
57 57
58 [RuntimeFact] 58 [RuntimeFact]
@@ -85,7 +85,7 @@ namespace WixToolsetTest.BurnE2E
85 packageTestExe.VerifyInstalled(true); 85 packageTestExe.VerifyInstalled(true);
86 86
87 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe, default: None, requested: Acquire")); 87 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe, default: None, requested: Acquire"));
88 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); 88 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}\""));
89 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); 89 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
90 } 90 }
91 91
@@ -113,7 +113,7 @@ namespace WixToolsetTest.BurnE2E
113 packageTestExe.VerifyInstalled(true); 113 packageTestExe.VerifyInstalled(true);
114 114
115 Assert.False(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe")); 115 Assert.False(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe"));
116 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); 116 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}\""));
117 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); 117 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
118 } 118 }
119 119
@@ -144,7 +144,7 @@ namespace WixToolsetTest.BurnE2E
144 packageTestExe.VerifyInstalled(true); 144 packageTestExe.VerifyInstalled(true);
145 145
146 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe, default: None, requested: None")); 146 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe, default: None, requested: None"));
147 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); 147 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}\""));
148 } 148 }
149 149
150 [RuntimeFact] 150 [RuntimeFact]
@@ -161,7 +161,7 @@ namespace WixToolsetTest.BurnE2E
161 arpEntryExePackage.VerifyRegistered(false); 161 arpEntryExePackage.VerifyRegistered(false);
162 162
163 Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); 163 Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
164 Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); 164 Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"testexe.exe\" /regd \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}\""));
165 } 165 }
166 166
167 [RuntimeFact] 167 [RuntimeFact]
@@ -209,7 +209,7 @@ namespace WixToolsetTest.BurnE2E
209 perUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache(); 209 perUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
210 arpEntryExePackage.VerifyRegistered(false); 210 arpEntryExePackage.VerifyRegistered(false);
211 211
212 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); 212 Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}\""));
213 } 213 }
214 214
215 [RuntimeFact] 215 [RuntimeFact]