Bug 1549797: Remove loader hooks for TestDllBlocklist from mozglue; r=mhowell, a=jcristau
authorAaron Klotz <aklotz@mozilla.com>
Tue, 11 Jun 2019 17:15:20 +0000
changeset 536927 4ff3f4af050df6110825067eef38240126c2274a
parent 536926 bea9c810099f78f3a5867d7e9bd5e7a7f4477bf3
child 536928 f8429b9c6790161fa215e5d340ba05eae544c6de
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmhowell, jcristau
bugs1549797
milestone68.0
Bug 1549797: Remove loader hooks for TestDllBlocklist from mozglue; r=mhowell, a=jcristau We remove the debugging hooks that were added to check to see whether a DLL was loaded, as we can just as easily check that by querying the loader itself. Plus, we shouldn't be exporting a bunch of test-only loader hooks from mozglue in our release builds, which is what we are currently doing. We also remove Injector, InjectorDLL, and TestDLLEject, as these tests can just as easily be done from within TestDllBlocklist by creating a thread with LoadLibrary* as the entry point. The CreateRemoteThread stuff, while a more accurate simulation, has no material effect on whether or not the thread blocking code works. Differential Revision: https://phabricator.services.mozilla.com/D34444
mozglue/build/WindowsDllBlocklist.cpp
mozglue/build/WindowsDllBlocklist.h
mozglue/tests/gtest/Injector/Injector.cpp
mozglue/tests/gtest/Injector/moz.build
mozglue/tests/gtest/InjectorDLL/InjectorDLL.cpp
mozglue/tests/gtest/InjectorDLL/moz.build
mozglue/tests/gtest/TestDLLBlocklist.cpp
mozglue/tests/gtest/TestDLLEject.cpp
mozglue/tests/gtest/moz.build
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -339,91 +339,16 @@ static wchar_t* lastslash(wchar_t* s, in
   for (wchar_t* c = s + len - 1; c >= s; --c) {
     if (*c == L'\\' || *c == L'/') {
       return c;
     }
   }
   return nullptr;
 }
 
