WIXBUG:5234 - When launching the clean room Burn process, pass a file handle of the original exe to the process on the command line. Use this file handle when using the attached container.

This commit is contained in:
Sean Hall 2016-04-03 22:04:49 -05:00
Родитель 168760a2d6
Коммит 5a955a3c3c
10 изменённых файлов: 91 добавлений и 96 удалений

Просмотреть файл

@ -1 +1 @@
* SeanHall: WIXBUG5234 - Make Burn grab a file handle to the original bundle so it can still access compressed payloads even if the original bundle was deleted after initialization (e.g. when a bundle uses Burn's built-in update mechanism).
* SeanHall: WIXBUG:5234 - Make Burn grab a file handle to the original bundle so it can still access compressed payloads even if the original bundle was deleted after initialization (e.g. when a bundle uses Burn's built-in update mechanism). Also, when launching the clean room Burn process, pass a file handle of the original exe to the process on the command line. Use this file handle when using the attached container.

Просмотреть файл

@ -80,7 +80,6 @@ static HRESULT LayoutBundle(
__in DWORD64 qwTotalCacheSize
);
static HRESULT AcquireContainerOrPayload(
__in HANDLE hSourceEngineFile,
__in BURN_USER_EXPERIENCE* pUX,
__in BURN_VARIABLES* pVariables,
__in_opt BURN_CONTAINER* pContainer,
@ -518,7 +517,7 @@ extern "C" HRESULT ApplyCache(
break;
case BURN_CACHE_ACTION_TYPE_ACQUIRE_CONTAINER:
hr = AcquireContainerOrPayload(hSourceEngineFile, pUX, pVariables, pCacheAction->resolveContainer.pContainer, NULL, NULL, pCacheAction->resolveContainer.sczUnverifiedPath, qwSuccessfulCachedProgress, pPlan->qwCacheSizeTotal);
hr = AcquireContainerOrPayload(pUX, pVariables, pCacheAction->resolveContainer.pContainer, NULL, NULL, pCacheAction->resolveContainer.sczUnverifiedPath, qwSuccessfulCachedProgress, pPlan->qwCacheSizeTotal);
if (SUCCEEDED(hr))
{
qwSuccessfulCachedProgress += pCacheAction->resolveContainer.pContainer->qwFileSize;
@ -567,7 +566,7 @@ extern "C" HRESULT ApplyCache(
break;
case BURN_CACHE_ACTION_TYPE_ACQUIRE_PAYLOAD:
hr = AcquireContainerOrPayload(hSourceEngineFile, pUX, pVariables, NULL, pCacheAction->resolvePayload.pPackage, pCacheAction->resolvePayload.pPayload, pCacheAction->resolvePayload.sczUnverifiedPath, qwSuccessfulCachedProgress, pPlan->qwCacheSizeTotal);
hr = AcquireContainerOrPayload(pUX, pVariables, NULL, pCacheAction->resolvePayload.pPackage, pCacheAction->resolvePayload.pPayload, pCacheAction->resolvePayload.sczUnverifiedPath, qwSuccessfulCachedProgress, pPlan->qwCacheSizeTotal);
if (SUCCEEDED(hr))
{
qwSuccessfulCachedProgress += pCacheAction->resolvePayload.pPayload->qwFileSize;
@ -873,7 +872,8 @@ static HRESULT ExtractContainer(
HANDLE hContainerHandle = INVALID_HANDLE_VALUE;
LPWSTR sczExtractPayloadId = NULL;
if (pContainer->fAcquiredThroughSourceEngine)
// If the container is actually attached, then it was planned to be acquired through hSourceEngineFile.
if (pContainer->fActuallyAttached)
{
hContainerHandle = hSourceEngineFile;
}
@ -1065,7 +1065,6 @@ LExit:
}
static HRESULT AcquireContainerOrPayload(
__in HANDLE hSourceEngineFile,
__in BURN_USER_EXPERIENCE* pUX,
__in BURN_VARIABLES* pVariables,
__in_opt BURN_CONTAINER* pContainer,
@ -1086,8 +1085,6 @@ static HRESULT AcquireContainerOrPayload(
LPWSTR sczSourceFullPath = NULL;
BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT progress = { };
BOOL fRetry = FALSE;
LPWSTR sczSourceProcessPath = NULL;
int nContainerPathIsSourceProcessPath = 0;
progress.pContainer = pContainer;
progress.pPackage = pPackage;
@ -1102,7 +1099,6 @@ static HRESULT AcquireContainerOrPayload(
LPCWSTR wzSourcePath = pContainer ? pContainer->sczSourcePath : pPayload->sczSourcePath;
BOOL fFoundLocal = FALSE;
BOOL fAcquiredThroughSourceEngine = FALSE;
BOOL fCopy = FALSE;
BOOL fDownload = FALSE;
@ -1111,32 +1107,8 @@ static HRESULT AcquireContainerOrPayload(
hr = CacheFindLocalSource(wzSourcePath, pVariables, &fFoundLocal, &sczSourceFullPath);
ExitOnFailure(hr, "Failed to search local source.");
// If the container is attached to the source executable
// and the container path points at the source process executable
// then use the source engine file handle
// since it might have been deleted or moved since initialization.
if (pContainer && pContainer->fPrimary && !pContainer->fActuallyAttached && INVALID_HANDLE_VALUE != hSourceEngineFile)
{
// This is all "best effort" since in the worst case scenario we open a new
// handle to the container.
hr = VariableGetString(pVariables, BURN_BUNDLE_SOURCE_PROCESS_PATH, &sczSourceProcessPath);
if (SUCCEEDED(hr))
{
hr = PathCompare(sczSourceProcessPath, sczSourceFullPath, &nContainerPathIsSourceProcessPath);
if (SUCCEEDED(hr) && CSTR_EQUAL == nContainerPathIsSourceProcessPath)
{
fAcquiredThroughSourceEngine = TRUE;
}
}
}
if (fAcquiredThroughSourceEngine)
{
// TODO: verify the container is actually attached?
pContainer->fAcquiredThroughSourceEngine = TRUE;
}
else if (fFoundLocal) // the file exists locally, so copy it.
if (fFoundLocal) // the file exists locally, so copy it.
{
// If the source path and destination path are different, do the copy (otherwise there's no point).
hr = PathCompare(sczSourceFullPath, wzDestinationPath, &nEquivalentPaths);
@ -1190,38 +1162,8 @@ static HRESULT AcquireContainerOrPayload(
hr = DownloadPayload(&progress, wzDestinationPath);
// Error handling happens after sending complete message to BA.
}
else if (fAcquiredThroughSourceEngine)
{
int nResult = pUX->pUserExperience->OnCacheAcquireBegin(wzPackageOrContainerId, wzPayloadId, BOOTSTRAPPER_CACHE_OPERATION_COPY, sczSourceFullPath);
hr = UserExperienceInterpretExecuteResult(pUX, FALSE, MB_OKCANCEL, nResult);
ExitOnRootFailure(hr, "BA aborted cache acquire begin.");
// Send fake progress.
LARGE_INTEGER totalFileSize = { };
LARGE_INTEGER totalBytesTransferred = { };
static LARGE_INTEGER LARGE_INTEGER_ZERO = { };
totalFileSize.QuadPart = pContainer->qwFileSize;
totalBytesTransferred.QuadPart = pContainer->qwFileSize;
DWORD dwResult = CacheProgressRoutine(totalFileSize, totalBytesTransferred, LARGE_INTEGER_ZERO, LARGE_INTEGER_ZERO, 0, 0, NULL, NULL, &progress);
switch (dwResult)
{
case PROGRESS_CONTINUE:
case PROGRESS_QUIET:
hr = S_OK;
break;
case PROGRESS_CANCEL: __fallthrough;
case PROGRESS_STOP:
hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
ExitOnRootFailure(hr, "BA aborted on acquire progress.");
default:
hr = E_UNEXPECTED;
ExitOnRootFailure(hr, "Invalid return code from progress routine.");
}
}
if (fCopy || fDownload || fAcquiredThroughSourceEngine)
if (fCopy || fDownload)
{
int nResult = pUX->pUserExperience->OnCacheAcquireComplete(wzPackageOrContainerId, wzPayloadId, hr, IDNOACTION);
nResult = UserExperienceCheckExecuteResult(pUX, FALSE, MB_RETRYCANCEL, nResult);
@ -1231,13 +1173,12 @@ static HRESULT AcquireContainerOrPayload(
hr = S_OK;
}
}
ExitOnFailure2(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", fCopy ? sczSourceFullPath : wzDownloadUrl, wzDestinationPath);
ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", fCopy ? sczSourceFullPath : wzDownloadUrl, wzDestinationPath);
} while (fRetry);
ExitOnFailure(hr, "Failed to find external payload to cache.");
LExit:
ReleaseStr(sczSourceFullPath);
ReleaseStr(sczSourceProcessPath);
return hr;
}

Просмотреть файл

@ -83,7 +83,6 @@ typedef struct _BURN_CONTAINER
DWORD cbHash;
DWORD64 qwAttachedOffset;
BOOL fActuallyAttached; // indicates whether an attached container is attached or missing.
BOOL fAcquiredThroughSourceEngine;
//LPWSTR* rgsczPayloads;
//DWORD cPayloads;

Просмотреть файл

@ -119,9 +119,6 @@ extern "C" HRESULT CoreInitialize(
if (sczSourceProcessPath)
{
pEngineState->hSourceEngineFile = ::CreateFileW(sczSourceProcessPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Best effort to get handle to the untrusted engine, since that makes it much more likely to be able to get the attached container.
hr = VariableSetLiteralString(&pEngineState->variables, BURN_BUNDLE_SOURCE_PROCESS_PATH, sczSourceProcessPath, TRUE);
ExitOnFailure(hr, "Failed to set source process path variable.");
@ -259,7 +256,7 @@ extern "C" HRESULT CoreDetect(
pEngineState->userExperience.hwndDetect = hwndParent;
// Always reset the detect state which means the plan should be reset too.
DetectReset(&pEngineState->registration, &pEngineState->packages, &pEngineState->containers);
DetectReset(&pEngineState->registration, &pEngineState->packages);
PlanReset(&pEngineState->plan, &pEngineState->packages);
hr = SearchesExecute(&pEngineState->searches, &pEngineState->variables);
@ -993,6 +990,40 @@ LExit:
return hr;
}
extern "C" HRESULT CoreAppendFileHandleAttachedToCommandLine(
__in HANDLE hFileWithAttachedContainer,
__out HANDLE* phExecutableFile,
__deref_inout_z LPWSTR* psczCommandLine
)
{
HRESULT hr = S_OK;
HANDLE hExecutableFile = INVALID_HANDLE_VALUE;
LPWSTR sczCommandLine = NULL;
*phExecutableFile = INVALID_HANDLE_VALUE;
if (!::DuplicateHandle(::GetCurrentProcess(), hFileWithAttachedContainer, ::GetCurrentProcess(), &hExecutableFile, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
ExitWithLastError(hr, "Failed to duplicate file handle for attached container.");
}
hr = StrAllocFormattedSecure(&sczCommandLine, L"-%ls=%u %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, hExecutableFile, *psczCommandLine);
ExitOnFailure(hr, "Failed to append the file handle to the command line.");
StrSecureZeroFreeString(*psczCommandLine);
*psczCommandLine = sczCommandLine;
sczCommandLine = NULL;
*phExecutableFile = hExecutableFile;
hExecutableFile = INVALID_HANDLE_VALUE;
LExit:
StrSecureZeroFreeString(sczCommandLine);
ReleaseFileHandle(hExecutableFile);
return hr;
}
extern "C" HRESULT CoreAppendFileHandleSelfToCommandLine(
__in LPCWSTR wzExecutablePath,
__out HANDLE* phExecutableFile,
@ -1367,6 +1398,14 @@ static HRESULT ParseCommandLine(
hr = StrAllocString(psczAncestors, &wzParam[1], 0);
ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
}
else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED), BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)))
{
// Already processed in InitializeEngineState.
}
else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF), BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF)))
{
// Already processed in InitializeEngineState.
}
else if (lstrlenW(&argv[i][1]) >= lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX) &&
CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX), BURN_COMMANDLINE_SWITCH_PREFIX, lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX)))
{
@ -1546,7 +1585,7 @@ static DWORD WINAPI CacheThreadProc(
fComInitialized = TRUE;
// cache packages
hr = ApplyCache(pEngineState->hSourceEngineFile, &pEngineState->userExperience, &pEngineState->variables, &pEngineState->plan, pEngineState->companionConnection.hCachePipe, pcOverallProgressTicks, pfRollback);
hr = ApplyCache(pEngineState->section.hSourceEngineFile, &pEngineState->userExperience, &pEngineState->variables, &pEngineState->plan, pEngineState->companionConnection.hCachePipe, pcOverallProgressTicks, pfRollback);
LExit:
UserExperienceExecutePhaseComplete(&pEngineState->userExperience, hr); // signal that cache completed.

Просмотреть файл

@ -41,6 +41,7 @@ const LPCWSTR BURN_COMMANDLINE_SWITCH_PASSTHROUGH = L"burn.passthrough";
const LPCWSTR BURN_COMMANDLINE_SWITCH_DISABLE_UNELEVATE = L"burn.disable.unelevate";
const LPCWSTR BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES = L"burn.ignoredependencies";
const LPCWSTR BURN_COMMANDLINE_SWITCH_ANCESTORS = L"burn.ancestors";
const LPCWSTR BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED = L"burn.filehandle.attached";
const LPCWSTR BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF = L"burn.filehandle.self";
const LPCWSTR BURN_COMMANDLINE_SWITCH_PREFIX = L"burn.";
@ -143,7 +144,6 @@ typedef struct _BURN_ENGINE_STATE
int argc;
LPWSTR* argv;
HANDLE hSourceEngineFile;
} BURN_ENGINE_STATE;
@ -207,6 +207,11 @@ HRESULT CoreRecreateCommandLine(
__in_z_opt LPCWSTR wzAppendLogPath,
__in_z_opt LPCWSTR wzAdditionalCommandLineArguments
);
HRESULT CoreAppendFileHandleAttachedToCommandLine(
__in HANDLE hFileWithAttachedContainer,
__out HANDLE* phExecutableFile,
__deref_inout_z LPWSTR* psczCommandLine
);
HRESULT CoreAppendFileHandleSelfToCommandLine(
__in LPCWSTR wzExecutablePath,
__out HANDLE* phExecutableFile,

Просмотреть файл

@ -45,8 +45,7 @@ static HRESULT DownloadUpdateFeed(
extern "C" void DetectReset(
__in BURN_REGISTRATION* pRegistration,
__in BURN_PACKAGES* pPackages,
__in BURN_CONTAINERS* pContainers
__in BURN_PACKAGES* pPackages
)
{
RelatedBundlesUninitialize(&pRegistration->relatedBundles);
@ -89,12 +88,6 @@ extern "C" void DetectReset(
pPatchInfo->dwOrder = 0;
pPatchInfo->uStatus = 0;
}
for (DWORD iContainer = 0; iContainer < pContainers->cContainers; ++iContainer)
{
BURN_CONTAINER* pContainer = pContainers->rgContainers + iContainer;
pContainer->fAcquiredThroughSourceEngine = FALSE;
}
}
extern "C" HRESULT DetectForwardCompatibleBundle(

Просмотреть файл

@ -29,8 +29,7 @@ extern "C" {
void DetectReset(
__in BURN_REGISTRATION* pRegistration,
__in BURN_PACKAGES* pPackages,
__in BURN_CONTAINERS* pContainers
__in BURN_PACKAGES* pPackages
);
HRESULT DetectForwardCompatibleBundle(

Просмотреть файл

@ -276,6 +276,7 @@ static HRESULT InitializeEngineState(
HRESULT hr = S_OK;
LPCWSTR wzParam = NULL;
HANDLE hSectionFile = hEngineFile;
HANDLE hSourceEngineFile = INVALID_HANDLE_VALUE;
pEngineState->automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED;
pEngineState->dwElevatedLoggingTlsId = TLS_OUT_OF_INDEXES;
@ -288,6 +289,17 @@ static HRESULT InitializeEngineState(
{
if (pEngineState->argv[i][0] == L'-')
{
if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &pEngineState->argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED), BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)))
{
wzParam = &pEngineState->argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)];
if (L'=' != wzParam[-1] || L'\0' == wzParam[0])
{
ExitOnRootFailure(hr = E_INVALIDARG, "Missing required parameter for switch: %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED);
}
hr = StrStringToUInt32(wzParam, 0, reinterpret_cast<UINT*>(&hSourceEngineFile));
ExitOnFailure(hr, "Failed to parse file handle: '%ls'", (wzParam));
}
if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &pEngineState->argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF), BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF)))
{
wzParam = &pEngineState->argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF)];
@ -298,13 +310,11 @@ static HRESULT InitializeEngineState(
hr = StrStringToUInt32(wzParam, 0, reinterpret_cast<UINT*>(&hSectionFile));
ExitOnFailure(hr, "Failed to parse file handle: '%ls'", (wzParam));
break;
}
}
}
hr = SectionInitialize(&pEngineState->section, hSectionFile);
hr = SectionInitialize(&pEngineState->section, hSectionFile, hSourceEngineFile);
ExitOnFailure(hr, "Failed to initialize engine section.");
LExit:
@ -320,8 +330,6 @@ static void UninitializeEngineState(
AppFreeCommandLineArgs(pEngineState->argv);
}
ReleaseFileHandle(pEngineState->hSourceEngineFile);
ReleaseStr(pEngineState->sczIgnoreDependencies);
PipeConnectionUninitialize(&pEngineState->embeddedConnection);
@ -375,7 +383,8 @@ static HRESULT RunUntrusted(
LPWSTR sczFullCommandLine = NULL;
STARTUPINFOW si = { };
PROCESS_INFORMATION pi = { };
HANDLE hFile = NULL;
HANDLE hFileAttached = NULL;
HANDLE hFileSelf = NULL;
HANDLE hProcess = NULL;
hr = PathForCurrentProcess(&sczCurrentProcessPath, NULL);
@ -387,8 +396,12 @@ static HRESULT RunUntrusted(
hr = StrAllocFormattedSecure(&sczParameters, L"-%ls=\"%ls\" %ls", BURN_COMMANDLINE_SWITCH_CLEAN_ROOM, sczCurrentProcessPath, wzCommandLine);
ExitOnFailure(hr, "Failed to allocate parameters for unelevated process.");
// Send a file handle for the child Burn process to access the attached container.
hr = CoreAppendFileHandleAttachedToCommandLine(pEngineState->section.hEngineFile, &hFileAttached, &sczParameters);
ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED);
// Grab a file handle for the child Burn process.
hr = CoreAppendFileHandleSelfToCommandLine(sczCleanRoomBundlePath, &hFile, &sczParameters, NULL);
hr = CoreAppendFileHandleSelfToCommandLine(sczCleanRoomBundlePath, &hFileSelf, &sczParameters, NULL);
ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF);
#ifdef ENABLE_UNELEVATE
@ -421,7 +434,8 @@ static HRESULT RunUntrusted(
LExit:
ReleaseHandle(pi.hThread);
ReleaseFileHandle(hFile);
ReleaseFileHandle(hFileSelf);
ReleaseFileHandle(hFileAttached);
ReleaseHandle(hProcess);
StrSecureZeroFreeString(sczFullCommandLine);
StrSecureZeroFreeString(sczParameters);

Просмотреть файл

@ -43,7 +43,8 @@ typedef struct _BURN_SECTION_HEADER
extern "C" HRESULT SectionInitialize(
__in BURN_SECTION* pSection,
__in HANDLE hEngineFile
__in HANDLE hEngineFile,
__in HANDLE hSourceEngineFile
)
{
HRESULT hr = S_OK;
@ -63,6 +64,8 @@ extern "C" HRESULT SectionInitialize(
pSection->hEngineFile = hEngineFile;
ExitOnInvalidHandleWithLastError(pSection->hEngineFile, hr, "Failed to open handle to engine process path.");
pSection->hSourceEngineFile = INVALID_HANDLE_VALUE == hSourceEngineFile ? hEngineFile : hSourceEngineFile;
//
// First, make sure we have a valid DOS signature.
//
@ -208,7 +211,7 @@ extern "C" HRESULT SectionInitialize(
ExitOnRootFailure1(hr, "Failed to read section info, unsupported version: %08x", pBurnSectionHeader->dwVersion);
}
hr = FileSizeByHandle(pSection->hEngineFile, &llSize);
hr = FileSizeByHandle(pSection->hSourceEngineFile, &llSize);
ExitOnFailure(hr, "Failed to get total size of bundle.");
pSection->cbStub = pBurnSectionHeader->dwStubSize;

Просмотреть файл

@ -24,6 +24,7 @@ extern "C" {
typedef struct _BURN_SECTION
{
HANDLE hEngineFile;
HANDLE hSourceEngineFile;
DWORD cbStub;
DWORD cbEngineSize; // stub + UX container + original certficiate
@ -45,7 +46,8 @@ typedef struct _BURN_SECTION
HRESULT SectionInitialize(
__in BURN_SECTION* pSection,
__in HANDLE hEngineFile
__in HANDLE hEngineFile,
__in HANDLE hSourceEngineFile
);
void SectionUninitialize(
__in BURN_SECTION* pSection