376 lines
9.7 KiB
C++
376 lines
9.7 KiB
C++
|
/*
|
||
|
|
||
|
Copyright (c) 2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
SMSDeadlock.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
SMS experiences a deadlock due to its loading a module that tries to take
|
||
|
MFC42's AfxResourceLock during DllMain when the LoaderLock is held.
|
||
|
|
||
|
MFC42's established locking-order is FIRST take the AfxResourceLock, and
|
||
|
SECONDLY take the loader lock.
|
||
|
|
||
|
This shim tries to right the order of lock-taking by taking the
|
||
|
AfxResourceLock prior to allowing LoadLibrary and FreeLibrary calls.
|
||
|
Thus the order of lock acquisition is righted.
|
||
|
|
||
|
DLL's for which LoadLibrary takes the Afx lock are specified on the
|
||
|
command line and separated by semi-colons. A blank command line indicates
|
||
|
that ALL modules should take the lock.
|
||
|
|
||
|
NOTE: Every module in a process (including system) should be shimmed by
|
||
|
this shim. The dlls specified in the command line are the TARGETS of
|
||
|
LoadLibrary for which we should take the AfxResource lock. To actually
|
||
|
make that switch no matter who calls LoadLibrary, we must shim all
|
||
|
modules.
|
||
|
|
||
|
History:
|
||
|
|
||
|
09/26/2002 astritz Created
|
||
|
*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
IMPLEMENT_SHIM_BEGIN(SMSDeadlock)
|
||
|
|
||
|
#include "ShimHookMacro.h"
|
||
|
|
||
|
typedef void (AFXAPI * _pfn_AfxLockGlobals)(int nLockType);
|
||
|
typedef void (AFXAPI * _pfn_AfxUnlockGlobals)(int nLockType);
|
||
|
|
||
|
_pfn_AfxLockGlobals g_pfnAfxLockGlobals = NULL;
|
||
|
_pfn_AfxUnlockGlobals g_pfnAfxUnlockGlobals = NULL;
|
||
|
CString * g_csLockLib = NULL;
|
||
|
int g_csLockLibCount = NULL;
|
||
|
|
||
|
APIHOOK_ENUM_BEGIN
|
||
|
APIHOOK_ENUM_ENTRY(LoadLibraryA)
|
||
|
APIHOOK_ENUM_ENTRY(LoadLibraryExA)
|
||
|
APIHOOK_ENUM_ENTRY(LoadLibraryW)
|
||
|
APIHOOK_ENUM_ENTRY(LoadLibraryExW)
|
||
|
APIHOOK_ENUM_ENTRY(FreeLibrary)
|
||
|
APIHOOK_ENUM_END
|
||
|
|
||
|
/*++
|
||
|
|
||
|
This function parses the COMMAND_LINE for the libraries you wish to ignore.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
ParseCommandLine(
|
||
|
LPCSTR lpszCommandLine
|
||
|
)
|
||
|
{
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
DPF(g_szModuleName, eDbgLevelInfo, "[ParseCommandLine] CommandLine(%s)\n", lpszCommandLine);
|
||
|
|
||
|
CString csCl(lpszCommandLine);
|
||
|
CStringParser csParser(csCl, L";");
|
||
|
|
||
|
g_csLockLibCount = csParser.GetCount();
|
||
|
g_csLockLib = csParser.ReleaseArgv();
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
// Do nothing.
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
HINSTANCE
|
||
|
APIHOOK(LoadLibraryA)(
|
||
|
LPCSTR lpLibFileName
|
||
|
)
|
||
|
{
|
||
|
HINSTANCE hRet;
|
||
|
BOOL bTakeLock = FALSE;
|
||
|
|
||
|
if( g_pfnAfxLockGlobals && g_pfnAfxUnlockGlobals ) {
|
||
|
|
||
|
if( g_csLockLibCount == 0 ) {
|
||
|
bTakeLock = TRUE;
|
||
|
} else {
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csFilePath(lpLibFileName);
|
||
|
CString csFileName;
|
||
|
csFilePath.GetLastPathComponent(csFileName);
|
||
|
|
||
|
for (int i = 0; i < g_csLockLibCount; i++)
|
||
|
{
|
||
|
if (g_csLockLib[i].CompareNoCase(csFileName) == 0)
|
||
|
{
|
||
|
LOG(g_szModuleName,eDbgLevelError, "[LoadLibraryA] Caught attempt loading %ls, taking AfxResourceLock.", g_csLockLib[i].Get());
|
||
|
bTakeLock = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
// Do Nothing
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxLockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
hRet = ORIGINAL_API(LoadLibraryA)(lpLibFileName);
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxUnlockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
return hRet;
|
||
|
}
|
||
|
|
||
|
HINSTANCE
|
||
|
APIHOOK(LoadLibraryW)(
|
||
|
LPCWSTR lpLibFileName
|
||
|
)
|
||
|
{
|
||
|
HINSTANCE hRet;
|
||
|
BOOL bTakeLock = FALSE;
|
||
|
|
||
|
if( g_pfnAfxLockGlobals && g_pfnAfxUnlockGlobals ) {
|
||
|
if( g_csLockLibCount == 0 ) {
|
||
|
bTakeLock = TRUE;
|
||
|
} else {
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csFilePath(lpLibFileName);
|
||
|
CString csFileName;
|
||
|
csFilePath.GetLastPathComponent(csFileName);
|
||
|
|
||
|
for (int i = 0; i < g_csLockLibCount; i++)
|
||
|
{
|
||
|
if (g_csLockLib[i].CompareNoCase(csFileName) == 0)
|
||
|
{
|
||
|
LOG(g_szModuleName,eDbgLevelError, "[LoadLibraryW] Caught attempt loading %ls, taking AfxResourceLock.", g_csLockLib[i].Get());
|
||
|
bTakeLock = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
// Do Nothing
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxLockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
hRet = ORIGINAL_API(LoadLibraryW)(lpLibFileName);
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxUnlockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
return hRet;
|
||
|
}
|
||
|
|
||
|
HINSTANCE
|
||
|
APIHOOK(LoadLibraryExA)(
|
||
|
LPCSTR lpLibFileName,
|
||
|
HANDLE hFile,
|
||
|
DWORD dwFlags
|
||
|
)
|
||
|
{
|
||
|
HINSTANCE hRet;
|
||
|
BOOL bTakeLock = FALSE;
|
||
|
|
||
|
if( g_pfnAfxLockGlobals && g_pfnAfxUnlockGlobals ) {
|
||
|
if( g_csLockLibCount == 0 ) {
|
||
|
bTakeLock = TRUE;
|
||
|
} else {
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csFilePath(lpLibFileName);
|
||
|
CString csFileName;
|
||
|
csFilePath.GetLastPathComponent(csFileName);
|
||
|
|
||
|
for (int i = 0; i < g_csLockLibCount; i++)
|
||
|
{
|
||
|
if (g_csLockLib[i].CompareNoCase(csFileName) == 0)
|
||
|
{
|
||
|
LOG(g_szModuleName,eDbgLevelError, "[LoadLibraryExA] Caught attempt loading %ls, taking AfxResourceLock.", g_csLockLib[i].Get());
|
||
|
bTakeLock = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
// Do Nothing
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxLockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
hRet = ORIGINAL_API(LoadLibraryExA)(lpLibFileName, hFile, dwFlags);
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxUnlockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
return hRet;
|
||
|
}
|
||
|
|
||
|
HINSTANCE
|
||
|
APIHOOK(LoadLibraryExW)(
|
||
|
LPCWSTR lpLibFileName,
|
||
|
HANDLE hFile,
|
||
|
DWORD dwFlags
|
||
|
)
|
||
|
{
|
||
|
HINSTANCE hRet;
|
||
|
BOOL bTakeLock = FALSE;
|
||
|
|
||
|
if( g_pfnAfxLockGlobals && g_pfnAfxUnlockGlobals ) {
|
||
|
if( g_csLockLibCount == 0 ) {
|
||
|
bTakeLock = TRUE;
|
||
|
} else {
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csFilePath(lpLibFileName);
|
||
|
CString csFileName;
|
||
|
csFilePath.GetLastPathComponent(csFileName);
|
||
|
|
||
|
for (int i = 0; i < g_csLockLibCount; i++)
|
||
|
{
|
||
|
if (g_csLockLib[i].CompareNoCase(csFileName) == 0)
|
||
|
{
|
||
|
LOG(g_szModuleName,eDbgLevelError, "[LoadLibraryExW] Caught attempt loading %ls, taking AfxResourceLock.", g_csLockLib[i].Get());
|
||
|
bTakeLock = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
// Do Nothing
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxLockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
hRet = ORIGINAL_API(LoadLibraryExW)(lpLibFileName, hFile, dwFlags);
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxUnlockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
return hRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
APIHOOK(FreeLibrary)(
|
||
|
HMODULE hModule
|
||
|
)
|
||
|
{
|
||
|
BOOL bTakeLock = FALSE;
|
||
|
BOOL bRet;
|
||
|
|
||
|
if( g_pfnAfxLockGlobals && g_pfnAfxUnlockGlobals ) {
|
||
|
if( g_csLockLibCount == 0 ) {
|
||
|
bTakeLock = TRUE;
|
||
|
} else {
|
||
|
WCHAR wszModule[MAX_PATH];
|
||
|
|
||
|
if( GetModuleFileNameW(hModule, wszModule, MAX_PATH) ) {
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csFilePath(wszModule);
|
||
|
CString csFileName;
|
||
|
csFilePath.GetLastPathComponent(csFileName);
|
||
|
|
||
|
for (int i = 0; i < g_csLockLibCount; i++)
|
||
|
{
|
||
|
if (g_csLockLib[i].CompareNoCase(csFileName) == 0)
|
||
|
{
|
||
|
LOG(g_szModuleName,eDbgLevelError, "[FreeLibrary] Caught attempt freeing %ls, taking AfxResourceLock.", g_csLockLib[i].Get());
|
||
|
bTakeLock = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
// Do Nothing
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxLockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
bRet = ORIGINAL_API(FreeLibrary)(hModule);
|
||
|
|
||
|
if( bTakeLock ) {
|
||
|
(*g_pfnAfxUnlockGlobals)(0);
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Register hooked functions
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
NOTIFY_FUNCTION(
|
||
|
DWORD fdwReason
|
||
|
)
|
||
|
{
|
||
|
if( fdwReason == DLL_PROCESS_ATTACH )
|
||
|
{
|
||
|
ParseCommandLine(COMMAND_LINE);
|
||
|
}
|
||
|
else if( fdwReason == SHIM_STATIC_DLLS_INITIALIZED )
|
||
|
{
|
||
|
HMODULE hMod = LoadLibraryW(L"MFC42.DLL");
|
||
|
if( NULL != hMod )
|
||
|
{
|
||
|
g_pfnAfxLockGlobals = (_pfn_AfxLockGlobals)GetProcAddress(hMod, (LPCSTR)1196);
|
||
|
g_pfnAfxUnlockGlobals = (_pfn_AfxUnlockGlobals)GetProcAddress(hMod, (LPCSTR)1569);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
HOOK_BEGIN
|
||
|
|
||
|
CALL_NOTIFY_FUNCTION
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, LoadLibraryA)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, LoadLibraryExA)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, LoadLibraryW)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, LoadLibraryExW)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, FreeLibrary)
|
||
|
|
||
|
HOOK_END
|
||
|
|
||
|
IMPLEMENT_SHIM_END
|