-#ifdef ENABLE_TESTS
-DllLoadHookType gDllLoadHook = nullptr;
-
-void DllBlocklist_SetDllLoadHook(DllLoadHookType aHook) {
-  gDllLoadHook = aHook;
-}
-
-void CallDllLoadHook(bool aDllLoaded, NTSTATUS aStatus, HANDLE aDllBase,
-                     PUNICODE_STRING aDllName) {
-  if (gDllLoadHook) {
-    gDllLoadHook(aDllLoaded, aStatus, aDllBase, aDllName);
-  }
-}
-
-CreateThreadHookType gCreateThreadHook = nullptr;
-
-void DllBlocklist_SetCreateThreadHook(CreateThreadHookType aHook) {
-  gCreateThreadHook = aHook;
-}
-
-void CallCreateThreadHook(bool aWasAllowed, void* aStartAddress) {
-  if (gCreateThreadHook) {
-    gCreateThreadHook(aWasAllowed, aStartAddress);
-  }
-}
-
-// This function does the work for gtest TestDllBlocklist.BlocklistIntegrity.
-// If the test fails, the return value is the pointer to a string description
-// of the failure. If the test passes, the return value is nullptr.
-const char* DllBlocklist_TestBlocklistIntegrity() {
-  mozilla::Vector<DLL_BLOCKLIST_STRING_TYPE> dupes;
-  DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(pFirst);
-  DECLARE_POINTER_TO_LAST_DLL_BLOCKLIST_ENTRY(pLast);
-
-  if (pLast->name || pLast->maxVersion || pLast->flags) {
-    return "The last dll blocklist entry must be all-null.";
-  }
-
-  for (size_t i = 0; i < mozilla::ArrayLength(gWindowsDllBlocklist) - 1; ++i) {
-    auto pEntry = pFirst + i;
-
-    // Validate name
-    if (!pEntry->name) {
-      return "A dll blocklist entry contains a null name.";
-    }
-
-    if (strlen(pEntry->name) <= 2) {
-      return "Dll blocklist entry names must be longer than 2 characters.";
-    }
-    // Check the filename for valid characters.
-    for (auto pch = pEntry->name; *pch != 0; ++pch) {
-      if (*pch >= 'A' && *pch <= 'Z') {
-        return "Dll blocklist entry names cannot contain uppercase characters.";
-      }
-    }
-
-    // Check for duplicate entries
-    for (auto dupe : dupes) {
-      if (!stricmp(dupe, pEntry->name)) {
-        return "At least one duplicate dll blocklist entry was found.";
-      }
-    }
-    if (!dupes.append(pEntry->name)) {
-      return "Failed to append to duplicates list; test unable to continue.";
-    }
-  }
-
-  return nullptr;
-}
-
-#else  // ENABLE_TESTS
-#  define CallDllLoadHook(...)
-#  define CallCreateThreadHook(...)
-#endif  // ENABLE_TESTS
-
 static NTSTATUS NTAPI patched_LdrLoadDll(PWCHAR filePath, PULONG flags,
                                          PUNICODE_STRING moduleFileName,
                                          PHANDLE handle) {
   if (IsUntrustedDllsHandlerEnabled()) {
     glue::UntrustedDllsHandler::EnterLoaderCall();
   }
   // Warning: this must be at the top function scope.
   auto exitLoaderCallScopeExit = MakeScopeExit([]() {
@@ -502,28 +427,26 @@ static NTSTATUS NTAPI patched_LdrLoadDll
   if (!(sInitFlags & eDllBlocklistInitFlagWasBootstrapped)) {
     // Block a suspicious binary that uses various 12-digit hex strings
     // e.g. MovieMode.48CA2AEFA22D.dll (bug 973138)
     dot = strchr(dllName, '.');
     if (dot && (strchr(dot + 1, '.') == dot + 13)) {
       char* end = nullptr;
       _strtoui64(dot + 1, &end, 16);
       if (end == dot + 13) {
-        CallDllLoadHook(false, STATUS_DLL_NOT_FOUND, 0, moduleFileName);
         return STATUS_DLL_NOT_FOUND;
       }
     }
     // Block binaries where the filename is at least 16 hex digits
     if (dot && ((dot - dllName) >= 16)) {
       char* current = dllName;
       while (current < dot && isxdigit(*current)) {
         current++;
       }
       if (current == dot) {
-        CallDllLoadHook(false, STATUS_DLL_NOT_FOUND, 0, moduleFileName);
         return STATUS_DLL_NOT_FOUND;
       }
     }
 
     // then compare to everything on the blocklist
     DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(info);
     while (info->name) {
       if (strcmp(info->name, dllName) == 0) break;
@@ -563,17 +486,16 @@ static NTSTATUS NTAPI patched_LdrLoadDll
 
         full_fname = getFullPath(filePath, fname);
         if (!full_fname) {
           // uh, we couldn't find the DLL at all, so...
           printf_stderr(
               "LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find "
               "it?)\n",
               dllName);
-          CallDllLoadHook(false, STATUS_DLL_NOT_FOUND, 0, moduleFileName);
           return STATUS_DLL_NOT_FOUND;
         }
 
         if (info->flags & DllBlockInfo::USE_TIMESTAMP) {
           fVersion = GetTimestamp(full_fname.get());
           if (fVersion > info->maxVersion) {
             load_ok = true;
           }
@@ -604,17 +526,16 @@ static NTSTATUS NTAPI patched_LdrLoadDll
       }
 
       if (!load_ok) {
         printf_stderr(
             "LdrLoadDll: Blocking load of '%s' -- see "
             "http://www.mozilla.com/en-US/blocklist/\n",
             dllName);
         DllBlockSet::Add(info->name, fVersion);
-        CallDllLoadHook(false, STATUS_DLL_NOT_FOUND, 0, moduleFileName);
         return STATUS_DLL_NOT_FOUND;
       }
     }
   }
 
 continue_loading:
 #ifdef DEBUG_very_verbose
   printf_stderr("LdrLoadDll: continuing load... ('%S')\n",
@@ -657,17 +578,16 @@ continue_loading:
   } else {
     ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
   }
 
   if (handle) {
     *handle = myHandle;
   }
 
-  CallDllLoadHook(NT_SUCCESS(ret), ret, handle ? *handle : 0, moduleFileName);
   return ret;
 }
 
 #if defined(NIGHTLY_BUILD)
 // Map of specific thread proc addresses we should block. In particular,
 // LoadLibrary* APIs which indicate DLL injection
 static mozilla::Vector<void*, 4>* gStartAddressesToBlock;
 #endif
@@ -698,20 +618,17 @@ static bool ShouldBlockThread(void* aSta
 
 // Allows blocked threads to still run normally through BaseThreadInitThunk, in
 // case there's any magic there that we shouldn't skip.
 static DWORD WINAPI NopThreadProc(void* /* aThreadParam */) { return 0; }
 
 static MOZ_NORETURN void __fastcall patched_BaseThreadInitThunk(
     BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam) {
   if (ShouldBlockThread(aStartAddress)) {
-    CallCreateThreadHook(false, aStartAddress);
     aStartAddress = (void*)NopThreadProc;
-  } else {
-    CallCreateThreadHook(true, aStartAddress);
   }
 
   stub_BaseThreadInitThunk(aIsInitialThread, aStartAddress, aThreadParam);
 }
 
 static WindowsDllInterceptor NtDllIntercept;
 static WindowsDllInterceptor Kernel32Intercept;
 
--- a/mozglue/build/WindowsDllBlocklist.h
+++ b/mozglue/build/WindowsDllBlocklist.h
@@ -5,19 +5,16 @@
 
 #ifndef mozilla_windowsdllblocklist_h
 #define mozilla_windowsdllblocklist_h
 
 #if (defined(_MSC_VER) || defined(__MINGW32__)) && \
     (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64))
 
 #  include <windows.h>
-#  ifdef ENABLE_TESTS
-#    include <winternl.h>
-#  endif  // ENABLE_TESTS
 #  include "mozilla/Attributes.h"
 #  include "mozilla/Types.h"
 
 #  define HAS_DLL_BLOCKLIST
 
 enum DllBlocklistInitFlags {
   eDllBlocklistInitFlagDefault = 0,
   eDllBlocklistInitFlagIsChildProcess = 1,
@@ -31,25 +28,16 @@ MFBT_API bool DllBlocklist_CheckStatus()
 
 // This export intends to clean up after DllBlocklist_Initialize().
 // It's disabled in release builds for performance and to limit callers' ability
 // to interfere with dll blocking.
 #  ifdef DEBUG
 MFBT_API void DllBlocklist_Shutdown();
 #  endif  // DEBUG
 
-#  ifdef ENABLE_TESTS
-typedef void (*DllLoadHookType)(bool aDllLoaded, NTSTATUS aNtStatus,
-                                HANDLE aDllBase, PUNICODE_STRING aDllName);
-MFBT_API void DllBlocklist_SetDllLoadHook(DllLoadHookType aHook);
-typedef void (*CreateThreadHookType)(bool aWasAllowed, void* aStartAddress);
-MFBT_API void DllBlocklist_SetCreateThreadHook(CreateThreadHookType aHook);
-MFBT_API const char* DllBlocklist_TestBlocklistIntegrity();
-#  endif  // ENABLE_TESTS
-
 // Forward declaration
 namespace mozilla {
 namespace glue {
 namespace detail {
 class DllServicesBase;
 }  // namespace detail
 }  // namespace glue
 }  // namespace mozilla
deleted file mode 100644
--- a/mozglue/tests/gtest/Injector/Injector.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <windows.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char** argv) {
-  if (argc < 4) {
-    fprintf(stderr,
-            "Not enough command line arguments.\n"
-            "Command line syntax:\n"
-            "Injector.exe [pid] [startAddr] [threadParam]\n");
-    return 1;
-  }
-
-  DWORD pid = strtoul(argv[1], 0, 0);
-#ifdef HAVE_64BIT_BUILD
-  void* startAddr = (void*)strtoull(argv[2], 0, 0);
-  void* threadParam = (void*)strtoull(argv[3], 0, 0);
-#else
-  void* startAddr = (void*)strtoul(argv[2], 0, 0);
-  void* threadParam = (void*)strtoul(argv[3], 0, 0);
-#endif
-  HANDLE targetProc =
-      OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
-                      PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
-                  FALSE, pid);
-  if (targetProc == nullptr) {
-    fprintf(stderr, "Error %lu opening target process, PID %lu \n",
-            GetLastError(), pid);
-    return 1;
-  }
-
-  HANDLE hThread = CreateRemoteThread(targetProc, nullptr, 0,
-                                      (LPTHREAD_START_ROUTINE)startAddr,
-                                      threadParam, 0, nullptr);
-  if (hThread == nullptr) {
-    fprintf(stderr, "Error %lu in CreateRemoteThread\n", GetLastError());
-    CloseHandle(targetProc);
-    return 1;
-  }
-
-  CloseHandle(hThread);
-  CloseHandle(targetProc);
-
-  return 0;
-}
deleted file mode 100644
--- a/mozglue/tests/gtest/Injector/moz.build
+++ /dev/null
@@ -1,10 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DIST_INSTALL = False
-
-SimplePrograms(['Injector'])
-
-if CONFIG['COMPILE_ENVIRONMENT']:
-   TEST_HARNESS_FILES.gtest += ['!Injector.exe']
deleted file mode 100644
--- a/mozglue/tests/gtest/InjectorDLL/InjectorDLL.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <windows.h>
-
-BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD aReason, LPVOID) { return TRUE; }
deleted file mode 100644
--- a/mozglue/tests/gtest/InjectorDLL/moz.build
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DIST_INSTALL = False
-
-SharedLibrary('InjectorDLL')
-
-UNIFIED_SOURCES = [
-    'InjectorDLL.cpp',
-]
-
-if CONFIG['COMPILE_ENVIRONMENT']:
-    TEST_HARNESS_FILES.gtest += ['!InjectorDLL.dll']
--- a/mozglue/tests/gtest/TestDLLBlocklist.cpp
+++ b/mozglue/tests/gtest/TestDLLBlocklist.cpp
@@ -1,134 +1,136 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <windows.h>
-#include <shlwapi.h>
 #include <winternl.h>
