mozglue/build/WindowsDllBlocklist.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <windows.h>
     7 #include <winternl.h>
     8 #include <io.h>
    10 #pragma warning( push )
    11 #pragma warning( disable : 4275 4530 ) // See msvc-stl-wrapper.template.h
    12 #include <map>
    13 #pragma warning( pop )
    15 #define MOZ_NO_MOZALLOC
    16 #include "nsAutoPtr.h"
    18 #include "nsWindowsDllInterceptor.h"
    19 #include "mozilla/WindowsVersion.h"
    20 #include "nsWindowsHelpers.h"
    22 using namespace mozilla;
    24 #define ALL_VERSIONS   ((unsigned long long)-1LL)
    26 // DLLs sometimes ship without a version number, particularly early
    27 // releases. Blocking "version <= 0" has the effect of blocking unversioned
    28 // DLLs (since the call to get version info fails), but not blocking
    29 // any versioned instance.
    30 #define UNVERSIONED    ((unsigned long long)0LL)
    32 // Convert the 4 (decimal) components of a DLL version number into a
    33 // single unsigned long long, as needed by the blocklist
    34 #define MAKE_VERSION(a,b,c,d)\
    35   ((a##ULL << 48) + (b##ULL << 32) + (c##ULL << 16) + d##ULL)
    37 struct DllBlockInfo {
    38   // The name of the DLL -- in LOWERCASE!  It will be compared to
    39   // a lowercase version of the DLL name only.
    40   const char *name;
    42   // If maxVersion is ALL_VERSIONS, we'll block all versions of this
    43   // dll.  Otherwise, we'll block all versions less than or equal to
    44   // the given version, as queried by GetFileVersionInfo and
    45   // VS_FIXEDFILEINFO's dwFileVersionMS and dwFileVersionLS fields.
    46   //
    47   // Note that the version is usually 4 components, which is A.B.C.D
    48   // encoded as 0x AAAA BBBB CCCC DDDD ULL (spaces added for clarity),
    49   // but it's not required to be of that format.
    50   //
    51   // If the USE_TIMESTAMP flag is set, then we use the timestamp from
    52   // the IMAGE_FILE_HEADER in lieu of a version number.
    53   unsigned long long maxVersion;
    55   enum {
    56     FLAGS_DEFAULT = 0,
    57     BLOCK_WIN8PLUS_ONLY = 1,
    58     BLOCK_XP_ONLY = 2,
    59     USE_TIMESTAMP = 4,
    60   } flags;
    61 };
    63 static DllBlockInfo sWindowsDllBlocklist[] = {
    64   // EXAMPLE:
    65   // { "uxtheme.dll", ALL_VERSIONS },
    66   // { "uxtheme.dll", 0x0000123400000000ULL },
    67   // The DLL name must be in lowercase!
    69   // NPFFAddon - Known malware
    70   { "npffaddon.dll", ALL_VERSIONS},
    72   // AVG 8 - Antivirus vendor AVG, old version, plugin already blocklisted
    73   {"avgrsstx.dll", MAKE_VERSION(8,5,0,401)},
    75   // calc.dll - Suspected malware
    76   {"calc.dll", MAKE_VERSION(1,0,0,1)},
    78   // hook.dll - Suspected malware
    79   {"hook.dll", ALL_VERSIONS},
    81   // GoogleDesktopNetwork3.dll - Extremely old, unversioned instances
    82   // of this DLL cause crashes
    83   {"googledesktopnetwork3.dll", UNVERSIONED},
    85   // rdolib.dll - Suspected malware
    86   {"rdolib.dll", MAKE_VERSION(6,0,88,4)},
    88   // fgjk4wvb.dll - Suspected malware
    89   {"fgjk4wvb.dll", MAKE_VERSION(8,8,8,8)},
    91   // radhslib.dll - Naomi internet filter - unmaintained since 2006
    92   {"radhslib.dll", UNVERSIONED},
    94   // Music download filter for vkontakte.ru - old instances
    95   // of this DLL cause crashes
    96   {"vksaver.dll", MAKE_VERSION(2,2,2,0)},
    98   // Topcrash in Firefox 4.0b1
    99   {"rlxf.dll", MAKE_VERSION(1,2,323,1)},
   101   // psicon.dll - Topcrashes in Thunderbird, and some crashes in Firefox
   102   // Adobe photoshop library, now redundant in later installations
   103   {"psicon.dll", ALL_VERSIONS},
   105   // Topcrash in Firefox 4 betas (bug 618899)
   106   {"accelerator.dll", MAKE_VERSION(3,2,1,6)},
   108   // Topcrash with Roboform in Firefox 8 (bug 699134)
   109   {"rf-firefox.dll", MAKE_VERSION(7,6,1,0)},
   110   {"roboform.dll", MAKE_VERSION(7,6,1,0)},
   112   // Topcrash with Babylon Toolbar on FF16+ (bug 721264)
   113   {"babyfox.dll", ALL_VERSIONS},
   115   // sprotector.dll crashes, bug 957258
   116   {"sprotector.dll", ALL_VERSIONS},
   118   // Topcrash with Websense Endpoint, bug 828184
   119   {"qipcap.dll", MAKE_VERSION(7, 6, 815, 1)},
   121   // leave these two in always for tests
   122   { "mozdllblockingtest.dll", ALL_VERSIONS },
   123   { "mozdllblockingtest_versioned.dll", 0x0000000400000000ULL },
   125   // Windows Media Foundation FLAC decoder and type sniffer (bug 839031).
   126   { "mfflac.dll", ALL_VERSIONS },
   128   // Older Relevant Knowledge DLLs cause us to crash (bug 904001).
   129   { "rlnx.dll", MAKE_VERSION(1, 3, 334, 9) },
   130   { "pmnx.dll", MAKE_VERSION(1, 3, 334, 9) },
   131   { "opnx.dll", MAKE_VERSION(1, 3, 334, 9) },
   132   { "prnx.dll", MAKE_VERSION(1, 3, 334, 9) },
   134   // Older belgian ID card software causes Firefox to crash or hang on
   135   // shutdown, bug 831285 and 918399.
   136   { "beid35cardlayer.dll", MAKE_VERSION(3, 5, 6, 6968) },
   138   // bug 925459, bitguard crashes
   139   { "bitguard.dll", ALL_VERSIONS },
   141   // bug 812683 - crashes in Windows library when Asus Gamer OSD is installed
   142   // Software is discontinued/unsupported
   143   { "atkdx11disp.dll", ALL_VERSIONS },
   145   // Topcrash with Conduit SearchProtect, bug 944542
   146   { "spvc32.dll", ALL_VERSIONS },
   148   // XP topcrash with F-Secure, bug 970362
   149   { "fs_ccf_ni_umh32.dll", MAKE_VERSION(1, 42, 101, 0), DllBlockInfo::BLOCK_XP_ONLY },
   151   // Topcrash with V-bates, bug 1002748 and bug 1023239
   152   { "libinject.dll", UNVERSIONED },
   153   { "libinject2.dll", 0x537DDC93, DllBlockInfo::USE_TIMESTAMP },
   154   { "libredir2.dll", 0x5385B7ED, DllBlockInfo::USE_TIMESTAMP },
   156   // Crashes with RoboForm2Go written against old SDK, bug 988311
   157   { "rf-firefox-22.dll", ALL_VERSIONS },
   159   { nullptr, 0 }
   160 };
   162 #ifndef STATUS_DLL_NOT_FOUND
   163 #define STATUS_DLL_NOT_FOUND ((DWORD)0xC0000135L)
   164 #endif
   166 // define this for very verbose dll load debug spew
   167 #undef DEBUG_very_verbose
   169 static const char kBlockedDllsParameter[] = "BlockedDllList=";
   170 static const int kBlockedDllsParameterLen =
   171   sizeof(kBlockedDllsParameter) - 1;
   173 static const char kBlocklistInitFailedParameter[] = "BlocklistInitFailed=1\n";
   174 static const int kBlocklistInitFailedParameterLen =
   175   sizeof(kBlocklistInitFailedParameter) - 1;
   177 static const char kUser32BeforeBlocklistParameter[] = "User32BeforeBlocklist=1\n";
   178 static const int kUser32BeforeBlocklistParameterLen =
   179   sizeof(kUser32BeforeBlocklistParameter) - 1;
   181 static DWORD sThreadLoadingXPCOMModule;
   182 static bool sBlocklistInitFailed;
   183 static bool sUser32BeforeBlocklist;
   185 // Duplicated from xpcom glue. Ideally this should be shared.
   186 void
   187 printf_stderr(const char *fmt, ...)
   188 {
   189   if (IsDebuggerPresent()) {
   190     char buf[2048];
   191     va_list args;
   192     va_start(args, fmt);
   193     vsnprintf(buf, sizeof(buf), fmt, args);
   194     buf[sizeof(buf) - 1] = '\0';
   195     va_end(args);
   196     OutputDebugStringA(buf);
   197   }
   199   FILE *fp = _fdopen(_dup(2), "a");
   200   if (!fp)
   201       return;
   203   va_list args;
   204   va_start(args, fmt);
   205   vfprintf(fp, fmt, args);
   206   va_end(args);
   208   fclose(fp);
   209 }
   211 namespace {
   213 typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle);
   215 static LdrLoadDll_func stub_LdrLoadDll = 0;
   217 template <class T>
   218 struct RVAMap {
   219   RVAMap(HANDLE map, DWORD offset) {
   220     SYSTEM_INFO info;
   221     GetSystemInfo(&info);
   223     DWORD alignedOffset = (offset / info.dwAllocationGranularity) *
   224                           info.dwAllocationGranularity;
   226     MOZ_ASSERT(offset - alignedOffset < info.dwAllocationGranularity, "Wtf");
   228     mRealView = ::MapViewOfFile(map, FILE_MAP_READ, 0, alignedOffset,
   229                                 sizeof(T) + (offset - alignedOffset));
   231     mMappedView = mRealView ? reinterpret_cast<T*>((char*)mRealView + (offset - alignedOffset)) :
   232                               nullptr;
   233   }
   234   ~RVAMap() {
   235     if (mRealView) {
   236       ::UnmapViewOfFile(mRealView);
   237     }
   238   }
   239   operator const T*() const { return mMappedView; }
   240   const T* operator->() const { return mMappedView; }
   241 private:
   242   const T* mMappedView;
   243   void* mRealView;
   244 };
   246 bool
   247 CheckASLR(const wchar_t* path)
   248 {
   249   bool retval = false;
   251   HANDLE file = ::CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
   252                               nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
   253                               nullptr);
   254   if (file != INVALID_HANDLE_VALUE) {
   255     HANDLE map = ::CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0,
   256                                       nullptr);
   257     if (map) {
   258       RVAMap<IMAGE_DOS_HEADER> peHeader(map, 0);
   259       if (peHeader) {
   260         RVAMap<IMAGE_NT_HEADERS> ntHeader(map, peHeader->e_lfanew);
   261         if (ntHeader) {
   262           // If the DLL has no code, permit it regardless of ASLR status.
   263           if (ntHeader->OptionalHeader.SizeOfCode == 0) {
   264             retval = true;
   265           }
   266           // Check to see if the DLL supports ASLR
   267           else if ((ntHeader->OptionalHeader.DllCharacteristics &
   268                     IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) != 0) {
   269             retval = true;
   270           }
   271         }
   272       }
   273       ::CloseHandle(map);
   274     }
   275     ::CloseHandle(file);
   276   }
   278   return retval;
   279 }
   281 DWORD
   282 GetTimestamp(const wchar_t* path)
   283 {
   284   DWORD timestamp = 0;
   286   HANDLE file = ::CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
   287                               nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
   288                               nullptr);
   289   if (file != INVALID_HANDLE_VALUE) {
   290     HANDLE map = ::CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0,
   291                                       nullptr);
   292     if (map) {
   293       RVAMap<IMAGE_DOS_HEADER> peHeader(map, 0);
   294       if (peHeader) {
   295         RVAMap<IMAGE_NT_HEADERS> ntHeader(map, peHeader->e_lfanew);
   296         if (ntHeader) {
   297           timestamp = ntHeader->FileHeader.TimeDateStamp;
   298         }
   299       }
   300       ::CloseHandle(map);
   301     }
   302     ::CloseHandle(file);
   303   }
   305   return timestamp;
   306 }
   308 // This lock protects both the reentrancy sentinel and the crash reporter
   309 // data structures.
   310 static CRITICAL_SECTION sLock;
   312 /**
   313  * Some versions of Windows call LoadLibraryEx to get the version information
   314  * for a DLL, which causes our patched LdrLoadDll implementation to re-enter
   315  * itself and cause infinite recursion and a stack-exhaustion crash. We protect
   316  * against reentrancy by allowing recursive loads of the same DLL.
   317  *
   318  * Note that we don't use __declspec(thread) because that doesn't work in DLLs
   319  * loaded via LoadLibrary and there can be a limited number of TLS slots, so
   320  * we roll our own.
   321  */
   322 class ReentrancySentinel
   323 {
   324 public:
   325   explicit ReentrancySentinel(const char* dllName)
   326   {
   327     DWORD currentThreadId = GetCurrentThreadId();
   328     AutoCriticalSection lock(&sLock);
   329     mPreviousDllName = (*sThreadMap)[currentThreadId];
   331     // If there is a DLL currently being loaded and it has the same name
   332     // as the current attempt, we're re-entering.
   333     mReentered = mPreviousDllName && !stricmp(mPreviousDllName, dllName);
   334     (*sThreadMap)[currentThreadId] = dllName;
   335   }
   337   ~ReentrancySentinel()
   338   {
   339     DWORD currentThreadId = GetCurrentThreadId();
   340     AutoCriticalSection lock(&sLock);
   341     (*sThreadMap)[currentThreadId] = mPreviousDllName;
   342   }
   344   bool BailOut() const
   345   {
   346     return mReentered;
   347   };
   349   static void InitializeStatics()
   350   {
   351     InitializeCriticalSection(&sLock);
   352     sThreadMap = new std::map<DWORD, const char*>;
   353   }
   355 private:
   356   static std::map<DWORD, const char*>* sThreadMap;
   358   const char* mPreviousDllName;
   359   bool mReentered;
   360 };
   362 std::map<DWORD, const char*>* ReentrancySentinel::sThreadMap;
   364 /**
   365  * This is a linked list of DLLs that have been blocked. It doesn't use
   366  * mozilla::LinkedList because this is an append-only list and doesn't need
   367  * to be doubly linked.
   368  */
   369 class DllBlockSet
   370 {
   371 public:
   372   static void Add(const char* name, unsigned long long version);
   374   // Write the list of blocked DLLs to a file HANDLE. This method is run after
   375   // a crash occurs and must therefore not use the heap, etc.
   376   static void Write(HANDLE file);
   378 private:
   379   DllBlockSet(const char* name, unsigned long long version)
   380     : mName(name)
   381     , mVersion(version)
   382     , mNext(nullptr)
   383   {
   384   }
   386   const char* mName; // points into the sWindowsDllBlocklist string
   387   unsigned long long mVersion;
   388   DllBlockSet* mNext;
   390   static DllBlockSet* gFirst;
   391 };
   393 DllBlockSet* DllBlockSet::gFirst;
   395 void
   396 DllBlockSet::Add(const char* name, unsigned long long version)
   397 {
   398   AutoCriticalSection lock(&sLock);
   399   for (DllBlockSet* b = gFirst; b; b = b->mNext) {
   400     if (0 == strcmp(b->mName, name) && b->mVersion == version) {
   401       return;
   402     }
   403   }
   404   // Not already present
   405   DllBlockSet* n = new DllBlockSet(name, version);
   406   n->mNext = gFirst;
   407   gFirst = n;
   408 }
   410 void
   411 DllBlockSet::Write(HANDLE file)
   412 {
   413   AutoCriticalSection lock(&sLock);
   414   DWORD nBytes;
   416   // Because this method is called after a crash occurs, and uses heap memory,
   417   // protect this entire block with a structured exception handler.
   418   MOZ_SEH_TRY {
   419     for (DllBlockSet* b = gFirst; b; b = b->mNext) {
   420       // write name[,v.v.v.v];
   421       WriteFile(file, b->mName, strlen(b->mName), &nBytes, nullptr);
   422       if (b->mVersion != -1) {
   423         WriteFile(file, ",", 1, &nBytes, nullptr);
   424         uint16_t parts[4];
   425         parts[0] = b->mVersion >> 48;
   426         parts[1] = (b->mVersion >> 32) & 0xFFFF;
   427         parts[2] = (b->mVersion >> 16) & 0xFFFF;
   428         parts[3] = b->mVersion & 0xFFFF;
   429         for (int p = 0; p < 4; ++p) {
   430           char buf[32];
   431           ltoa(parts[p], buf, 10);
   432           WriteFile(file, buf, strlen(buf), &nBytes, nullptr);
   433           if (p != 3) {
   434             WriteFile(file, ".", 1, &nBytes, nullptr);
   435           }
   436         }
   437       }
   438       WriteFile(file, ";", 1, &nBytes, nullptr);
   439     }
   440   }
   441   MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { }
   442 }
   444 static
   445 wchar_t* getFullPath (PWCHAR filePath, wchar_t* fname)
   446 {
   447   // In Windows 8, the first parameter seems to be used for more than just the
   448   // path name.  For example, its numerical value can be 1.  Passing a non-valid
   449   // pointer to SearchPathW will cause a crash, so we need to check to see if we
   450   // are handed a valid pointer, and otherwise just pass nullptr to SearchPathW.
   451   PWCHAR sanitizedFilePath = (intptr_t(filePath) < 1024) ? nullptr : filePath;
   453   // figure out the length of the string that we need
   454   DWORD pathlen = SearchPathW(sanitizedFilePath, fname, L".dll", 0, nullptr,
   455                               nullptr);
   456   if (pathlen == 0) {
   457     return nullptr;
   458   }
   460   wchar_t* full_fname = new wchar_t[pathlen+1];
   461   if (!full_fname) {
   462     // couldn't allocate memory?
   463     return nullptr;
   464   }
   466   // now actually grab it
   467   SearchPathW(sanitizedFilePath, fname, L".dll", pathlen + 1, full_fname,
   468               nullptr);
   469   return full_fname;
   470 }
   472 // No builtin function to find the last character matching a set
   473 static wchar_t* lastslash(wchar_t* s, int len)
   474 {
   475   for (wchar_t* c = s + len - 1; c >= s; --c) {
   476     if (*c == L'\\' || *c == L'/') {
   477       return c;
   478     }
   479   }
   480   return nullptr;
   481 }
   483 static NTSTATUS NTAPI
   484 patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle)
   485 {
   486   // We have UCS2 (UTF16?), we want ASCII, but we also just want the filename portion
   487 #define DLLNAME_MAX 128
   488   char dllName[DLLNAME_MAX+1];
   489   wchar_t *dll_part;
   490   char *dot;
   491   DllBlockInfo *info;
   493   int len = moduleFileName->Length / 2;
   494   wchar_t *fname = moduleFileName->Buffer;
   495   nsAutoArrayPtr<wchar_t> full_fname;
   497   // The filename isn't guaranteed to be null terminated, but in practice
   498   // it always will be; ensure that this is so, and bail if not.
   499   // This is done instead of the more robust approach because of bug 527122,
   500   // where lots of weird things were happening when we tried to make a copy.
   501   if (moduleFileName->MaximumLength < moduleFileName->Length+2 ||
   502       fname[len] != 0)
   503   {
   504 #ifdef DEBUG
   505     printf_stderr("LdrLoadDll: non-null terminated string found!\n");
   506 #endif
   507     goto continue_loading;
   508   }
   510   dll_part = lastslash(fname, len);
   511   if (dll_part) {
   512     dll_part = dll_part + 1;
   513     len -= dll_part - fname;
   514   } else {
   515     dll_part = fname;
   516   }
   518 #ifdef DEBUG_very_verbose
   519   printf_stderr("LdrLoadDll: dll_part '%S' %d\n", dll_part, len);
   520 #endif
   522   // if it's too long, then, we assume we won't want to block it,
   523   // since DLLNAME_MAX should be at least long enough to hold the longest
   524   // entry in our blocklist.
   525   if (len > DLLNAME_MAX) {
   526 #ifdef DEBUG
   527     printf_stderr("LdrLoadDll: len too long! %d\n", len);
   528 #endif
   529     goto continue_loading;
   530   }
   532   // copy over to our char byte buffer, lowercasing ASCII as we go
   533   for (int i = 0; i < len; i++) {
   534     wchar_t c = dll_part[i];
   536     if (c > 0x7f) {
   537       // welp, it's not ascii; if we need to add non-ascii things to
   538       // our blocklist, we'll have to remove this limitation.
   539       goto continue_loading;
   540     }
   542     // ensure that dll name is all lowercase
   543     if (c >= 'A' && c <= 'Z')
   544       c += 'a' - 'A';
   546     dllName[i] = (char) c;
   547   }
   549   dllName[len] = 0;
   551 #ifdef DEBUG_very_verbose
   552   printf_stderr("LdrLoadDll: dll name '%s'\n", dllName);
   553 #endif
   555   // Block a suspicious binary that uses various 12-digit hex strings
   556   // e.g. MovieMode.48CA2AEFA22D.dll (bug 973138)
   557   dot = strchr(dllName, '.');
   558   if (dot && (strchr(dot+1, '.') == dot+13)) {
   559     char * end = nullptr;
   560     _strtoui64(dot+1, &end, 16);
   561     if (end == dot+13) {
   562       return STATUS_DLL_NOT_FOUND;
   563     }
   564   }
   566   // then compare to everything on the blocklist
   567   info = &sWindowsDllBlocklist[0];
   568   while (info->name) {
   569     if (strcmp(info->name, dllName) == 0)
   570       break;
   572     info++;
   573   }
   575   if (info->name) {
   576     bool load_ok = false;
   578 #ifdef DEBUG_very_verbose
   579     printf_stderr("LdrLoadDll: info->name: '%s'\n", info->name);
   580 #endif
   582     if ((info->flags == DllBlockInfo::BLOCK_WIN8PLUS_ONLY) &&
   583         !IsWin8OrLater()) {
   584       goto continue_loading;
   585     }
   587     if ((info->flags == DllBlockInfo::BLOCK_XP_ONLY) &&
   588         IsWin2003OrLater()) {
   589       goto continue_loading;
   590     }
   592     unsigned long long fVersion = ALL_VERSIONS;
   594     if (info->maxVersion != ALL_VERSIONS) {
   595       ReentrancySentinel sentinel(dllName);
   596       if (sentinel.BailOut()) {
   597         goto continue_loading;
   598       }
   600       full_fname = getFullPath(filePath, fname);
   601       if (!full_fname) {
   602         // uh, we couldn't find the DLL at all, so...
   603         printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
   604         return STATUS_DLL_NOT_FOUND;
   605       }
   607       if (info->flags & DllBlockInfo::USE_TIMESTAMP) {
   608         fVersion = GetTimestamp(full_fname);
   609         if (fVersion > info->maxVersion) {
   610           load_ok = true;
   611         }
   612       } else {
   613         DWORD zero;
   614         DWORD infoSize = GetFileVersionInfoSizeW(full_fname, &zero);
   616         // If we failed to get the version information, we block.
   618         if (infoSize != 0) {
   619           nsAutoArrayPtr<unsigned char> infoData(new unsigned char[infoSize]);
   620           VS_FIXEDFILEINFO *vInfo;
   621           UINT vInfoLen;
   623           if (GetFileVersionInfoW(full_fname, 0, infoSize, infoData) &&
   624               VerQueryValueW(infoData, L"\\", (LPVOID*) &vInfo, &vInfoLen))
   625           {
   626             fVersion =
   627               ((unsigned long long)vInfo->dwFileVersionMS) << 32 |
   628               ((unsigned long long)vInfo->dwFileVersionLS);
   630             // finally do the version check, and if it's greater than our block
   631             // version, keep loading
   632             if (fVersion > info->maxVersion)
   633               load_ok = true;
   634           }
   635         }
   636       }
   637     }
   639     if (!load_ok) {
   640       printf_stderr("LdrLoadDll: Blocking load of '%s' -- see http://www.mozilla.com/en-US/blocklist/\n", dllName);
   641       DllBlockSet::Add(info->name, fVersion);
   642       return STATUS_DLL_NOT_FOUND;
   643     }
   644   }
   646 continue_loading:
   647 #ifdef DEBUG_very_verbose
   648   printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
   649 #endif
   651   if (GetCurrentThreadId() == sThreadLoadingXPCOMModule) {
   652     // Check to ensure that the DLL has ASLR.
   653     full_fname = getFullPath(filePath, fname);
   654     if (!full_fname) {
   655       // uh, we couldn't find the DLL at all, so...
   656       printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
   657       return STATUS_DLL_NOT_FOUND;
   658     }
   660     if (IsVistaOrLater() && !CheckASLR(full_fname)) {
   661       printf_stderr("LdrLoadDll: Blocking load of '%s'.  XPCOM components must support ASLR.\n", dllName);
   662       return STATUS_DLL_NOT_FOUND;
   663     }
   664   }
   666   return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
   667 }
   669 WindowsDllInterceptor NtDllIntercept;
   671 } // anonymous namespace
   673 NS_EXPORT void
   674 DllBlocklist_Initialize()
   675 {
   676   if (GetModuleHandleA("user32.dll")) {
   677     sUser32BeforeBlocklist = true;
   678   }
   680   NtDllIntercept.Init("ntdll.dll");
   682   ReentrancySentinel::InitializeStatics();
   684   // We specifically use a detour, because there are cases where external
   685   // code also tries to hook LdrLoadDll, and doesn't know how to relocate our
   686   // nop space patches. (Bug 951827)
   687   bool ok = NtDllIntercept.AddDetour("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll);
   689   if (!ok) {
   690     sBlocklistInitFailed = true;
   691 #ifdef DEBUG
   692     printf_stderr ("LdrLoadDll hook failed, no dll blocklisting active\n");
   693 #endif
   694   }
   695 }
   697 NS_EXPORT void
   698 DllBlocklist_SetInXPCOMLoadOnMainThread(bool inXPCOMLoadOnMainThread)
   699 {
   700   if (inXPCOMLoadOnMainThread) {
   701     MOZ_ASSERT(sThreadLoadingXPCOMModule == 0, "Only one thread should be doing this");
   702     sThreadLoadingXPCOMModule = GetCurrentThreadId();
   703   } else {
   704     sThreadLoadingXPCOMModule = 0;
   705   }
   706 }
   708 NS_EXPORT void
   709 DllBlocklist_WriteNotes(HANDLE file)
   710 {
   711   DWORD nBytes;
   713   WriteFile(file, kBlockedDllsParameter, kBlockedDllsParameterLen, &nBytes, nullptr);
   714   DllBlockSet::Write(file);
   715   WriteFile(file, "\n", 1, &nBytes, nullptr);
   717   if (sBlocklistInitFailed) {
   718     WriteFile(file, kBlocklistInitFailedParameter,
   719               kBlocklistInitFailedParameterLen, &nBytes, nullptr);
   720   }
   722   if (sUser32BeforeBlocklist) {
   723     WriteFile(file, kUser32BeforeBlocklistParameter,
   724               kUser32BeforeBlocklistParameterLen, &nBytes, nullptr);
   725   }
   726 }

mercurial