From b72f58abdf6dd5d0020f174358027158cb52cb72 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 19 Aug 2022 14:08:23 -0500 Subject: Use a dedicated pipe for redirecting logging from the elevated process. Fixes 6869 --- src/burn/engine/core.cpp | 24 ++++ src/burn/engine/core.h | 2 +- src/burn/engine/elevation.cpp | 15 +-- src/burn/engine/elevation.h | 1 - src/burn/engine/embedded.cpp | 4 +- src/burn/engine/engine.cpp | 264 ++++++++++++++++++++++++++++++++++-------- src/burn/engine/pipe.cpp | 91 ++++++++++++--- src/burn/engine/pipe.h | 10 +- src/burn/engine/uithread.cpp | 12 -- 9 files changed, 325 insertions(+), 98 deletions(-) (limited to 'src/burn') diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index bfd979de..ed824411 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -69,6 +69,9 @@ static HRESULT DetectPackagePayloadsCached( static DWORD WINAPI CacheThreadProc( __in LPVOID lpThreadParameter ); +static DWORD WINAPI LoggingThreadProc( + __in LPVOID lpThreadParameter + ); static void LogPackages( __in_opt const BURN_PACKAGE* pUpgradeBundlePackage, __in_opt const BURN_PACKAGE* pForwardCompatibleBundlePackage, @@ -615,6 +618,9 @@ extern "C" HRESULT CoreElevate( hr = VariableSetNumeric(&pEngineState->variables, BURN_BUNDLE_ELEVATED, TRUE, TRUE); ExitOnFailure(hr, "Failed to overwrite the %ls built-in variable.", BURN_BUNDLE_ELEVATED); + + pEngineState->hUnelevatedLoggingThread = ::CreateThread(NULL, 0, LoggingThreadProc, pEngineState, 0, NULL); + ExitOnNullWithLastError(pEngineState->hUnelevatedLoggingThread, hr, "Failed to create unelevated logging thread."); } LExit: @@ -2325,6 +2331,24 @@ LExit: return (DWORD)hr; } +static DWORD WINAPI LoggingThreadProc( + __in LPVOID lpThreadParameter + ) +{ + HRESULT hr = S_OK; + BURN_ENGINE_STATE* pEngineState = reinterpret_cast(lpThreadParameter); + BURN_PIPE_RESULT result = { }; + + hr = PipePumpMessages(pEngineState->companionConnection.hLoggingPipe, NULL, NULL, &result); + ExitOnFailure(hr, "Failed to pump logging messages for elevated process."); + + hr = (HRESULT)result.dwResult; + +LExit: + + return (DWORD)hr; +} + static void LogPackages( __in_opt const BURN_PACKAGE* pUpgradeBundlePackage, __in_opt const BURN_PACKAGE* pForwardCompatibleBundlePackage, diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h index c75d42de..a2f1ab4c 100644 --- a/src/burn/engine/core.h +++ b/src/burn/engine/core.h @@ -152,7 +152,7 @@ typedef struct _BURN_ENGINE_STATE BURN_PLAN plan; - DWORD dwElevatedLoggingTlsId; + HANDLE hUnelevatedLoggingThread; LPWSTR sczBundleEngineWorkingPath; BURN_PIPE_CONNECTION companionConnection; diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index e30a05bb..adc3aad9 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -91,7 +91,6 @@ typedef struct _BURN_ELEVATION_LAUNCH_APPROVED_EXE_MESSAGE_CONTEXT typedef struct _BURN_ELEVATION_CHILD_MESSAGE_CONTEXT { - DWORD dwLoggingTlsId; HANDLE hPipe; HANDLE* phLock; BOOL* pfDisabledAutomaticUpdates; @@ -397,10 +396,10 @@ extern "C" HRESULT ElevationElevate( Assert(!pEngineState->companionConnection.dwProcessId); Assert(INVALID_HANDLE_VALUE == pEngineState->companionConnection.hPipe); Assert(INVALID_HANDLE_VALUE == pEngineState->companionConnection.hCachePipe); + Assert(INVALID_HANDLE_VALUE == pEngineState->companionConnection.hLoggingPipe); HRESULT hr = S_OK; int nResult = IDOK; - HANDLE hPipesCreatedEvent = INVALID_HANDLE_VALUE; hr = UserExperienceOnElevateBegin(&pEngineState->userExperience); ExitOnRootFailure(hr, "BA aborted elevation requirement."); @@ -408,7 +407,7 @@ extern "C" HRESULT ElevationElevate( hr = PipeCreateNameAndSecret(&pEngineState->companionConnection.sczName, &pEngineState->companionConnection.sczSecret); ExitOnFailure(hr, "Failed to create pipe name and client token."); - hr = PipeCreatePipes(&pEngineState->companionConnection, TRUE, &hPipesCreatedEvent); + hr = PipeCreatePipes(&pEngineState->companionConnection, TRUE); ExitOnFailure(hr, "Failed to create pipe and cache pipe."); LogId(REPORT_STANDARD, MSG_LAUNCH_ELEVATED_ENGINE_STARTING); @@ -442,8 +441,6 @@ extern "C" HRESULT ElevationElevate( ExitOnFailure(hr, "Failed to elevate."); LExit: - ReleaseHandle(hPipesCreatedEvent); - if (FAILED(hr)) { PipeConnectionUninitialize(&pEngineState->companionConnection); @@ -1532,7 +1529,6 @@ LExit: *******************************************************************/ extern "C" HRESULT ElevationChildPumpMessages( - __in DWORD dwLoggingTlsId, __in HANDLE hPipe, __in HANDLE hCachePipe, __in BURN_APPROVED_EXES* pApprovedExes, @@ -1556,7 +1552,6 @@ extern "C" HRESULT ElevationChildPumpMessages( BURN_PIPE_RESULT result = { }; BOOL fDisabledAutomaticUpdates = FALSE; - cacheContext.dwLoggingTlsId = dwLoggingTlsId; cacheContext.hPipe = hCachePipe; cacheContext.pCache = pCache; cacheContext.pContainers = pContainers; @@ -1566,7 +1561,6 @@ extern "C" HRESULT ElevationChildPumpMessages( cacheContext.pRegistration = pRegistration; cacheContext.pUserExperience = pUserExperience; - context.dwLoggingTlsId = dwLoggingTlsId; context.hPipe = hPipe; context.phLock = phLock; context.pfDisabledAutomaticUpdates = &fDisabledAutomaticUpdates; @@ -1660,11 +1654,6 @@ static DWORD WINAPI ElevatedChildCacheThreadProc( BOOL fComInitialized = FALSE; BURN_PIPE_RESULT result = { }; - if (!::TlsSetValue(pContext->dwLoggingTlsId, pContext->hPipe)) - { - ExitWithLastError(hr, "Failed to set elevated cache pipe into thread local storage for logging."); - } - // initialize COM hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); ExitOnFailure(hr, "Failed to initialize COM."); diff --git a/src/burn/engine/elevation.h b/src/burn/engine/elevation.h index bda0fdef..0d15b470 100644 --- a/src/burn/engine/elevation.h +++ b/src/burn/engine/elevation.h @@ -166,7 +166,6 @@ HRESULT ElevationLaunchApprovedExe( // Child (per-machine process) side functions. HRESULT ElevationChildPumpMessages( - __in DWORD dwLoggingTlsId, __in HANDLE hPipe, __in HANDLE hCachePipe, __in BURN_APPROVED_EXES* pApprovedExes, diff --git a/src/burn/engine/embedded.cpp b/src/burn/engine/embedded.cpp index ac4c76d0..b9335cdf 100644 --- a/src/burn/engine/embedded.cpp +++ b/src/burn/engine/embedded.cpp @@ -51,7 +51,6 @@ extern "C" HRESULT EmbeddedRunBundle( { HRESULT hr = S_OK; DWORD dwCurrentProcessId = ::GetCurrentProcessId(); - HANDLE hCreatedPipesEvent = NULL; LPWSTR sczCommand = NULL; PROCESS_INFORMATION pi = { }; BURN_PIPE_RESULT result = { }; @@ -65,7 +64,7 @@ extern "C" HRESULT EmbeddedRunBundle( hr = PipeCreateNameAndSecret(&pConnection->sczName, &pConnection->sczSecret); ExitOnFailure(hr, "Failed to create embedded pipe name and client token."); - hr = PipeCreatePipes(pConnection, FALSE, &hCreatedPipesEvent); + hr = PipeCreatePipes(pConnection, FALSE); ExitOnFailure(hr, "Failed to create embedded pipe."); hr = StrAllocFormatted(&sczCommand, L"%ls -%ls %ls %ls %u", sczBaseCommand, BURN_COMMANDLINE_SWITCH_EMBEDDED, pConnection->sczName, pConnection->sczSecret, dwCurrentProcessId); @@ -100,7 +99,6 @@ LExit: ReleaseHandle(pi.hProcess); StrSecureZeroFreeString(sczCommand); - ReleaseHandle(hCreatedPipesEvent); PipeConnectionUninitialize(pConnection); return hr; diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp index 323d2c3a..daaf51dc 100644 --- a/src/burn/engine/engine.cpp +++ b/src/burn/engine/engine.cpp @@ -3,6 +3,15 @@ #include "precomp.h" +typedef struct _REDIRECTED_LOGGING_CONTEXT +{ + CRITICAL_SECTION csBuffer; + LPSTR sczBuffer; + HANDLE hPipe; + HANDLE hLogEvent; + HANDLE hFinishedEvent; +} REDIRECTED_LOGGING_CONTEXT; + // constants const DWORD RESTART_RETRIES = 10; @@ -49,6 +58,20 @@ static HRESULT DAPI RedirectLoggingOverPipe( __in_z LPCSTR szString, __in_opt LPVOID pvContext ); +static HRESULT LogStringOverPipe( + __in_z LPCSTR szString, + __in HANDLE hPipe + ); +static DWORD WINAPI ElevatedLoggingThreadProc( + __in LPVOID lpThreadParameter + ); +static HRESULT WaitForElevatedLoggingThread( + __in REDIRECTED_LOGGING_CONTEXT* pContext, + __in HANDLE hLoggingThread + ); +static HRESULT WaitForUnelevatedLoggingThread( + __in HANDLE hUnelevatedLoggingThread + ); static HRESULT Restart(); static void CALLBACK BurnTraceError( __in_z LPCSTR szFile, @@ -361,7 +384,6 @@ static HRESULT InitializeEngineState( HANDLE hSourceEngineFile = INVALID_HANDLE_VALUE; pEngineState->internalCommand.automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED; - pEngineState->dwElevatedLoggingTlsId = TLS_OUT_OF_INDEXES; ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive); PipeConnectionInitialize(&pEngineState->companionConnection); PipeConnectionInitialize(&pEngineState->embeddedConnection); @@ -434,11 +456,6 @@ static void UninitializeEngineState( ReleaseStr(pEngineState->log.sczPath); ReleaseStr(pEngineState->log.sczPathVariable); - if (TLS_OUT_OF_INDEXES != pEngineState->dwElevatedLoggingTlsId) - { - ::TlsFree(pEngineState->dwElevatedLoggingTlsId); - } - // clear struct memset(pEngineState, 0, sizeof(BURN_ENGINE_STATE)); } @@ -624,6 +641,8 @@ LExit: if (INVALID_HANDLE_VALUE != pEngineState->companionConnection.hPipe) { PipeTerminateChildProcess(&pEngineState->companionConnection, pEngineState->userExperience.dwExitCode, FALSE); + + WaitForUnelevatedLoggingThread(pEngineState->hUnelevatedLoggingThread); } // If the splash screen is still around, close it. @@ -646,6 +665,9 @@ static HRESULT RunElevated( { HRESULT hr = S_OK; HANDLE hLock = NULL; + HANDLE hLoggingThread = NULL; + REDIRECTED_LOGGING_CONTEXT loggingContext = { }; + BOOL fDeleteLoggingCs = FALSE; // Initialize logging. hr = LoggingOpen(&pEngineState->log, &pEngineState->internalCommand, &pEngineState->command, &pEngineState->variables, pEngineState->registration.sczDisplayName); @@ -655,20 +677,23 @@ static HRESULT RunElevated( hr = PipeChildConnect(&pEngineState->companionConnection, TRUE); ExitOnFailure(hr, "Failed to connect to unelevated process."); - // Set up the thread local storage to store the correct pipe to communicate logging then + // Set up the context for the logging thread then // override logging to write over the pipe. - pEngineState->dwElevatedLoggingTlsId = ::TlsAlloc(); - if (TLS_OUT_OF_INDEXES == pEngineState->dwElevatedLoggingTlsId) - { - ExitWithLastError(hr, "Failed to allocate thread local storage for logging."); - } + ::InitializeCriticalSection(&loggingContext.csBuffer); + fDeleteLoggingCs = TRUE; - if (!::TlsSetValue(pEngineState->dwElevatedLoggingTlsId, pEngineState->companionConnection.hPipe)) - { - ExitWithLastError(hr, "Failed to set elevated pipe into thread local storage for logging."); - } + loggingContext.hLogEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); + ExitOnNullWithLastError(loggingContext.hLogEvent, hr, "Failed to create log event for logging thread."); + + loggingContext.hFinishedEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); + ExitOnNullWithLastError(loggingContext.hFinishedEvent, hr, "Failed to create finished event for logging thread."); + + loggingContext.hPipe = pEngineState->companionConnection.hLoggingPipe; + + hLoggingThread = ::CreateThread(NULL, 0, ElevatedLoggingThreadProc, &loggingContext, 0, NULL); + ExitOnNullWithLastError(hLoggingThread, hr, "Failed to create elevated logging thread."); - LogRedirect(RedirectLoggingOverPipe, pEngineState); + LogRedirect(RedirectLoggingOverPipe, &loggingContext); // Create a top-level window to prevent shutting down the elevated process. hr = UiCreateMessageWindow(hInstance, pEngineState); @@ -677,16 +702,35 @@ static HRESULT RunElevated( SrpInitialize(TRUE); // Pump messages from parent process. - hr = ElevationChildPumpMessages(pEngineState->dwElevatedLoggingTlsId, pEngineState->companionConnection.hPipe, pEngineState->companionConnection.hCachePipe, &pEngineState->approvedExes, &pEngineState->cache, &pEngineState->containers, &pEngineState->packages, &pEngineState->payloads, &pEngineState->variables, &pEngineState->registration, &pEngineState->userExperience, &hLock, &pEngineState->userExperience.dwExitCode, &pEngineState->fRestart, &pEngineState->plan.fApplying); - LogRedirect(NULL, NULL); // reset logging so the next failure gets written to "log buffer" for the failure log. + hr = ElevationChildPumpMessages(pEngineState->companionConnection.hPipe, pEngineState->companionConnection.hCachePipe, &pEngineState->approvedExes, &pEngineState->cache, &pEngineState->containers, &pEngineState->packages, &pEngineState->payloads, &pEngineState->variables, &pEngineState->registration, &pEngineState->userExperience, &hLock, &pEngineState->userExperience.dwExitCode, &pEngineState->fRestart, &pEngineState->plan.fApplying); ExitOnFailure(hr, "Failed to pump messages from parent process."); + WaitForElevatedLoggingThread(&loggingContext, hLoggingThread); + LExit: + ReleaseHandle(hLoggingThread); + LogRedirect(NULL, NULL); // we're done talking to the child so always reset logging now. // If the message window is still around, close it. UiCloseMessageWindow(pEngineState); + if (fDeleteLoggingCs) + { + ::DeleteCriticalSection(&loggingContext.csBuffer); + } + + ReleaseHandle(loggingContext.hLogEvent); + ReleaseHandle(loggingContext.hFinishedEvent); + + // If there was a log message left, try to log it locally. + if (loggingContext.sczBuffer) + { + LogStringWorkRaw(loggingContext.sczBuffer); + + ReleaseStr(loggingContext.sczBuffer); + } + if (hLock) { ::ReleaseMutex(hLock); @@ -883,54 +927,180 @@ static HRESULT DAPI RedirectLoggingOverPipe( __in_opt LPVOID pvContext ) { - static BOOL s_fCurrentlyLoggingToPipe = FALSE; + HRESULT hr = S_OK; + REDIRECTED_LOGGING_CONTEXT* pContext = static_cast(pvContext); + + ::EnterCriticalSection(&pContext->csBuffer); + + hr = StrAnsiAllocConcat(&pContext->sczBuffer, szString, 0); + + if (SUCCEEDED(hr) && !::SetEvent(pContext->hLogEvent)) + { + HRESULT hrSet = HRESULT_FROM_WIN32(::GetLastError()); + if (FAILED(hrSet)) + { + TraceError(hrSet, "Failed to set log event."); + } + } + + ::LeaveCriticalSection(&pContext->csBuffer); + return hr; +} + +static HRESULT LogStringOverPipe( + __in_z LPCSTR szString, + __in HANDLE hPipe + ) +{ HRESULT hr = S_OK; - BURN_ENGINE_STATE* pEngineState = static_cast(pvContext); - BOOL fStartedLogging = FALSE; - HANDLE hPipe = INVALID_HANDLE_VALUE; BYTE* pbData = NULL; SIZE_T cbData = 0; DWORD dwResult = 0; - // Prevent this function from being called recursively. - if (s_fCurrentlyLoggingToPipe) - { - ExitFunction(); - } + hr = BuffWriteStringAnsi(&pbData, &cbData, szString); + ExitOnFailure(hr, "Failed to prepare logging pipe message."); + + hr = PipeSendMessage(hPipe, static_cast(BURN_PIPE_MESSAGE_TYPE_LOG), pbData, cbData, NULL, NULL, &dwResult); + ExitOnFailure(hr, "Failed to send logging message over the pipe."); + + hr = (HRESULT)dwResult; + +LExit: + ReleaseBuffer(pbData); - s_fCurrentlyLoggingToPipe = TRUE; - fStartedLogging = TRUE; + return hr; +} + +static DWORD WINAPI ElevatedLoggingThreadProc( + __in LPVOID lpThreadParameter + ) +{ + HRESULT hr = S_OK; + DWORD dwLastError = ERROR_SUCCESS; + REDIRECTED_LOGGING_CONTEXT* pContext = static_cast(lpThreadParameter); + DWORD dwSignaledIndex = 0; + LPSTR sczBuffer = NULL; + BURN_PIPE_RESULT result = { }; + HANDLE rghEvents[2] = + { + pContext->hLogEvent, + pContext->hFinishedEvent, + }; - // Make sure the current thread set the pipe in TLS. - hPipe = ::TlsGetValue(pEngineState->dwElevatedLoggingTlsId); - if (!hPipe || INVALID_HANDLE_VALUE == hPipe) + for (;;) { - hr = HRESULT_FROM_WIN32(ERROR_PIPE_NOT_CONNECTED); - ExitFunction(); + hr = AppWaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE, &dwSignaledIndex); + if (FAILED(hr)) + { + LogRedirect(NULL, NULL); // reset logging so the next failure gets written locally. + ExitOnFailure(hr, "Failed to wait for log thread events, signaled: %u.", dwSignaledIndex); + } + + if (1 == dwSignaledIndex) + { + LogRedirect(NULL, NULL); // No more messages will be logged over the pipe. + } + + dwLastError = ERROR_SUCCESS; + + ::EnterCriticalSection(&pContext->csBuffer); + + sczBuffer = pContext->sczBuffer; + pContext->sczBuffer = NULL; + + if (0 == dwSignaledIndex && !::ResetEvent(rghEvents[0])) + { + dwLastError = ::GetLastError(); + } + + ::LeaveCriticalSection(&pContext->csBuffer); + + if (ERROR_SUCCESS != dwLastError) + { + LogRedirect(NULL, NULL); // reset logging so the next failure gets written locally. + ExitOnWin32Error(dwLastError, hr, "Failed to reset log event."); + } + + if (sczBuffer) + { + hr = LogStringOverPipe(sczBuffer, pContext->hPipe); + if (FAILED(hr)) + { + LogRedirect(NULL, NULL); // reset logging so the next failure gets written locally. + ExitOnFailure(hr, "Failed to wait log message over pipe."); + } + + ReleaseStr(sczBuffer); + } + + if (1 == dwSignaledIndex) + { + break; + } } - // Do not log or use ExitOnFailure() macro here because they will be discarded - // by the recursive block at the top of this function. - hr = BuffWriteStringAnsi(&pbData, &cbData, szString); - if (SUCCEEDED(hr)) +LExit: + LogRedirect(NULL, NULL); // No more messages will be logged over the pipe. + { - hr = PipeSendMessage(hPipe, static_cast(BURN_PIPE_MESSAGE_TYPE_LOG), pbData, cbData, NULL, NULL, &dwResult); - if (SUCCEEDED(hr)) + HRESULT hrTerminate = PipeTerminateLoggingPipe(pContext->hPipe, hr); + if (FAILED(hrTerminate)) { - hr = (HRESULT)dwResult; + TraceError(hrTerminate, "Failed to terminate logging pipe."); } } -LExit: - ReleaseBuffer(pbData); + // Log the message locally if it failed to go over the pipe. + if (sczBuffer) + { + LogStringWorkRaw(sczBuffer); + + ReleaseStr(sczBuffer); + } + + // Log any remaining message locally. + if (pContext->sczBuffer) + { + AssertSz(FAILED(hr), "Exiting logging thread on success even though there was a leftover message"); + LogStringWorkRaw(pContext->sczBuffer); + + ReleaseStr(pContext->sczBuffer); + } + + return (DWORD)hr; +} + +static HRESULT WaitForElevatedLoggingThread( + __in REDIRECTED_LOGGING_CONTEXT* pContext, + __in HANDLE hLoggingThread + ) +{ + HRESULT hr = S_OK; - // We started logging so remember to say we are no longer logging. - if (fStartedLogging) + if (!::SetEvent(pContext->hFinishedEvent)) { - s_fCurrentlyLoggingToPipe = FALSE; + ExitWithLastError(hr, "Failed to set log finished event."); } + hr = AppWaitForSingleObject(hLoggingThread, 5 * 60 * 1000); // TODO: is 5 minutes good? + ExitOnFailure(hr, "Failed to wait for elevated logging thread."); + +LExit: + return hr; +} + +static HRESULT WaitForUnelevatedLoggingThread( + __in HANDLE hUnelevatedLoggingThread + ) +{ + HRESULT hr = S_OK; + + // Give the thread 15 seconds to exit. + hr = AppWaitForSingleObject(hUnelevatedLoggingThread, 15 * 1000); + ExitOnFailure(hr, "Failed to wait for unelevated logging thread."); + +LExit: return hr; } diff --git a/src/burn/engine/pipe.cpp b/src/burn/engine/pipe.cpp index 9529ef40..19bdcaa2 100644 --- a/src/burn/engine/pipe.cpp +++ b/src/burn/engine/pipe.cpp @@ -8,6 +8,7 @@ static const DWORD PIPE_RETRY_FOR_CONNECTION = 1800; // for up to 3 minutes. static const LPCWSTR PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls"; static const LPCWSTR CACHE_PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls.Cache"; +static const LPCWSTR LOGGING_PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls.Log"; static HRESULT AllocatePipeMessage( __in DWORD dwMessage, @@ -48,6 +49,7 @@ void PipeConnectionInitialize( memset(pConnection, 0, sizeof(BURN_PIPE_CONNECTION)); pConnection->hPipe = INVALID_HANDLE_VALUE; pConnection->hCachePipe = INVALID_HANDLE_VALUE; + pConnection->hLoggingPipe = INVALID_HANDLE_VALUE; } /******************************************************************* @@ -58,15 +60,14 @@ void PipeConnectionUninitialize( __in BURN_PIPE_CONNECTION* pConnection ) { + ReleaseFileHandle(pConnection->hLoggingPipe); ReleaseFileHandle(pConnection->hCachePipe); ReleaseFileHandle(pConnection->hPipe); ReleaseHandle(pConnection->hProcess); ReleaseStr(pConnection->sczSecret); ReleaseStr(pConnection->sczName); - memset(pConnection, 0, sizeof(BURN_PIPE_CONNECTION)); - pConnection->hPipe = INVALID_HANDLE_VALUE; - pConnection->hCachePipe = INVALID_HANDLE_VALUE; + PipeConnectionInitialize(pConnection); } /******************************************************************* @@ -235,13 +236,13 @@ LExit: *******************************************************************/ extern "C" HRESULT PipeCreatePipes( __in BURN_PIPE_CONNECTION* pConnection, - __in BOOL fCreateCachePipe, - __out HANDLE* phEvent + __in BOOL fCompanion ) { Assert(pConnection->sczName); Assert(INVALID_HANDLE_VALUE == pConnection->hPipe); Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe); + Assert(INVALID_HANDLE_VALUE == pConnection->hLoggingPipe); HRESULT hr = S_OK; PSECURITY_DESCRIPTOR psd = NULL; @@ -249,10 +250,10 @@ extern "C" HRESULT PipeCreatePipes( LPWSTR sczFullPipeName = NULL; HANDLE hPipe = INVALID_HANDLE_VALUE; HANDLE hCachePipe = INVALID_HANDLE_VALUE; + HANDLE hLoggingPipe = INVALID_HANDLE_VALUE; - // Only the grant special rights when the pipe is being used for "embedded" - // scenarios (aka: there is no cache pipe). - if (!fCreateCachePipe) + // Only grant special rights when the pipe is being used for "embedded" scenarios. + if (!fCompanion) { // Create the security descriptor that grants read/write/sync access to Everyone. // TODO: consider locking down "WD" to LogonIds (logon session) @@ -278,7 +279,7 @@ extern "C" HRESULT PipeCreatePipes( ExitWithLastError(hr, "Failed to create pipe: %ls", sczFullPipeName); } - if (fCreateCachePipe) + if (fCompanion) { // Create the cache pipe. hr = StrAllocFormatted(&sczFullPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName); @@ -287,20 +288,31 @@ extern "C" HRESULT PipeCreatePipes( hCachePipe = ::CreateNamedPipeW(sczFullPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, PIPE_64KB, PIPE_64KB, 1, NULL); if (INVALID_HANDLE_VALUE == hCachePipe) { - ExitWithLastError(hr, "Failed to create pipe: %ls", sczFullPipeName); + ExitWithLastError(hr, "Failed to create cache pipe: %ls", sczFullPipeName); + } + + // Create the logging pipe. + hr = StrAllocFormatted(&sczFullPipeName, LOGGING_PIPE_NAME_FORMAT_STRING, pConnection->sczName); + ExitOnFailure(hr, "Failed to allocate full name of logging pipe: %ls", pConnection->sczName); + + hLoggingPipe = ::CreateNamedPipeW(sczFullPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, PIPE_64KB, PIPE_64KB, 1, NULL); + if (INVALID_HANDLE_VALUE == hLoggingPipe) + { + ExitWithLastError(hr, "Failed to create logging pipe: %ls", sczFullPipeName); } } + pConnection->hLoggingPipe = hLoggingPipe; + hLoggingPipe = INVALID_HANDLE_VALUE; + pConnection->hCachePipe = hCachePipe; hCachePipe = INVALID_HANDLE_VALUE; pConnection->hPipe = hPipe; hPipe = INVALID_HANDLE_VALUE; - // TODO: remove the following - *phEvent = NULL; - LExit: + ReleaseFileHandle(hLoggingPipe); ReleaseFileHandle(hCachePipe); ReleaseFileHandle(hPipe); ReleaseStr(sczFullPipeName); @@ -322,7 +334,7 @@ extern "C" HRESULT PipeWaitForChildConnect( ) { HRESULT hr = S_OK; - HANDLE hPipes[2] = { pConnection->hPipe, pConnection->hCachePipe}; + HANDLE hPipes[3] = { pConnection->hPipe, pConnection->hCachePipe, pConnection->hLoggingPipe}; LPCWSTR wzSecret = pConnection->sczSecret; DWORD cbSecret = lstrlenW(wzSecret) * sizeof(WCHAR); DWORD dwCurrentProcessId = ::GetCurrentProcessId(); @@ -409,6 +421,32 @@ LExit: return hr; } +/******************************************************************* + PipeTerminateLoggingPipe - + +*******************************************************************/ +extern "C" HRESULT PipeTerminateLoggingPipe( + __in HANDLE hLoggingPipe, + __in DWORD dwParentExitCode + ) +{ + HRESULT hr = S_OK; + BYTE* pbData = NULL; + SIZE_T cbData = 0; + + // Prepare the exit message. + hr = BuffWriteNumber(&pbData, &cbData, dwParentExitCode); + ExitOnFailure(hr, "Failed to write exit code to message buffer."); + + hr = WritePipeMessage(hLoggingPipe, static_cast(BURN_PIPE_MESSAGE_TYPE_COMPLETE), pbData, cbData); + ExitOnFailure(hr, "Failed to post complete message to logging pipe."); + +LExit: + ReleaseBuffer(pbData); + + return hr; +} + /******************************************************************* PipeTerminateChildProcess - @@ -468,6 +506,8 @@ extern "C" HRESULT PipeTerminateChildProcess( #endif LExit: + ReleaseBuffer(pbData); + return hr; } @@ -478,7 +518,7 @@ LExit: *******************************************************************/ extern "C" HRESULT PipeChildConnect( __in BURN_PIPE_CONNECTION* pConnection, - __in BOOL fConnectCachePipe + __in BOOL fCompanion ) { Assert(pConnection->sczName); @@ -486,6 +526,7 @@ extern "C" HRESULT PipeChildConnect( Assert(!pConnection->hProcess); Assert(INVALID_HANDLE_VALUE == pConnection->hPipe); Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe); + Assert(INVALID_HANDLE_VALUE == pConnection->hLoggingPipe); HRESULT hr = S_OK; LPWSTR sczPipeName = NULL; @@ -519,7 +560,7 @@ extern "C" HRESULT PipeChildConnect( hr = ChildPipeConnected(pConnection->hPipe, pConnection->sczSecret, &pConnection->dwProcessId); ExitOnFailure(hr, "Failed to verify parent pipe: %ls", sczPipeName); - if (fConnectCachePipe) + if (fCompanion) { // Connect to the parent for the cache pipe. hr = StrAllocFormatted(&sczPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName); @@ -528,12 +569,26 @@ extern "C" HRESULT PipeChildConnect( pConnection->hCachePipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (INVALID_HANDLE_VALUE == pConnection->hCachePipe) { - ExitWithLastError(hr, "Failed to open parent pipe: %ls", sczPipeName) + ExitWithLastError(hr, "Failed to open parent cache pipe: %ls", sczPipeName) } // Verify the parent and notify it that the child connected. hr = ChildPipeConnected(pConnection->hCachePipe, pConnection->sczSecret, &pConnection->dwProcessId); - ExitOnFailure(hr, "Failed to verify parent pipe: %ls", sczPipeName); + ExitOnFailure(hr, "Failed to verify parent cache pipe: %ls", sczPipeName); + + // Connect to the parent for the logging pipe. + hr = StrAllocFormatted(&sczPipeName, LOGGING_PIPE_NAME_FORMAT_STRING, pConnection->sczName); + ExitOnFailure(hr, "Failed to allocate name of parent logging pipe."); + + pConnection->hLoggingPipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (INVALID_HANDLE_VALUE == pConnection->hLoggingPipe) + { + ExitWithLastError(hr, "Failed to open parent logging pipe: %ls", sczPipeName) + } + + // Verify the parent and notify it that the child connected. + hr = ChildPipeConnected(pConnection->hLoggingPipe, pConnection->sczSecret, &pConnection->dwProcessId); + ExitOnFailure(hr, "Failed to verify parent logging pipe: %ls", sczPipeName); } pConnection->hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, pConnection->dwProcessId); diff --git a/src/burn/engine/pipe.h b/src/burn/engine/pipe.h index f2d8070e..6571c0e2 100644 --- a/src/burn/engine/pipe.h +++ b/src/burn/engine/pipe.h @@ -15,6 +15,7 @@ typedef struct _BURN_PIPE_CONNECTION HANDLE hProcess; HANDLE hPipe; HANDLE hCachePipe; + HANDLE hLoggingPipe; } BURN_PIPE_CONNECTION; typedef enum _BURN_PIPE_MESSAGE_TYPE : DWORD @@ -77,12 +78,15 @@ HRESULT PipeCreateNameAndSecret( ); HRESULT PipeCreatePipes( __in BURN_PIPE_CONNECTION* pConnection, - __in BOOL fCreateCachePipe, - __out HANDLE* phEvent + __in BOOL fCompanion ); HRESULT PipeWaitForChildConnect( __in BURN_PIPE_CONNECTION* pConnection ); +HRESULT PipeTerminateLoggingPipe( + __in HANDLE hLoggingPipe, + __in DWORD dwParentExitCode + ); HRESULT PipeTerminateChildProcess( __in BURN_PIPE_CONNECTION* pConnection, __in DWORD dwParentExitCode, @@ -92,7 +96,7 @@ HRESULT PipeTerminateChildProcess( // Child functions. HRESULT PipeChildConnect( __in BURN_PIPE_CONNECTION* pConnection, - __in BOOL fConnectCachePipe + __in BOOL fCompanion ); #ifdef __cplusplus diff --git a/src/burn/engine/uithread.cpp b/src/burn/engine/uithread.cpp index fe1c21b8..26a9b723 100644 --- a/src/burn/engine/uithread.cpp +++ b/src/burn/engine/uithread.cpp @@ -107,18 +107,6 @@ static DWORD WINAPI ThreadProc( BURN_ENGINE_STATE* pEngineState = pContext->pEngineState; BOOL fElevatedEngine = BURN_MODE_ELEVATED == pContext->pEngineState->internalCommand.mode; - // If elevated, set up the thread local storage to store the correct pipe to communicate logging. - if (fElevatedEngine) - { - Assert(TLS_OUT_OF_INDEXES != pEngineState->dwElevatedLoggingTlsId); - - if (!::TlsSetValue(pEngineState->dwElevatedLoggingTlsId, pEngineState->companionConnection.hPipe)) - { - // If the function failed we cannot write to the pipe so just terminate. - ExitFunction1(hr = E_INVALIDSTATE); - } - } - wc.lpfnWndProc = WndProc; wc.hInstance = pContext->hInstance; wc.lpszClassName = BURN_UITHREAD_CLASS_WINDOW; -- cgit v1.2.3-55-g6feb