You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
609 lines
17 KiB
609 lines
17 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sxsmain.cpp
|
|
|
|
Abstract:
|
|
|
|
Author:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "stdinc.h"
|
|
#include <windows.h>
|
|
#include "sxsp.h"
|
|
#include "fusioneventlog.h"
|
|
#include "fusiontrace.h"
|
|
#include "fusionsha1.h"
|
|
|
|
extern CRITICAL_SECTION g_csHashFile;
|
|
|
|
//
|
|
// This typedef of a function represents a dll-main startup function. These are
|
|
// called during a DLL_PROCESS_ATTACH call to SxsDllMain in the order they're listed.
|
|
//
|
|
typedef BOOL (WINAPI *PFNStartupPointer)(
|
|
HINSTANCE hDllInstnace,
|
|
DWORD dwReason,
|
|
PVOID pvReason
|
|
);
|
|
|
|
BOOL WINAPI DllStartup_CrtInit(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
|
|
BOOL WINAPI FusionpEventLogMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
|
|
BOOL WINAPI DllStartup_HeapSetup(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
|
|
BOOL WINAPI DllStartup_ActCtxContributors(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
|
|
BOOL WINAPI FusionpCryptoContext_DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
|
|
BOOL WINAPI DllStartup_AtExitList(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
|
|
BOOL WINAPI DllStartup_AlternateAssemblyStoreRoot(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
|
|
BOOL WINAPI DllStartup_SetupLog(HINSTANCE Module, DWORD Reason, PVOID Reserved);
|
|
BOOL WINAPI DllStartup_FileHashCriticalSectionInitialization(HINSTANCE Module, DWORD Reason, PVOID Reserved);
|
|
BOOL WINAPI FusionpAreWeInOSSetupModeMain(HINSTANCE Module, DWORD Reason, PVOID Reserved);
|
|
|
|
#define MAKE_STARTUP_RECORD(f) { &f, L#f }
|
|
|
|
#define SXSP_DLLMAIN_ATTACHED 0x01
|
|
|
|
const struct StartupFunctionRecord {
|
|
PFNStartupPointer Handler;
|
|
PCWSTR Name;
|
|
} g_SxspDllMainStartupPointers[] = {
|
|
MAKE_STARTUP_RECORD(DllStartup_CrtInit),
|
|
MAKE_STARTUP_RECORD(DllStartup_HeapSetup),
|
|
MAKE_STARTUP_RECORD(FusionpEventLogMain),
|
|
MAKE_STARTUP_RECORD(DllStartup_AtExitList),
|
|
MAKE_STARTUP_RECORD(DllStartup_AlternateAssemblyStoreRoot),
|
|
MAKE_STARTUP_RECORD(DllStartup_ActCtxContributors),
|
|
MAKE_STARTUP_RECORD(FusionpCryptoContext_DllMain),
|
|
MAKE_STARTUP_RECORD(DllStartup_SetupLog),
|
|
MAKE_STARTUP_RECORD(DllStartup_FileHashCriticalSectionInitialization),
|
|
MAKE_STARTUP_RECORD(FusionpAreWeInOSSetupModeMain)
|
|
};
|
|
|
|
BYTE g_SxspDllMainStartupStatus[NUMBER_OF(g_SxspDllMainStartupPointers)];
|
|
|
|
HINSTANCE g_hInstance;
|
|
|
|
/*
|
|
NTRAID#NTBUG9-591174-2002/03/31-JayKrell
|
|
Replace all SLists with criticalsection and CDeque.
|
|
*/
|
|
SLIST_HEADER sxspAtExitList;
|
|
|
|
PCWSTR g_AlternateAssemblyStoreRoot;
|
|
BOOL g_WriteRegistryAnyway;
|
|
|
|
#if DBG
|
|
PCSTR
|
|
FusionpDllMainReasonToString(DWORD Reason)
|
|
{
|
|
PCSTR String;
|
|
|
|
String =
|
|
(Reason == DLL_THREAD_ATTACH) ? "DLL_THREAD_ATTACH" :
|
|
(Reason == DLL_THREAD_DETACH) ? "DLL_THREAD_DETACH" :
|
|
(Reason == DLL_PROCESS_ATTACH) ? "DLL_PROCESS_ATTACH" :
|
|
(Reason == DLL_PROCESS_DETACH) ? "DLL_PROCESS_DETACH" :
|
|
"";
|
|
|
|
return String;
|
|
}
|
|
#endif
|
|
|
|
extern "C"
|
|
BOOL
|
|
WINAPI
|
|
SxsDllMain(
|
|
HINSTANCE hInst,
|
|
DWORD dwReason,
|
|
PVOID pvReserved
|
|
)
|
|
//
|
|
// We do not call DisableThreadLibraryCalls
|
|
// because some/all versions of the CRT do work in the thread calls,
|
|
// allocation and free of the per thread data.
|
|
//
|
|
{
|
|
//
|
|
// Several "oca" (online crash analysis) bugs show
|
|
// Sxs.dll in various places in DllMain(process_detach) in hung apps.
|
|
// We load in many processes for oleaut/typelibrary support.
|
|
//
|
|
// When ExitProcess is called, it is impossible to leak memory and kernel handles,
|
|
// so it is sufficient and preferrable to do nothing quickly than to go through
|
|
// and free each individual resource.
|
|
//
|
|
// The pvReserved parameter is actually documented as having a meaning.
|
|
// Its NULLness indicates if we are in FreeLibrary or ExitProcess.
|
|
//
|
|
if (dwReason == DLL_PROCESS_DETACH && pvReserved != NULL)
|
|
{
|
|
// For ExitProcess, do nothing quickly.
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL fResult = FALSE;
|
|
SIZE_T nCounter = 0;
|
|
|
|
#if DBG
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_VERBOSE,
|
|
"SXS: 0x%lx.0x%lx, %s() %s\n",
|
|
GetCurrentProcessId(),
|
|
GetCurrentThreadId(),
|
|
__FUNCTION__,
|
|
FusionpDllMainReasonToString(dwReason));
|
|
#endif
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_THREAD_ATTACH:
|
|
if (!g_SxspDllMainStartupPointers[0].Handler(hInst, dwReason, pvReserved))
|
|
{
|
|
const DWORD dwLastError = ::FusionpGetLastWin32Error();
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS: %s - %ls(DLL_THREAD_ATTACH) failed. Last WinError 0x%08x (%d).\n",
|
|
__FUNCTION__,
|
|
g_SxspDllMainStartupPointers[0].Name,
|
|
dwLastError,
|
|
dwLastError);
|
|
|
|
::SxsDllMain(hInst, DLL_THREAD_DETACH, pvReserved);
|
|
|
|
::FusionpSetLastWin32Error(dwLastError);
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
case DLL_THREAD_DETACH:
|
|
if (!g_SxspDllMainStartupPointers[0].Handler(hInst, dwReason, pvReserved))
|
|
{
|
|
const DWORD dwLastError = ::FusionpGetLastWin32Error();
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS: %s - %ls(DLL_THREAD_ATTACH) failed. Last WinError 0x%08x (%d).\n",
|
|
__FUNCTION__,
|
|
g_SxspDllMainStartupPointers[0].Name,
|
|
dwLastError,
|
|
dwLastError);
|
|
// Eat the error, the loader ignores it.
|
|
}
|
|
break;
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
ASSERT_NTC(hInst);
|
|
g_hInstance = hInst;
|
|
|
|
for (nCounter = 0; nCounter != NUMBER_OF(g_SxspDllMainStartupPointers) ; ++nCounter)
|
|
{
|
|
const SIZE_T nIndex = nCounter;
|
|
if (g_SxspDllMainStartupPointers[nIndex].Handler(hInst, dwReason, pvReserved))
|
|
{
|
|
g_SxspDllMainStartupStatus[nIndex] |= SXSP_DLLMAIN_ATTACHED;
|
|
}
|
|
else
|
|
{
|
|
const DWORD dwLastError = ::FusionpGetLastWin32Error();
|
|
//
|
|
// It's a little iffy to set the bit even upon failure, but
|
|
// we do this because we assume individual functions do not handle
|
|
// rollback internally upon attach failure.
|
|
//
|
|
g_SxspDllMainStartupStatus[nIndex] |= SXSP_DLLMAIN_ATTACHED;
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS: %s - %ls(DLL_PROCESS_ATTACH) failed. Last WinError 0x%08x (%d).\n",
|
|
__FUNCTION__,
|
|
g_SxspDllMainStartupPointers[nIndex].Name,
|
|
dwLastError,
|
|
dwLastError);
|
|
|
|
// pvReserved has approximately the same defined meaning for attach and detach
|
|
::SxsDllMain(hInst, DLL_PROCESS_DETACH, pvReserved);
|
|
|
|
::FusionpSetLastWin32Error(dwLastError);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
//
|
|
// We always succeed DLL_PROCESS_DETACH, and we do not
|
|
// short circuit it upon failure. The loader in fact
|
|
// ignores what we return.
|
|
//
|
|
for (nCounter = NUMBER_OF(g_SxspDllMainStartupPointers) ; nCounter != 0 ; --nCounter)
|
|
{
|
|
const SIZE_T nIndex = nCounter - 1;
|
|
if ((g_SxspDllMainStartupStatus[nIndex] & SXSP_DLLMAIN_ATTACHED) != 0)
|
|
{
|
|
g_SxspDllMainStartupStatus[nIndex] &= ~SXSP_DLLMAIN_ATTACHED;
|
|
if (!g_SxspDllMainStartupPointers[nIndex].Handler(hInst, dwReason, pvReserved))
|
|
{
|
|
const DWORD dwLastError = ::FusionpGetLastWin32Error();
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS: %s - %ls(DLL_PROCESS_DETACH) failed. Last WinError 0x%08x (%d).\n",
|
|
__FUNCTION__,
|
|
g_SxspDllMainStartupPointers[nIndex].Name,
|
|
dwLastError,
|
|
dwLastError);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
fResult = TRUE;
|
|
Exit:
|
|
return fResult;
|
|
}
|
|
|
|
/*
|
|
NTRAID#NTBUG9-591174-2002/03/31-JayKrell
|
|
Replace all SLists with criticalsection and CDeque.
|
|
*/
|
|
BOOL
|
|
SxspAtExit(
|
|
CCleanupBase* pCleanup
|
|
)
|
|
{
|
|
if (!pCleanup->m_fInAtExitList)
|
|
{
|
|
SxspInterlockedPushEntrySList(&sxspAtExitList, pCleanup);
|
|
pCleanup->m_fInAtExitList = true;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
NTRAID#NTBUG9-591174-2002/03/31-JayKrell
|
|
Replace all SLists with criticalsection and CDeque.
|
|
*/
|
|
BOOL
|
|
SxspTryCancelAtExit(
|
|
CCleanupBase* pCleanup
|
|
)
|
|
{
|
|
if (!pCleanup->m_fInAtExitList)
|
|
return FALSE;
|
|
|
|
if (::SxspIsSListEmpty(&sxspAtExitList))
|
|
{
|
|
pCleanup->m_fInAtExitList = false;
|
|
return FALSE;
|
|
}
|
|
|
|
PSLIST_ENTRY pTop = ::SxspInterlockedPopEntrySList(&sxspAtExitList);
|
|
if (pTop == pCleanup)
|
|
{
|
|
pCleanup->m_fInAtExitList = false;
|
|
return TRUE;
|
|
}
|
|
|
|
if (pTop != NULL)
|
|
::SxspInterlockedPushEntrySList(&sxspAtExitList, pTop);
|
|
return FALSE;
|
|
}
|
|
|
|
#define COMMON_HANDLER_PROLOG(dwReason) \
|
|
{ \
|
|
ASSERT_NTC(\
|
|
(dwReason == DLL_PROCESS_ATTACH) || \
|
|
(dwReason == DLL_PROCESS_DETACH) \
|
|
); \
|
|
if (!(\
|
|
(dwReason == DLL_PROCESS_ATTACH) || \
|
|
(dwReason == DLL_PROCESS_DETACH) \
|
|
)) goto Exit; \
|
|
}
|
|
|
|
BOOL WINAPI
|
|
DllStartup_AtExitList(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
COMMON_HANDLER_PROLOG(dwReason);
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
CCleanupBase *pCleanup = NULL;
|
|
while (pCleanup = UNCHECKED_DOWNCAST<CCleanupBase*>(SxspPopEntrySList(&sxspAtExitList)))
|
|
{
|
|
pCleanup->m_fInAtExitList = false;
|
|
pCleanup->DeleteYourself();
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
}
|
|
break;
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
::SxspInitializeSListHead(&sxspAtExitList);
|
|
fSuccess = TRUE;
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
|
|
BOOL g_fInCrtInit;
|
|
|
|
//
|
|
// This is the internal CRT routine that does the bulk of
|
|
// the initialization and uninitialization.
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
_CRT_INIT(
|
|
HINSTANCE hDllInstnace,
|
|
DWORD dwReason,
|
|
PVOID pvReason
|
|
);
|
|
|
|
void
|
|
SxspCrtRaiseExit(
|
|
PCSTR pszCaller,
|
|
int crtError
|
|
)
|
|
//
|
|
// all the various CRT functions that end up calling ExitProcess end up here
|
|
// see crt0dat.c
|
|
//
|
|
{
|
|
const static struct
|
|
{
|
|
NTSTATUS ntstatus;
|
|
PCSTR psz;
|
|
} rgErrors[] =
|
|
{
|
|
{ STATUS_FATAL_APP_EXIT, "STATUS_FATAL_APP_EXIT" },
|
|
{ STATUS_DLL_INIT_FAILED, "STATUS_DLL_INIT_FAILED" },
|
|
};
|
|
const ULONG nInCrtInit = g_fInCrtInit ? 1 : 0;
|
|
|
|
//
|
|
// if (!g_fInCrtInit), then throwing STATUS_DLL_INIT_FAILED is dubious,
|
|
// but there no clearly good answer, maybe STATUS_NO_MEMORY, maybe introduce
|
|
// an NTSTATUS facility to wrap the values in.
|
|
//
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS: [0x%lx.0x%lx] %s(crtError:%d, g_fInCrtInit:%s) calling RaiseException(%08lx %s)\n",
|
|
GetCurrentProcessId(),
|
|
GetCurrentThreadId(),
|
|
pszCaller,
|
|
crtError,
|
|
nInCrtInit ? "true" : "false",
|
|
rgErrors[nInCrtInit].ntstatus,
|
|
rgErrors[nInCrtInit].psz
|
|
);
|
|
::RaiseException(
|
|
static_cast<DWORD>(rgErrors[nInCrtInit].ntstatus),
|
|
0, // flags
|
|
0, // number of extra parameters
|
|
NULL); // extra parameters
|
|
//
|
|
// RaiseException returns void, and generally doesn't return, though it
|
|
// can if you intervene in a debugger.
|
|
//
|
|
}
|
|
|
|
extern void (__cdecl * _aexit_rtn)(int);
|
|
|
|
void
|
|
__cdecl
|
|
SxsCrtAExitRoutine(
|
|
int crtError
|
|
)
|
|
//
|
|
// This is our replacement for an internal CRT routine that otherwise
|
|
// calls ExitProcess.
|
|
//
|
|
{
|
|
SxspCrtRaiseExit(__FUNCTION__, crtError);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
NTRAID#NTBUG9-591174-2002/03/31-JayKrell
|
|
It'd be nice if we could just use msvcrt.dll without this hacking..
|
|
*/
|
|
BOOL WINAPI
|
|
DllStartup_CrtInit(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
|
|
/*
|
|
This mess is because
|
|
we need destructors to run, even if there is an exception
|
|
the startup code in msvcrt.dll and libcmt.lib is not very good
|
|
it tends to call MessageBox and/or ExitProcess upon out of memory
|
|
we need it to simply propagate an error
|
|
*/
|
|
{
|
|
#if !FUSION_WIN
|
|
//
|
|
// having this do-nothing function makes our DLL_THREAD_ATTACH handling simpler.
|
|
//
|
|
return TRUE;
|
|
#else
|
|
BOOL fSuccess = FALSE;
|
|
DWORD dwExceptionCode = 0;
|
|
|
|
__try
|
|
{
|
|
__try
|
|
{
|
|
g_fInCrtInit = TRUE;
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
_aexit_rtn = SxsCrtAExitRoutine;
|
|
//
|
|
// __app_type and __error_mode determine if
|
|
// _CRT_INIT calls MessageBox or WriteFile(GetStdHandle()) upon errors.
|
|
// MessageBox is a big nono in csrss.
|
|
// WriteFile we expect to fail, but that's ok, and they don't check
|
|
// the return value.
|
|
//
|
|
// It should be sufficient to set __error_mode.
|
|
//
|
|
_set_error_mode(_OUT_TO_STDERR);
|
|
}
|
|
fSuccess = _CRT_INIT(hInstance, dwReason, pvReserved);
|
|
}
|
|
__finally
|
|
{
|
|
g_fInCrtInit = FALSE;
|
|
}
|
|
}
|
|
__except(
|
|
( (dwExceptionCode = GetExceptionCode()) == STATUS_DLL_INIT_FAILED
|
|
|| dwExceptionCode == STATUS_FATAL_APP_EXIT
|
|
)
|
|
? EXCEPTION_EXECUTE_HANDLER
|
|
: EXCEPTION_CONTINUE_SEARCH)
|
|
{
|
|
}
|
|
return fSuccess;
|
|
#endif // FUSION_WIN
|
|
}
|
|
|
|
BOOL WINAPI
|
|
DllStartup_HeapSetup(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
COMMON_HANDLER_PROLOG(dwReason);
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
fSuccess = FusionpInitializeHeap(hInstance);
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
#if defined(FUSION_DEBUG_HEAP)
|
|
::FusionpDumpHeap(L"");
|
|
#endif
|
|
::FusionpUninitializeHeap();
|
|
fSuccess = TRUE;
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
DllStartup_ActCtxContributors(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
COMMON_HANDLER_PROLOG(dwReason);
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
fSuccess = SxspInitActCtxContributors();
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
SxspUninitActCtxContributors();
|
|
fSuccess = TRUE;
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllStartup_AlternateAssemblyStoreRoot(HINSTANCE, DWORD dwReason, PVOID pvReserved)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
COMMON_HANDLER_PROLOG(dwReason);
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_DETACH:
|
|
if (g_AlternateAssemblyStoreRoot != NULL)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
delete[] const_cast<PWSTR>(g_AlternateAssemblyStoreRoot);
|
|
g_AlternateAssemblyStoreRoot = NULL;
|
|
ple.Restore();
|
|
}
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
g_AlternateAssemblyStoreRoot = NULL;
|
|
fSuccess = TRUE;
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllStartup_FileHashCriticalSectionInitialization(
|
|
HINSTANCE hInstance,
|
|
DWORD dwReason,
|
|
PVOID pvReserved
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
//
|
|
// We're always called back on disconnect, which isn't really a bug,
|
|
// but a different contract that this can't uphold. Instead, we'll
|
|
// keep rollback information here about whether or not the csec was
|
|
// initialized.
|
|
//
|
|
static BOOL s_fCritSecCreated;
|
|
|
|
COMMON_HANDLER_PROLOG(dwReason);
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_DETACH:
|
|
if (s_fCritSecCreated)
|
|
{
|
|
::DeleteCriticalSection(&g_csHashFile);
|
|
s_fCritSecCreated = FALSE;
|
|
}
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
if (!s_fCritSecCreated)
|
|
{
|
|
if (!::FusionpInitializeCriticalSection(&g_csHashFile))
|
|
goto Exit;
|
|
s_fCritSecCreated = TRUE;
|
|
}
|
|
fSuccess = TRUE;
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|