@joebigelow / wix-1 / commits / ae3a3179

Minimize chance of user arguments messing up the command line to avoid variations of issue 3890

Minimize chance of user arguments messing up the command line to avoid variations of issue 3890

Sean Hall committed Mar 30, 2022 at 17:05 UTC ae3a31795614000207470e6824887c414366a681
8 files changed +119 -91
src/burn/engine/bundlepackageengine.cpp
+34 -37
@@ -252,12 +252,12 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle(
252 {
253 HRESULT hr = S_OK;
254 LPCWSTR wzArguments = NULL;
255 - LPWSTR sczArguments = NULL;
256 - LPWSTR sczArgumentsFormatted = NULL;
257 - LPWSTR sczArgumentsObfuscated = NULL;
255 LPWSTR sczCachedDirectory = NULL;
256 LPWSTR sczExecutablePath = NULL;
260 - LPWSTR sczCommand = NULL;
257 + LPWSTR sczBaseCommand = NULL;
258 + LPWSTR sczUnformattedUserArgs = NULL;
259 + LPWSTR sczUserArgs = NULL;
260 + LPWSTR sczUserArgsObfuscated = NULL;
261 LPWSTR sczCommandObfuscated = NULL;
262 HANDLE hExecutableFile = INVALID_HANDLE_VALUE;
263 STARTUPINFOW si = { };
@@ -309,7 +309,7 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle(
309 // now add optional arguments
310 if (wzArguments && *wzArguments)
311 {
312 - hr = StrAllocString(&sczArguments, wzArguments, 0);
312 + hr = StrAllocString(&sczUnformattedUserArgs, wzArguments, 0);
313 ExitOnFailure(hr, "Failed to copy package arguments.");
314 }
315
@@ -323,26 +323,26 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle(
323
324 if (fCondition)
325 {
326 - if (sczArguments)
326 + if (sczUnformattedUserArgs)
327 {
328 - hr = StrAllocConcat(&sczArguments, L" ", 0);
328 + hr = StrAllocConcat(&sczUnformattedUserArgs, L" ", 0);
329 ExitOnFailure(hr, "Failed to separate command-line arguments.");
330 }
331
332 switch (action)
333 {
334 case BOOTSTRAPPER_ACTION_STATE_INSTALL:
335 - hr = StrAllocConcat(&sczArguments, commandLineArgument->sczInstallArgument, 0);
335 + hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczInstallArgument, 0);
336 ExitOnFailure(hr, "Failed to get command-line argument for install.");
337 break;
338
339 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
340 - hr = StrAllocConcat(&sczArguments, commandLineArgument->sczUninstallArgument, 0);
340 + hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczUninstallArgument, 0);
341 ExitOnFailure(hr, "Failed to get command-line argument for uninstall.");
342 break;
343
344 case BOOTSTRAPPER_ACTION_STATE_REPAIR:
345 - hr = StrAllocConcat(&sczArguments, commandLineArgument->sczRepairArgument, 0);
345 + hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczRepairArgument, 0);
346 ExitOnFailure(hr, "Failed to get command-line argument for repair.");
347 break;
348
@@ -353,75 +353,72 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle(
353 }
354 }
355
356 - // build command
357 - AppAppendCommandLineArgument(&sczCommand, sczExecutablePath);
358 - ExitOnFailure(hr, "Failed to create executable command.");
356 + // build base command
357 + hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath);
358 + ExitOnFailure(hr, "Failed to allocate base command.");
359
360 if (!fRunEmbedded)
361 {
362 - hr = StrAllocConcat(&sczCommand, L" -quiet", 0);
362 + hr = StrAllocConcat(&sczBaseCommand, L" -quiet", 0);
363 ExitOnFailure(hr, "Failed to append quiet argument.");
364 }
365
366 if (wzOperationCommandLine)
367 {
368 - hr = StrAllocConcatFormatted(&sczCommand, L" %ls", wzOperationCommandLine);
368 + hr = StrAllocConcatFormatted(&sczBaseCommand, L" %ls", wzOperationCommandLine);
369 ExitOnFailure(hr, "Failed to append operation argument.");
370 }
371
372 if (wzRelationTypeCommandLine)
373 {
374 - hr = StrAllocConcatFormatted(&sczCommand, L" -%ls", wzRelationTypeCommandLine);
374 + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls", wzRelationTypeCommandLine);
375 ExitOnFailure(hr, "Failed to append relation type argument.");
376 }
377
378 // Add the list of dependencies to ignore, if any, to the burn command line.
379 if (pExecuteAction->relatedBundle.sczIgnoreDependencies)
380 {
381 - hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->relatedBundle.sczIgnoreDependencies);
381 + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->relatedBundle.sczIgnoreDependencies);
382 ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line.");
383 }
384
385 // Add the list of ancestors, if any, to the burn command line.
386 if (pExecuteAction->relatedBundle.sczAncestors)
387 {
388 - hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->relatedBundle.sczAncestors);
388 + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->relatedBundle.sczAncestors);
389 ExitOnFailure(hr, "Failed to append the list of ancestors to the command line.");
390 }
391
392 - hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->relatedBundle.sczEngineWorkingDirectory, &sczCommand, NULL);
392 + hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->relatedBundle.sczEngineWorkingDirectory, &sczBaseCommand, NULL);
393 ExitOnFailure(hr, "Failed to append the custom working directory to the bundlepackage command line.");
394
395 - hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, NULL);
395 + hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczBaseCommand, NULL);
396 ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF);
397
398 - // Always add user supplied arguments last.
399 - if (sczArguments && *sczArguments)
398 + // build user args
399 + if (sczUnformattedUserArgs && *sczUnformattedUserArgs)
400 {
401 - hr = VariableFormatString(pVariables, sczArguments, &sczArgumentsFormatted, NULL);
401 + hr = VariableFormatString(pVariables, sczUnformattedUserArgs, &sczUserArgs, NULL);
402 ExitOnFailure(hr, "Failed to format argument string.");
403
404 - hr = VariableFormatStringObfuscated(pVariables, sczArguments, &sczArgumentsObfuscated, NULL);
404 + hr = VariableFormatStringObfuscated(pVariables, sczUnformattedUserArgs, &sczUserArgsObfuscated, NULL);
405 ExitOnFailure(hr, "Failed to format obfuscated argument string.");
406
407 - hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczCommand, sczArgumentsObfuscated);
408 - ExitOnFailure(hr, "Failed to copy obfuscated formatted arguments.");
409 -
410 - hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", sczArgumentsFormatted);
411 - ExitOnFailure(hr, "Failed to copy formatted arguments.");
407 + hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczBaseCommand, sczUserArgsObfuscated);
408 + ExitOnFailure(hr, "Failed to allocate obfuscated bundle command.");
409 }
410
414 - // Log before we add the secret pipe name and client token for embedded processes.
415 - LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(action), sczExecutablePath, sczCommandObfuscated);
411 + // Log obfuscated command, which won't include raw hidden variable values or protocol specific arguments to avoid exposing secrets.
412 + LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(action), sczExecutablePath, sczCommandObfuscated ? sczCommandObfuscated : sczBaseCommand);
413
414 if (fRunEmbedded)
415 {
419 - hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode);
416 + hr = EmbeddedRunBundle(sczExecutablePath, sczBaseCommand, sczUserArgs, pfnGenericMessageHandler, pvContext, &dwExitCode);
417 ExitOnFailure(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath);
418 }
419 else
420 {
424 - hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczCommand, sczCachedDirectory, &dwExitCode);
421 + hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczBaseCommand, sczUserArgs, sczCachedDirectory, &dwExitCode);
422 ExitOnFailure(hr, "Failed to run BUNDLE process");
423 }
424
@@ -429,12 +426,12 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle(
426 ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode);
427
428 LExit:
432 - StrSecureZeroFreeString(sczArguments);
433 - StrSecureZeroFreeString(sczArgumentsFormatted);
434 - ReleaseStr(sczArgumentsObfuscated);
429 ReleaseStr(sczCachedDirectory);
430 ReleaseStr(sczExecutablePath);
437 - StrSecureZeroFreeString(sczCommand);
431 + ReleaseStr(sczBaseCommand);
432 + ReleaseStr(sczUnformattedUserArgs);
433 + StrSecureZeroFreeString(sczUserArgs);
434 + ReleaseStr(sczUserArgsObfuscated);
435 ReleaseStr(sczCommandObfuscated);
436
437 ReleaseHandle(pi.hThread);
src/burn/engine/embedded.cpp
+13 -5
@@ -36,12 +36,13 @@ static HRESULT OnEmbeddedProgress(
36 // function definitions
37
38 /*******************************************************************
39 - EmbeddedLaunchChildProcess -
39 + EmbeddedRunBundle -
40
41 *******************************************************************/
42 extern "C" HRESULT EmbeddedRunBundle(
43 - __in LPCWSTR wzExecutablePath,
44 - __in LPCWSTR wzArguments,
43 + __in_z LPCWSTR wzExecutablePath,
44 + __in_z LPWSTR sczBaseCommand,
45 + __in_z_opt LPCWSTR wzUserArgs,
46 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
47 __in LPVOID pvContext,
48 __out DWORD* pdwExitCode
@@ -68,8 +69,15 @@ extern "C" HRESULT EmbeddedRunBundle(
69 hr = PipeCreatePipes(&connection, FALSE, &hCreatedPipesEvent);
70 ExitOnFailure(hr, "Failed to create embedded pipe.");
71
71 - hr = StrAllocFormattedSecure(&sczCommand, L"%ls -%ls %ls %ls %u", wzArguments, BURN_COMMANDLINE_SWITCH_EMBEDDED, connection.sczName, connection.sczSecret, dwCurrentProcessId);
72 - ExitOnFailure(hr, "Failed to allocate embedded command.");
72 + hr = StrAllocFormatted(&sczCommand, L"%ls -%ls %ls %ls %u", sczBaseCommand, BURN_COMMANDLINE_SWITCH_EMBEDDED, connection.sczName, connection.sczSecret, dwCurrentProcessId);
73 + ExitOnFailure(hr, "Failed to append embedded args.");
74 +
75 + // Always add user supplied arguments last.
76 + if (wzUserArgs)
77 + {
78 + hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", wzUserArgs);
79 + ExitOnFailure(hr, "Failed to append user args.");
80 + }
81
82 if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
83 {
src/burn/engine/embedded.h
+3 -2
@@ -15,8 +15,9 @@ typedef enum _BURN_EMBEDDED_MESSAGE_TYPE
15
16
17 HRESULT EmbeddedRunBundle(
18 - __in LPCWSTR wzExecutablePath,
19 - __in LPCWSTR wzArguments,
18 + __in_z LPCWSTR wzExecutablePath,
19 + __in_z LPWSTR sczBaseCommand,
20 + __in_z_opt LPCWSTR wzUserArgs,
21 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
22 __in LPVOID pvContext,
23 __out DWORD* pdwExitCode
src/burn/engine/exeengine.cpp
+45 -38
@@ -362,12 +362,12 @@ extern "C" HRESULT ExeEngineExecutePackage(
362 {
363 HRESULT hr = S_OK;
364 LPCWSTR wzArguments = NULL;
365 - LPWSTR sczArguments = NULL;
366 - LPWSTR sczArgumentsFormatted = NULL;
367 - LPWSTR sczArgumentsObfuscated = NULL;
365 LPWSTR sczCachedDirectory = NULL;
366 LPWSTR sczExecutablePath = NULL;
370 - LPWSTR sczCommand = NULL;
367 + LPWSTR sczBaseCommand = NULL;
368 + LPWSTR sczUnformattedUserArgs = NULL;
369 + LPWSTR sczUserArgs = NULL;
370 + LPWSTR sczUserArgsObfuscated = NULL;
371 LPWSTR sczCommandObfuscated = NULL;
372 HANDLE hExecutableFile = INVALID_HANDLE_VALUE;
373 DWORD dwExitCode = 0;
@@ -406,7 +406,7 @@ extern "C" HRESULT ExeEngineExecutePackage(
406 }
407
408 // now add optional arguments
409 - hr = StrAllocString(&sczArguments, wzArguments && *wzArguments ? wzArguments : L"", 0);
409 + hr = StrAllocString(&sczUnformattedUserArgs, wzArguments && *wzArguments ? wzArguments : L"", 0);
410 ExitOnFailure(hr, "Failed to copy package arguments.");
411
412 for (DWORD i = 0; i < pPackage->Exe.cCommandLineArguments; ++i)
@@ -419,23 +419,23 @@ extern "C" HRESULT ExeEngineExecutePackage(
419
420 if (fCondition)
421 {
422 - hr = StrAllocConcat(&sczArguments, L" ", 0);
422 + hr = StrAllocConcat(&sczUnformattedUserArgs, L" ", 0);
423 ExitOnFailure(hr, "Failed to separate command-line arguments.");
424
425 switch (pExecuteAction->exePackage.action)
426 {
427 case BOOTSTRAPPER_ACTION_STATE_INSTALL:
428 - hr = StrAllocConcat(&sczArguments, commandLineArgument->sczInstallArgument, 0);
428 + hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczInstallArgument, 0);
429 ExitOnFailure(hr, "Failed to get command-line argument for install.");
430 break;
431
432 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
433 - hr = StrAllocConcat(&sczArguments, commandLineArgument->sczUninstallArgument, 0);
433 + hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczUninstallArgument, 0);
434 ExitOnFailure(hr, "Failed to get command-line argument for uninstall.");
435 break;
436
437 case BOOTSTRAPPER_ACTION_STATE_REPAIR:
438 - hr = StrAllocConcat(&sczArguments, commandLineArgument->sczRepairArgument, 0);
438 + hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczRepairArgument, 0);
439 ExitOnFailure(hr, "Failed to get command-line argument for repair.");
440 break;
441
@@ -446,71 +446,68 @@ extern "C" HRESULT ExeEngineExecutePackage(
446 }
447 }
448
449 - // build command
450 - AppAppendCommandLineArgument(&sczCommand, sczExecutablePath);
451 - ExitOnFailure(hr, "Failed to create executable command.");
449 + // build base command
450 + hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath);
451 + ExitOnFailure(hr, "Failed to allocate base command.");
452
453 if (pPackage->Exe.fBundle)
454 {
455 - hr = StrAllocConcat(&sczCommand, L" -norestart", 0);
456 - ExitOnFailure(hr, "Failed to append quiet argument.");
455 + hr = StrAllocConcat(&sczBaseCommand, L" -norestart", 0);
456 + ExitOnFailure(hr, "Failed to append norestart argument.");
457
458 // Add the list of dependencies to ignore, if any, to the burn command line.
459 if (pExecuteAction->exePackage.sczIgnoreDependencies)
460 {
461 - hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies);
461 + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies);
462 ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line.");
463 }
464
465 // Add the list of ancestors, if any, to the burn command line.
466 if (pExecuteAction->exePackage.sczAncestors)
467 {
468 - hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", sczCommand, BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->exePackage.sczAncestors);
468 + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->exePackage.sczAncestors);
469 ExitOnFailure(hr, "Failed to append the list of ancestors to the command line.");
470 }
471
472 if (pExecuteAction->exePackage.sczEngineWorkingDirectory)
473 {
474 - hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->exePackage.sczEngineWorkingDirectory, &sczCommand, NULL);
474 + hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->exePackage.sczEngineWorkingDirectory, &sczBaseCommand, NULL);
475 ExitOnFailure(hr, "Failed to append the custom working directory to the exepackage command line.");
476 }
477
478 - hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, NULL);
478 + hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczBaseCommand, NULL);
479 ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF);
480 }
481
482 - // Always add user supplied arguments last.
483 - if (sczArguments && *sczArguments)
482 + // build user args
483 + if (sczUnformattedUserArgs && *sczUnformattedUserArgs)
484 {
485 - hr = VariableFormatString(pVariables, sczArguments, &sczArgumentsFormatted, NULL);
485 + hr = VariableFormatString(pVariables, sczUnformattedUserArgs, &sczUserArgs, NULL);
486 ExitOnFailure(hr, "Failed to format argument string.");
487
488 - hr = VariableFormatStringObfuscated(pVariables, sczArguments, &sczArgumentsObfuscated, NULL);
488 + hr = VariableFormatStringObfuscated(pVariables, sczUnformattedUserArgs, &sczUserArgsObfuscated, NULL);
489 ExitOnFailure(hr, "Failed to format obfuscated argument string.");
490
491 - hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczCommand, sczArgumentsObfuscated);
492 - ExitOnFailure(hr, "Failed to copy obfuscated formatted arguments.");
493 -
494 - hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", sczArgumentsFormatted);
495 - ExitOnFailure(hr, "Failed to copy formatted arguments.");
491 + hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczBaseCommand, sczUserArgsObfuscated);
492 + ExitOnFailure(hr, "Failed to allocate obfuscated exe command.");
493 }
494
498 - // Log before we add the secret pipe name and client token for embedded processes.
499 - LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), sczExecutablePath, sczCommandObfuscated);
495 + // Log obfuscated command, which won't include raw hidden variable values or protocol specific arguments to avoid exposing secrets.
496 + LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), sczExecutablePath, sczCommandObfuscated ? sczCommandObfuscated : sczBaseCommand);
497
498 if (!pPackage->Exe.fFireAndForget && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol)
499 {
503 - hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode);
500 + hr = EmbeddedRunBundle(sczExecutablePath, sczBaseCommand, sczUserArgs, pfnGenericMessageHandler, pvContext, &dwExitCode);
501 ExitOnFailure(hr, "Failed to run exe with Burn protocol from path: %ls", sczExecutablePath);
502 }
503 else if (!pPackage->Exe.fFireAndForget && BURN_EXE_PROTOCOL_TYPE_NETFX4 == pPackage->Exe.protocol)
504 {
508 - hr = NetFxRunChainer(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode);
505 + hr = NetFxRunChainer(sczExecutablePath, sczBaseCommand, sczUserArgs, pfnGenericMessageHandler, pvContext, &dwExitCode);
506 ExitOnFailure(hr, "Failed to run netfx chainer: %ls", sczExecutablePath);
507 }
508 else
509 {
513 - hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczCommand, sczCachedDirectory, &dwExitCode);
510 + hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczBaseCommand, sczUserArgs, sczCachedDirectory, &dwExitCode);
511 ExitOnFailure(hr, "Failed to run EXE process");
512 }
513
@@ -518,12 +515,12 @@ extern "C" HRESULT ExeEngineExecutePackage(
515 ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode);
516
517 LExit:
521 - StrSecureZeroFreeString(sczArguments);
522 - StrSecureZeroFreeString(sczArgumentsFormatted);
523 - ReleaseStr(sczArgumentsObfuscated);
518 ReleaseStr(sczCachedDirectory);
519 ReleaseStr(sczExecutablePath);
526 - StrSecureZeroFreeString(sczCommand);
520 + ReleaseStr(sczBaseCommand);
521 + ReleaseStr(sczUnformattedUserArgs);
522 + StrSecureZeroFreeString(sczUserArgs);
523 + ReleaseStr(sczUserArgsObfuscated);
524 ReleaseStr(sczCommandObfuscated);
525
526 ReleaseFileHandle(hExecutableFile);
@@ -540,12 +537,14 @@ extern "C" HRESULT ExeEngineRunProcess(
537 __in LPVOID pvContext,
538 __in BURN_PACKAGE* pPackage,
539 __in_z LPCWSTR wzExecutablePath,
543 - __in_z LPWSTR wzCommand,
540 + __in_z LPWSTR sczBaseCommand,
541 + __in_z_opt LPCWSTR wzUserArgs,
542 __in_z_opt LPCWSTR wzCachedDirectory,
543 __inout DWORD* pdwExitCode
544 )
545 {
546 HRESULT hr = S_OK;
547 + LPWSTR sczCommand = NULL;
548 STARTUPINFOW si = { };
549 PROCESS_INFORMATION pi = { };
550 GENERIC_EXECUTE_MESSAGE message = { };
@@ -555,10 +554,17 @@ extern "C" HRESULT ExeEngineRunProcess(
554 BOOL fFireAndForget = BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fFireAndForget;
555 BOOL fInheritHandles = BURN_PACKAGE_TYPE_BUNDLE == pPackage->type;
556
557 + // Always add user supplied arguments last.
558 + if (wzUserArgs)
559 + {
560 + hr = StrAllocFormattedSecure(&sczCommand, L"%ls %ls", sczBaseCommand, wzUserArgs);
561 + ExitOnFailure(hr, "Failed to append user args.");
562 + }
563 +
564 // Make the cache location of the executable the current directory to help those executables
565 // that expect stuff to be relative to them.
566 si.cb = sizeof(si);
561 - if (!::CreateProcessW(wzExecutablePath, wzCommand, NULL, NULL, fInheritHandles, CREATE_NO_WINDOW, NULL, wzCachedDirectory, &si, &pi))
567 + if (!::CreateProcessW(wzExecutablePath, sczCommand ? sczCommand : sczBaseCommand, NULL, NULL, fInheritHandles, CREATE_NO_WINDOW, NULL, wzCachedDirectory, &si, &pi))
568 {
569 ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath);
570 }
@@ -632,6 +638,7 @@ extern "C" HRESULT ExeEngineRunProcess(
638 }
639
640 LExit:
641 + StrSecureZeroFreeString(sczCommand);
642 ReleaseHandle(pi.hThread);
643 ReleaseHandle(pi.hProcess);
644
src/burn/engine/exeengine.h
+2 -1
@@ -47,7 +47,8 @@ HRESULT ExeEngineRunProcess(
47 __in LPVOID pvContext,
48 __in BURN_PACKAGE* pPackage,
49 __in_z LPCWSTR wzExecutablePath,
50 - __in_z LPWSTR wzCommand,
50 + __in_z LPWSTR sczBaseCommand,
51 + __in_z_opt LPCWSTR wzUserArgs,
52 __in_z_opt LPCWSTR wzCachedDirectory,
53 __inout DWORD* pdwExitCode
54 );
src/burn/engine/msuengine.cpp
+7 -2
@@ -273,6 +273,7 @@ extern "C" HRESULT MsuEngineExecutePackage(
273 LPWSTR sczSystemPath = NULL;
274 LPWSTR sczWusaPath = NULL;
275 LPWSTR sczCommand = NULL;
276 + LPWSTR sczEscapedKB = NULL;
277 SC_HANDLE schWu = NULL;
278 BOOL fWuWasDisabled = FALSE;
279 STARTUPINFOW si = { };
@@ -328,8 +329,11 @@ extern "C" HRESULT MsuEngineExecutePackage(
329 break;
330
331 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
332 + hr = AppEscapeCommandLineArgumentFormatted(&sczEscapedKB, L"%ls", pPackage->Msu.sczKB);
333 + ExitOnFailure(hr, "Failed to escape MSU KB.");
334 +
335 // format command
332 - hr = StrAllocFormatted(&sczCommand, L"\"%ls\" /uninstall /kb:%ls /quiet /norestart", sczWusaPath, pPackage->Msu.sczKB);
336 + hr = StrAllocFormatted(&sczCommand, L"\"%ls\" /uninstall /kb:%ls /quiet /norestart", sczWusaPath, sczEscapedKB);
337 ExitOnFailure(hr, "Failed to format MSU uninstall command.");
338 break;
339
@@ -352,7 +356,7 @@ extern "C" HRESULT MsuEngineExecutePackage(
356 hr = EnsureWUServiceEnabled(fStopWusaService, &schWu, &fWuWasDisabled);
357 ExitOnFailure(hr, "Failed to ensure WU service was enabled to install MSU package.");
358
355 - hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczWusaPath, sczCommand, NULL, &dwExitCode);
359 + hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczWusaPath, sczCommand, NULL, NULL, &dwExitCode);
360 ExitOnFailure(hr, "Failed to run MSU process");
361
362 // We'll normalize the restart required error code from wusa.exe just in case. Most likely
@@ -389,6 +393,7 @@ LExit:
393 ReleaseStr(sczWindowsPath);
394 ReleaseStr(sczWusaPath);
395 ReleaseStr(sczCommand);
396 + ReleaseStr(sczEscapedKB);
397
398 ReleaseHandle(pi.hProcess);
399 ReleaseHandle(pi.hThread);
src/burn/engine/netfxchainer.cpp
+12 -4
@@ -329,8 +329,9 @@ LExit:
329 }
330
331 extern "C" HRESULT NetFxRunChainer(
332 - __in LPCWSTR wzExecutablePath,
333 - __in LPCWSTR wzArguments,
332 + __in_z LPCWSTR wzExecutablePath,
333 + __in_z LPWSTR sczBaseCommand,
334 + __in_z_opt LPCWSTR wzUserArgs,
335 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
336 __in LPVOID pvContext,
337 __out DWORD* pdwExitCode
@@ -360,8 +361,15 @@ extern "C" HRESULT NetFxRunChainer(
361 hr = CreateNetFxChainer(sczSectionName, sczEventName, &pNetfxChainer);
362 ExitOnFailure(hr, "Failed to create netfx chainer.");
363
363 - hr = StrAllocFormattedSecure(&sczCommand, L"%ls /pipe %ls", wzArguments, sczSectionName);
364 - ExitOnFailure(hr, "Failed to allocate netfx chainer arguments.");
364 + hr = StrAllocFormatted(&sczCommand, L"%ls /pipe %ls", sczBaseCommand, sczSectionName);
365 + ExitOnFailure(hr, "Failed to append netfx chainer args.");
366 +
367 + // Always add user supplied arguments last.
368 + if (wzUserArgs)
369 + {
370 + hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", wzUserArgs);
371 + ExitOnFailure(hr, "Failed to append user args.");
372 + }
373
374 si.cb = sizeof(si);
375 if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
src/burn/engine/netfxchainer.h
+3 -2
@@ -87,8 +87,9 @@ struct NetFxCloseApplications
87 };
88
89 HRESULT NetFxRunChainer(
90 - __in LPCWSTR wzExecutablePath,
91 - __in LPCWSTR wzArguments,
90 + __in_z LPCWSTR wzExecutablePath,
91 + __in_z LPWSTR sczBaseCommand,
92 + __in_z_opt LPCWSTR wzUserArgs,
93 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
94 __in LPVOID pvContext,
95 __out DWORD* pdwExitCode