forked from OSchip/llvm-project
[windows] Implement GetProcAddress internally to avoid initializing the CRT
ASan uses GetProcAddress to get the address of malloc so it can patch it. Newer versions of Windows make GetProcAddress initialize the DLL before returning a function pointer into it. That's perfectly reasonable, but ASan needs to finish patching malloc before CRT initialization. So now we roll our own GetProcAddress. Fixes PR24237 Based on a patch by David Major Originally written by David Major as part of: https://hg.mozilla.org/mozilla-central/file/tip/toolkit/xre/WindowsCrtPatch.h llvm-svn: 245377
This commit is contained in:
parent
6dc8d583b9
commit
d85f7010cc
|
@ -30,8 +30,9 @@ void *__stdcall GetProcAddress(void *module, const char *proc_name);
|
|||
void abort();
|
||||
}
|
||||
|
||||
static void *getRealProcAddressOrDie(const char *name) {
|
||||
void *ret = GetProcAddress(GetModuleHandleA(0), name);
|
||||
static uptr getRealProcAddressOrDie(const char *name) {
|
||||
uptr ret =
|
||||
__interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
|
||||
if (!ret)
|
||||
abort();
|
||||
return ret;
|
||||
|
@ -62,13 +63,12 @@ struct FunctionInterceptor<0> {
|
|||
};
|
||||
|
||||
#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
|
||||
template<> struct FunctionInterceptor<__LINE__> { \
|
||||
template <> struct FunctionInterceptor<__LINE__> { \
|
||||
static void Execute() { \
|
||||
void *wrapper = getRealProcAddressOrDie(main_function); \
|
||||
if (!__interception::OverrideFunction((uptr)dll_function, \
|
||||
(uptr)wrapper, 0)) \
|
||||
uptr wrapper = getRealProcAddressOrDie(main_function); \
|
||||
if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \
|
||||
abort(); \
|
||||
FunctionInterceptor<__LINE__-1>::Execute(); \
|
||||
FunctionInterceptor<__LINE__ - 1>::Execute(); \
|
||||
} \
|
||||
};
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static const void **InterestingDLLsAvailable() {
|
||||
static void **InterestingDLLsAvailable() {
|
||||
const char *InterestingDLLs[] = {
|
||||
"kernel32.dll",
|
||||
"msvcr110.dll", // VS2012
|
||||
|
@ -198,14 +198,65 @@ static const void **InterestingDLLsAvailable() {
|
|||
result[j++] = (void *)h;
|
||||
}
|
||||
}
|
||||
return (const void **)&result[0];
|
||||
return &result[0];
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Utility for reading loaded PE images.
|
||||
template <typename T> class RVAPtr {
|
||||
public:
|
||||
RVAPtr(void *module, uptr rva)
|
||||
: ptr_(reinterpret_cast<T *>(reinterpret_cast<char *>(module) + rva)) {}
|
||||
operator T *() { return ptr_; }
|
||||
T *operator->() { return ptr_; }
|
||||
T *operator++() { return ++ptr_; }
|
||||
|
||||
private:
|
||||
T *ptr_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Internal implementation of GetProcAddress. At least since Windows 8,
|
||||
// GetProcAddress appears to initialize DLLs before returning function pointers
|
||||
// into them. This is problematic for the sanitizers, because they typically
|
||||
// want to intercept malloc *before* MSVCRT initializes. Our internal
|
||||
// implementation walks the export list manually without doing initialization.
|
||||
uptr InternalGetProcAddress(void *module, const char *func_name) {
|
||||
// Check that the module header is full and present.
|
||||
RVAPtr<IMAGE_DOS_HEADER> dos_stub(module, 0);
|
||||
RVAPtr<IMAGE_NT_HEADERS> headers(module, dos_stub->e_lfanew);
|
||||
if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ"
|
||||
headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0"
|
||||
headers->FileHeader.SizeOfOptionalHeader <
|
||||
sizeof(IMAGE_OPTIONAL_HEADER)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IMAGE_DATA_DIRECTORY *export_directory =
|
||||
&headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module,
|
||||
export_directory->VirtualAddress);
|
||||
RVAPtr<DWORD> functions(module, exports->AddressOfFunctions);
|
||||
RVAPtr<DWORD> names(module, exports->AddressOfNames);
|
||||
RVAPtr<WORD> ordinals(module, exports->AddressOfNameOrdinals);
|
||||
|
||||
for (DWORD i = 0; i < exports->NumberOfNames; i++) {
|
||||
RVAPtr<char> name(module, names[i]);
|
||||
if (!strcmp(func_name, name)) {
|
||||
DWORD index = ordinals[i];
|
||||
RVAPtr<char> func(module, functions[index]);
|
||||
return (uptr)(char *)func;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
|
||||
*func_addr = 0;
|
||||
const void **DLLs = InterestingDLLsAvailable();
|
||||
void **DLLs = InterestingDLLsAvailable();
|
||||
for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
|
||||
*func_addr = (uptr)GetProcAddress((HMODULE)DLLs[i], func_name);
|
||||
*func_addr = InternalGetProcAddress(DLLs[i], func_name);
|
||||
return (*func_addr != 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0);
|
|||
|
||||
// Overrides a function in a system DLL or DLL CRT by its exported name.
|
||||
bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0);
|
||||
|
||||
// Windows-only replacement for GetProcAddress. Useful for some sanitizers.
|
||||
uptr InternalGetProcAddress(void *module, const char *func_name);
|
||||
|
||||
} // namespace __interception
|
||||
|
||||
#if defined(INTERCEPTION_DYNAMIC_CRT)
|
||||
|
|
Loading…
Reference in New Issue