Bug 1322554: Interpose kernel32!BaseThreadInitThunk to add verification of thread start addresses; r=dmajor
MozReview-Commit-ID: 4Mp9JyE9eat
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -277,16 +277,20 @@ printf_stderr(const char *fmt, ...)
vfprintf(fp, fmt, args);
va_end(args);
fclose(fp);
}
namespace {
+typedef void (__fastcall* BaseThreadInitThunk_func)(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam);
+
+static BaseThreadInitThunk_func stub_BaseThreadInitThunk = nullptr;
+
typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle);
static LdrLoadDll_func stub_LdrLoadDll = 0;
template <class T>
struct RVAMap {
RVAMap(HANDLE map, DWORD offset) {
SYSTEM_INFO info;
@@ -696,17 +700,43 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
continue_loading:
#ifdef DEBUG_very_verbose
printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
#endif
return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
}
+static bool
+ShouldBlockThread(void* aStartAddress, void* aThreadParam)
+{
+ bool shouldBlock = false;
+ MEMORY_BASIC_INFORMATION startAddressInfo;
+ if (VirtualQuery(aStartAddress, &startAddressInfo, sizeof(startAddressInfo))) {
+ shouldBlock |= startAddressInfo.State != MEM_COMMIT;
+ shouldBlock |= startAddressInfo.Protect != PAGE_EXECUTE_READ;
+ shouldBlock |= !(startAddressInfo.Type & MEM_IMAGE);
+ }
+
+ return shouldBlock;
+}
+
+static MOZ_NORETURN void __fastcall
+patched_BaseThreadInitThunk(BOOL aIsInitialThread, void* aStartAddress,
+ void* aThreadParam)
+{
+ if (ShouldBlockThread(aStartAddress, aThreadParam)) {
+ ExitThread(1);
+ }
+
+ stub_BaseThreadInitThunk(aIsInitialThread, aStartAddress, aThreadParam);
+}
+
WindowsDllInterceptor NtDllIntercept;
+WindowsDllInterceptor Kernel32DllIntercept;
} // namespace
MFBT_API void
DllBlocklist_Initialize()
{
if (sBlocklistInitAttempted) {
return;
@@ -732,16 +762,26 @@ DllBlocklist_Initialize()
bool ok = NtDllIntercept.AddDetour("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll);
if (!ok) {
sBlocklistInitFailed = true;
#ifdef DEBUG
printf_stderr("LdrLoadDll hook failed, no dll blocklisting active\n");
#endif
}
+
+ Kernel32DllIntercept.Init("kernel32.dll");
+ ok = Kernel32DllIntercept.AddHook("BaseThreadInitThunk",
+ reinterpret_cast<intptr_t>(patched_BaseThreadInitThunk),
+ (void**) &stub_BaseThreadInitThunk);
+ if (!ok) {
+#ifdef DEBUG
+ printf_stderr("BaseThreadInitThunk hook failed\n");
+#endif
+ }
}
MFBT_API void
DllBlocklist_WriteNotes(HANDLE file)
{
DWORD nBytes;
WriteFile(file, kBlockedDllsParameter, kBlockedDllsParameterLen, &nBytes, nullptr);
--- a/toolkit/xre/test/win/TestDllInterceptor.cpp
+++ b/toolkit/xre/test/win/TestDllInterceptor.cpp
@@ -463,15 +463,16 @@ int main()
TestHook(TestGetOpenFileNameW, "comdlg32.dll", "GetOpenFileNameW") &&
#ifdef _M_X64
TestHook(TestGetKeyState, "user32.dll", "GetKeyState") && // see Bug 1316415
#endif
MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") &&
#ifdef _M_IX86
TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") &&
#endif
+ TestDetour("kernel32.dll", "BaseThreadInitThunk") &&
TestDetour("ntdll.dll", "LdrLoadDll")) {
printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
return 0;
}
return 1;
}