Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Bug 699134 - Protect against reentrancy in the LdrLoadDll hook, with …

…less XPCOM stringery and more locking. a=bsmedberg ON A CLOSED TREE

--HG--
branch : GECKO80_2011110416_RELBRANCH
  • Loading branch information...
commit 601cfe66c412c861a780ce4dc26b3e76d06633c0 1 parent 2d77d28
authored November 18, 2011

Showing 1 changed file with 70 additions and 0 deletions. Show diff stats Hide diff stats

  1. 70  toolkit/xre/nsWindowsDllBlocklist.cpp
70  toolkit/xre/nsWindowsDllBlocklist.cpp
@@ -39,6 +39,9 @@
39 39
 #include <winternl.h>
40 40
 
41 41
 #include <stdio.h>
  42
+#include <string.h>
  43
+
  44
+#include <map>
42 45
 
43 46
 #ifdef XRE_WANT_DLL_BLOCKLIST
44 47
 #define XRE_SetupDllBlocklist SetupDllBlocklist
@@ -62,10 +65,68 @@
62 65
 // define this for very verbose dll load debug spew
63 66
 #undef DEBUG_very_verbose
64 67
 
  68
+namespace {
  69
+
65 70
 typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle);
66 71
 
67 72
 static LdrLoadDll_func stub_LdrLoadDll = 0;
68 73
 
  74
+/**
  75
+ * Some versions of Windows call LoadLibraryEx to get the version information
  76
+ * for a DLL, which causes our patched LdrLoadDll implementation to re-enter
  77
+ * itself and cause infinite recursion and a stack-exhaustion crash. We protect
  78
+ * against reentrancy by allowing recursive loads of the same DLL.
  79
+ *
  80
+ * Note that we don't use __declspec(thread) because that doesn't work in DLLs
  81
+ * loaded via LoadLibrary and there can be a limited number of TLS slots, so
  82
+ * we roll our own.
  83
+ */
  84
+class ReentrancySentinel
  85
+{
  86
+public:
  87
+  explicit ReentrancySentinel(const char* dllName)
  88
+  {
  89
+    DWORD currentThreadId = GetCurrentThreadId();
  90
+    EnterCriticalSection(&sLock);
  91
+    mPreviousDllName = (*sThreadMap)[currentThreadId];
  92
+
  93
+    // If there is a DLL currently being loaded and it has the same name
  94
+    // as the current attempt, we're re-entering.
  95
+    mReentered = mPreviousDllName && !stricmp(mPreviousDllName, dllName);
  96
+    (*sThreadMap)[currentThreadId] = dllName;
  97
+    LeaveCriticalSection(&sLock);
  98
+  }
  99
+    
  100
+  ~ReentrancySentinel()
  101
+  {
  102
+    DWORD currentThreadId = GetCurrentThreadId();
  103
+    EnterCriticalSection(&sLock);
  104
+    (*sThreadMap)[currentThreadId] = mPreviousDllName;
  105
+    LeaveCriticalSection(&sLock);
  106
+  }
  107
+
  108
+  bool BailOut() const
  109
+  {
  110
+    return mReentered;
  111
+  };
  112
+    
  113
+  static void InitializeStatics()
  114
+  {
  115
+    InitializeCriticalSection(&sLock);
  116
+    sThreadMap = new std::map<DWORD, const char*>;
  117
+  }
  118
+
  119
+private:
  120
+  static CRITICAL_SECTION sLock;
  121
+  static std::map<DWORD, const char*>* sThreadMap;
  122
+
  123
+  const char* mPreviousDllName;
  124
+  bool mReentered;
  125
+};
  126
+
  127
+CRITICAL_SECTION ReentrancySentinel::sLock;
  128
+std::map<DWORD, const char*>* ReentrancySentinel::sThreadMap;
  129
+
69 130
 static NTSTATUS NTAPI
70 131
 patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle)
71 132
 {
@@ -153,6 +214,11 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam
153 214
 #endif
154 215
 
155 216
     if (info->maxVersion != ALL_VERSIONS) {
  217
+      ReentrancySentinel sentinel(dllName);
  218
+      if (sentinel.BailOut()) {
  219
+        goto continue_loading;
  220
+      }
  221
+
156 222
       // In Windows 8, the first parameter seems to be used for more than just the
157 223
       // path name.  For example, its numerical value can be 1.  Passing a non-valid
158 224
       // pointer to SearchPathW will cause a crash, so we need to check to see if we
@@ -221,11 +287,15 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam
221 287
 
222 288
 WindowsDllInterceptor NtDllIntercept;
223 289
 
  290
+} // anonymous namespace
  291
+
224 292
 void
225 293
 XRE_SetupDllBlocklist()
226 294
 {
227 295
   NtDllIntercept.Init("ntdll.dll");
228 296
 
  297
+  ReentrancySentinel::InitializeStatics();
  298
+
229 299
   bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll);
230 300
 
231 301
 #ifdef DEBUG

0 notes on commit 601cfe6

Please sign in to comment.
Something went wrong with that request. Please try again.