+
+#include <process.h>
+
 #include "gtest/gtest.h"
-#include "mozilla/ScopeExit.h"
-#include "mozilla/WindowsDllBlocklist.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Char16.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
-#include "nsLiteralString.h"
-#include "nsUnicharUtils.h"
-#include "mozilla/Char16.h"
-
-static bool sDllWasBlocked = false;
-static bool sDllWasLoaded = false;
-static const char16_t* sDllName;
-
-static nsDependentSubstring MakeString(PUNICODE_STRING aOther) {
-  size_t numChars = aOther->Length / sizeof(WCHAR);
-  return nsDependentSubstring((const char16_t*)aOther->Buffer, numChars);
-}
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsWindowsHelpers.h"
 
-static void DllLoadHook(bool aDllLoaded, NTSTATUS aStatus, HANDLE aDllBase,
-                        PUNICODE_STRING aDllName) {
-  nsDependentSubstring str = MakeString(aDllName);
-  if (StringEndsWith(str, nsDependentString(sDllName),
-                     nsCaseInsensitiveStringComparator())) {
-    if (aDllLoaded) {
-      sDllWasLoaded = true;
-    } else {
-      sDllWasBlocked = true;
-    }
-  }
-}
+static nsString GetFullPath(const nsAString& aLeaf) {
+  nsCOMPtr<nsIFile> f;
 
-static nsString GetFullPath(const char16_t* leaf) {
-  nsCOMPtr<nsIFile> f;
   EXPECT_TRUE(NS_SUCCEEDED(
       NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(f))));
-  EXPECT_TRUE(NS_SUCCEEDED(f->Append(nsDependentString(leaf))));
+
+  EXPECT_TRUE(NS_SUCCEEDED(f->Append(aLeaf)));
 
   bool exists;
-  EXPECT_TRUE(NS_SUCCEEDED(f->Exists(&exists)));
-  EXPECT_TRUE(exists);
+  EXPECT_TRUE(NS_SUCCEEDED(f->Exists(&exists)) && exists);
 
   nsString ret;
   EXPECT_TRUE(NS_SUCCEEDED(f->GetPath(ret)));
   return ret;
 }
 
-TEST(TestDllBlocklist, BlockDllByName)
-{
-  sDllWasBlocked = false;
-  sDllWasLoaded = false;
-  DllBlocklist_SetDllLoadHook(DllLoadHook);
-  auto undoHooks =
-      mozilla::MakeScopeExit([&]() { DllBlocklist_SetDllLoadHook(nullptr); });
-
+TEST(TestDllBlocklist, BlockDllByName) {
   // The DLL name has capital letters, so this also tests that the comparison
   // is case-insensitive.
-  sDllName = u"TestDllBlocklist_MatchByName.dll";
-  nsString dllPath = GetFullPath(sDllName);
+  NS_NAMED_LITERAL_STRING(kLeafName, "TestDllBlocklist_MatchByName.dll");
+  nsString dllPath = GetFullPath(kLeafName);
+
+  nsModuleHandle hDll(::LoadLibraryW(dllPath.get()));
+
+  EXPECT_TRUE(!hDll);
+  EXPECT_TRUE(!::GetModuleHandleW(kLeafName.get()));
+}
+
+TEST(TestDllBlocklist, BlockDllByVersion) {
+  NS_NAMED_LITERAL_STRING(kLeafName, "TestDllBlocklist_MatchByVersion.dll");
+  nsString dllPath = GetFullPath(kLeafName);
+
+  nsModuleHandle hDll(::LoadLibraryW(dllPath.get()));
+
+  EXPECT_TRUE(!hDll);
+  EXPECT_TRUE(!::GetModuleHandleW(kLeafName.get()));
+}
+
+TEST(TestDllBlocklist, AllowDllByVersion) {
+  NS_NAMED_LITERAL_STRING(kLeafName, "TestDllBlocklist_AllowByVersion.dll");
+  nsString dllPath = GetFullPath(kLeafName);
+
+  nsModuleHandle hDll(::LoadLibraryW(dllPath.get()));
+
+  EXPECT_TRUE(!!hDll);
+  EXPECT_TRUE(!!::GetModuleHandleW(kLeafName.get()));
+}
 
-  auto hDll = ::LoadLibraryW((char16ptr_t)dllPath.get());
-  if (hDll) {
-    EXPECT_TRUE(!"DLL was loaded but should have been blocked.");
-  }
+#define DLL_BLOCKLIST_ENTRY(name, ...) {name, __VA_ARGS__},
+#define DLL_BLOCKLIST_STRING_TYPE const char*
+#include "mozilla/WindowsDllBlocklistDefs.h"
+
+TEST(TestDllBlocklist, BlocklistIntegrity) {
+  nsTArray<DLL_BLOCKLIST_STRING_TYPE> dupes;
+  DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(pFirst);
+  DECLARE_POINTER_TO_LAST_DLL_BLOCKLIST_ENTRY(pLast);
+
+  EXPECT_FALSE(pLast->name || pLast->maxVersion || pLast->flags);
+
+  for (size_t i = 0; i < mozilla::ArrayLength(gWindowsDllBlocklist) - 1; ++i) {
+    auto pEntry = pFirst + i;
 
-  EXPECT_FALSE(sDllWasLoaded);
-  EXPECT_TRUE(sDllWasBlocked);
+    // Validate name
+    EXPECT_TRUE(!!pEntry->name);
+    EXPECT_GT(strlen(pEntry->name), 3);
 
-  if (hDll) {
-    FreeLibrary(hDll);
+    // Check the filename for valid characters.
+    for (auto pch = pEntry->name; *pch != 0; ++pch) {
+      EXPECT_FALSE(*pch >= 'A' && *pch <= 'Z');
+    }
+
+    // Check for duplicate entries
+    for (auto&& dupe : dupes) {
+      EXPECT_NE(stricmp(dupe, pEntry->name), 0);
+    }
+
+    dupes.AppendElement(pEntry->name);
   }
 }
 
-TEST(TestDllBlocklist, BlockDllByVersion)
-{
-  sDllWasBlocked = false;
-  sDllWasLoaded = false;
-  DllBlocklist_SetDllLoadHook(DllLoadHook);
-  auto undoHooks =
-      mozilla::MakeScopeExit([&]() { DllBlocklist_SetDllLoadHook(nullptr); });
+TEST(TestDllBlocklist, BlockThreadWithLoadLibraryEntryPoint) {
+  // Only supported on Nightly
+#if defined(NIGHTLY_BUILD)
+  using ThreadProc = unsigned(__stdcall*)(void*);
+
+  NS_NAMED_LITERAL_STRING(kLeafNameW, "TestDllBlocklist_MatchByVersion.dll");
 
-  sDllName = u"TestDllBlocklist_MatchByVersion.dll";
-  nsString dllPath = GetFullPath(sDllName);
+  nsString fullPathW = GetFullPath(kLeafNameW);
+  EXPECT_FALSE(fullPathW.IsEmpty());
+
+  nsAutoHandle threadW(reinterpret_cast<HANDLE>(
+      _beginthreadex(nullptr, 0, reinterpret_cast<ThreadProc>(&::LoadLibraryW),
+                     (void*)fullPathW.get(), 0, nullptr)));
+
+  EXPECT_TRUE(!!threadW);
+  EXPECT_EQ(::WaitForSingleObject(threadW, INFINITE), WAIT_OBJECT_0);
 
-  auto hDll = ::LoadLibraryW((char16ptr_t)dllPath.get());
-  if (hDll) {
-    EXPECT_TRUE(!"DLL was loaded but should have been blocked.");
-  }
+  DWORD exitCode;
+  EXPECT_TRUE(::GetExitCodeThread(threadW, &exitCode) && !exitCode);
+  EXPECT_TRUE(!::GetModuleHandleW(kLeafNameW.get()));
+
+  const NS_LossyConvertUTF16toASCII fullPathA(fullPathW);
+  EXPECT_FALSE(fullPathA.IsEmpty());
 
-  EXPECT_FALSE(sDllWasLoaded);
-  EXPECT_TRUE(sDllWasBlocked);
+  nsAutoHandle threadA(reinterpret_cast<HANDLE>(
+      _beginthreadex(nullptr, 0, reinterpret_cast<ThreadProc>(&::LoadLibraryA),
+                     (void*)fullPathA.get(), 0, nullptr)));
 
-  if (hDll) {
-    FreeLibrary(hDll);
-  }
+  EXPECT_TRUE(!!threadA);
+  EXPECT_EQ(::WaitForSingleObject(threadA, INFINITE), WAIT_OBJECT_0);
+  EXPECT_TRUE(::GetExitCodeThread(threadA, &exitCode) && !exitCode);
+  EXPECT_TRUE(!::GetModuleHandleW(kLeafNameW.get()));
+#endif  // defined(NIGHTLY_BUILD)
 }
 
-TEST(TestDllBlocklist, AllowDllByVersion)
-{
-  sDllWasBlocked = false;
-  sDllWasLoaded = false;
-  DllBlocklist_SetDllLoadHook(DllLoadHook);
-  auto undoHooks =
-      mozilla::MakeScopeExit([&]() { DllBlocklist_SetDllLoadHook(nullptr); });
-
-  sDllName = u"TestDllBlocklist_AllowByVersion.dll";
-  nsString dllPath = GetFullPath(sDllName);
-
-  auto hDll = ::LoadLibraryW((char16ptr_t)dllPath.get());
-  if (!hDll) {
-    EXPECT_TRUE(!"DLL was blocked but should have been loaded.");
-  }
-
-  EXPECT_TRUE(sDllWasLoaded);
-  EXPECT_FALSE(sDllWasBlocked);
-
-  if (hDll) {
-    FreeLibrary(hDll);
-  }
-}
-
-TEST(TestDllBlocklist, BlocklistIntegrity)
-{
-  auto msg = DllBlocklist_TestBlocklistIntegrity();
-  EXPECT_FALSE(msg) << msg;
-}
deleted file mode 100644
--- a/mozglue/tests/gtest/TestDLLEject.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <windows.h>
-#include <winternl.h>
-#include "gtest/gtest.h"
-#include "nsReadableUtils.h"
-#include "nsString.h"
-#include "nsUnicharUtils.h"
-#include "mozilla/ArrayUtils.h"
-#include "mozilla/ScopeExit.h"
-#include "mozilla/UniquePtr.h"
-#include "mozilla/WindowsDllBlocklist.h"
-
-static HANDLE sThreadWasBlocked = 0;
-static HANDLE sThreadWasAllowed = 0;
-static HANDLE sDllWasLoaded = 0;
-static uintptr_t sStartAddress = 0;
-
-static const int sTimeoutMS = 10000;
-
-#define DLL_LEAF_NAME (u"InjectorDLL.dll")
-
-static nsString makeString(PUNICODE_STRING aOther) {
-  size_t numChars = aOther->Length / sizeof(WCHAR);
-  return nsString((const char16_t*)aOther->Buffer, numChars);
-}
-
-static void DllLoadHook(bool aDllLoaded, NTSTATUS aStatus, HANDLE aDllBase,
-                        PUNICODE_STRING aDllName) {
-  nsString str = makeString(aDllName);
-
-  nsString dllName = nsString(DLL_LEAF_NAME);
-  if (StringEndsWith(str, dllName, nsCaseInsensitiveStringComparator())) {
-    if (aDllLoaded) {
-      SetEvent(sDllWasLoaded);
-    }
-  }
-}
-
-static void CreateThreadHook(bool aWasAllowed, void* aStartAddress) {
-  if (sStartAddress == (uintptr_t)aStartAddress) {
-    if (!aWasAllowed) {
-      SetEvent(sThreadWasBlocked);
-    } else {
-      SetEvent(sThreadWasAllowed);
-    }
-  }
-}
-
-/**
- * This function tests that we correctly block DLLs injected into this process
- * via an injection technique which calls CreateRemoteThread with LoadLibrary*()
- * as the thread start address, and the path to the DLL as the thread param.
- *
- * We prevent this technique by blocking threads with a start address in any
- * LoadLibrary*() APIs.
- *
- * This function launches Injector.exe which simulates a 3rd-party application
- * executing this technique.
- *
- * @param aGetArgsProc  A callable procedure that specifies the thread start
- *                      address and thread param passed as arguments to
- *                      Injector.exe, which are in turn passed as arguments to
- *                      CreateRemoteThread. This procedure is defined as such:
- *
- *                      void (*aGetArgsProc)(const nsString& aDllPath,
- *                                           const nsCString& aDllPathC,
- *                                           uintptr_t& startAddress,
- *                                           uintptr_t& threadParam);
- *
- *                      aDllPath is a WCHAR-friendly path to InjectorDLL.dll.
- *                      Its memory will persist during the injection attempt.
- *
- *                      aDllPathC is the equivalent char-friendly path.
- *
- *                      startAddress and threadParam are passed into
- *                      CreateRemoteThread as arguments.
- */
-template <typename TgetArgsProc>
-static void DoTest_CreateRemoteThread_LoadLibrary(TgetArgsProc aGetArgsProc) {
-  sThreadWasBlocked = CreateEvent(NULL, FALSE, FALSE, NULL);
-  if (!sThreadWasBlocked) {
-    EXPECT_TRUE(!"Unable to create sThreadWasBlocked event");
-    ASSERT_EQ(GetLastError(), ERROR_SUCCESS);
-  }
-
-  sThreadWasAllowed = CreateEvent(NULL, FALSE, FALSE, NULL);
-  if (!sThreadWasAllowed) {
-    EXPECT_TRUE(!"Unable to create sThreadWasAllowed event");
-    ASSERT_EQ(GetLastError(), ERROR_SUCCESS);
-  }
-
-  sDllWasLoaded = CreateEvent(NULL, FALSE, FALSE, NULL);
-  if (!sDllWasLoaded) {
-    EXPECT_TRUE(!"Unable to create sDllWasLoaded event");
-    ASSERT_EQ(GetLastError(), ERROR_SUCCESS);
-  }
-
-  auto closeEvents = mozilla::MakeScopeExit([&]() {
-    CloseHandle(sThreadWasAllowed);
-    CloseHandle(sThreadWasBlocked);
-    CloseHandle(sDllWasLoaded);
-  });
-
-  // Hook into our DLL and thread blocking routines during this test.
-  DllBlocklist_SetDllLoadHook(DllLoadHook);
-  DllBlocklist_SetCreateThreadHook(CreateThreadHook);
-  auto undoHooks = mozilla::MakeScopeExit([&]() {
-    DllBlocklist_SetDllLoadHook(nullptr);
-    DllBlocklist_SetCreateThreadHook(nullptr);
-  });
-
-  // Launch Injector.exe.
-  STARTUPINFOW si = {0};
-  si.cb = sizeof(si);
-  ::GetStartupInfoW(&si);
-  PROCESS_INFORMATION pi = {0};
-
-  nsString path(u"Injector.exe");
-  nsString dllPath(DLL_LEAF_NAME);
-  nsCString dllPathC = NS_ConvertUTF16toUTF8(dllPath);
-
-  uintptr_t threadParam;
-  aGetArgsProc(dllPath, dllPathC, sStartAddress, threadParam);
-
-  path.AppendPrintf(" %lu 0x%p 0x%p", GetCurrentProcessId(), sStartAddress,
-                    threadParam);
-  if (::CreateProcessW(NULL, path.get(), 0, 0, FALSE, 0, NULL, NULL, &si,
-                       &pi) == FALSE) {
-    EXPECT_TRUE(!"Error in CreateProcessW() launching Injector.exe");
-    ASSERT_EQ(GetLastError(), ERROR_SUCCESS);
-    return;
-  }
-
-  // Ensure Injector.exe doesn't stay running after this test finishes.
-  auto cleanup = mozilla::MakeScopeExit([&]() {
-    CloseHandle(pi.hThread);
-    EXPECT_TRUE("Shutting down.");
-    WaitForSingleObject(pi.hProcess, INFINITE);
-    CloseHandle(pi.hProcess);
-  });
-
-  // Wait for information to come in and complete the test.
-  HANDLE handles[] = {sThreadWasBlocked, sThreadWasAllowed, sDllWasLoaded,
-                      pi.hProcess};
-  int handleCount = mozilla::ArrayLength(handles);
-  bool keepGoing = true;  // Set to false to signal that the test is over.
-
-  while (keepGoing) {
-    switch (WaitForMultipleObjectsEx(handleCount, handles, FALSE, sTimeoutMS,
-                                     FALSE)) {
-      case WAIT_OBJECT_0: {  // sThreadWasBlocked
-        EXPECT_TRUE("Thread was blocked successfully.");
-        // No need to continue testing; blocking was successful.
-        keepGoing = false;
-        break;
-      }
-      case WAIT_OBJECT_0 + 1: {  // sThreadWasAllowed
-        EXPECT_TRUE(!"Thread was allowed but should have been blocked.");
-        // No need to continue testing; blocking failed.
-        keepGoing = false;
-        break;
-      }
-      case WAIT_OBJECT_0 + 2: {  // sDllWasLoaded
-        EXPECT_TRUE(!"DLL was loaded.");
-        // No need to continue testing; blocking failed and the DLL was
-        // consequently loaded. In theory we should never see this fire, because
-        // the thread being allowed should already trigger a test failure.
-        keepGoing = false;
-        break;
-      }
-      case WAIT_OBJECT_0 + 3: {  // pi.hProcess
-        // Check to see if we got an error code from Injector.exe, in which case
-        // fail the test and exit.
-        DWORD exitCode;
-        if (!GetExitCodeProcess(pi.hProcess, &exitCode)) {
-          EXPECT_TRUE(
-              !"Injector.exe exited but we were unable to get the exit code.");
-          keepGoing = false;
-          break;
-        }
-        EXPECT_EQ(exitCode, 0);
-        if (exitCode != 0) {
-          EXPECT_TRUE(!"Injector.exe returned non-zero exit code");
-          keepGoing = false;
-          break;
-        }
-        // Process exited successfully. This can be ignored; we expect to get an
-        // event whether the DLL was loaded or blocked.
-        EXPECT_TRUE("Process exited as expected.");
-        handleCount--;
-        break;
-      }
-      case WAIT_TIMEOUT:
-      default: {
-        EXPECT_TRUE(!"An error or timeout occurred while waiting for activity "
-                    "from Injector.exe");
-        keepGoing = false;
-        break;
-      }
-    }
-  }
-
-  // Double-check that injectordll is not loaded.
-  auto hExisting = GetModuleHandleW(dllPath.get());
-  EXPECT_TRUE(!hExisting);
-
-  // If the DLL was erroneously loaded, attempt to unload it before exiting.
-  if (hExisting) {
-    FreeLibrary(hExisting);
-  }
-
-  return;
-}
-
-TEST(TestInjectEject, CreateRemoteThread_LoadLibraryA)
-{
-  DoTest_CreateRemoteThread_LoadLibrary(
-      [](const nsString& dllPath, const nsCString& dllPathC,
-         uintptr_t& aStartAddress, uintptr_t& aThreadParam) {
-        HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
-        aStartAddress = (uintptr_t)GetProcAddress(hKernel32, "LoadLibraryA");
-        aThreadParam = (uintptr_t)dllPathC.get();
-      });
-}
-
-TEST(TestInjectEject, CreateRemoteThread_LoadLibraryW)
-{
-  DoTest_CreateRemoteThread_LoadLibrary(
-      [](const nsString& dllPath, const nsCString& dllPathC,
-         uintptr_t& aStartAddress, uintptr_t& aThreadParam) {
-        HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
-        aStartAddress = (uintptr_t)GetProcAddress(hKernel32, "LoadLibraryW");
-        aThreadParam = (uintptr_t)dllPath.get();
-      });
-}
-
-TEST(TestInjectEject, CreateRemoteThread_LoadLibraryExW)
-{
-  DoTest_CreateRemoteThread_LoadLibrary(
-      [](const nsString& dllPath, const nsCString& dllPathC,
-         uintptr_t& aStartAddress, uintptr_t& aThreadParam) {
-        HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
-        // LoadLibraryEx requires three arguments so this injection method may
-        // not be viable. It's certainly not an allowable thread start in any
-        // case.
-        aStartAddress = (uintptr_t)GetProcAddress(hKernel32, "LoadLibraryExW");
-        aThreadParam = (uintptr_t)dllPath.get();
-      });
-}
-
-TEST(TestInjectEject, CreateRemoteThread_LoadLibraryExA)
-{
-  DoTest_CreateRemoteThread_LoadLibrary(
-      [](const nsString& dllPath, const nsCString& dllPathC,
-         uintptr_t& aStartAddress, uintptr_t& aThreadParam) {
-        HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
-        aStartAddress = (uintptr_t)GetProcAddress(hKernel32, "LoadLibraryExA");
-        aThreadParam = (uintptr_t)dllPathC.get();
-      });
-}
--- a/mozglue/tests/gtest/moz.build
+++ b/mozglue/tests/gtest/moz.build
@@ -1,22 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-if CONFIG['NIGHTLY_BUILD']:
-    SOURCES += [
-        'TestDLLEject.cpp',
-    ]
-
 SOURCES += [
     'TestDLLBlocklist.cpp',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
 
 TEST_DIRS += [
-  'Injector',
-  'InjectorDLL',
-  'TestDllBlocklist_AllowByVersion',
-  'TestDllBlocklist_MatchByName',
-  'TestDllBlocklist_MatchByVersion',
+    'TestDllBlocklist_AllowByVersion',
+    'TestDllBlocklist_MatchByName',
+    'TestDllBlocklist_MatchByVersion',
 ]
+