From 9f11895c629fc9e02e901b5be178e15e6364dc1d Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Fri, 6 Jul 2018 18:11:48 -0600 Subject: [PATCH] Bug 1475067: Faster handling of UNICODE_STRINGs in bootstrap blocklist; r=mhowell --- browser/app/winlauncher/DllBlocklistWin.cpp | 47 +++++++++++++-------- browser/app/winlauncher/NativeNt.h | 14 ++++++ mozglue/build/WindowsDllBlocklist.cpp | 2 +- mozglue/build/WindowsDllBlocklistCommon.h | 19 ++++++--- 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/browser/app/winlauncher/DllBlocklistWin.cpp b/browser/app/winlauncher/DllBlocklistWin.cpp index a7c55882e7a4..2ed8bc4dd75e 100644 --- a/browser/app/winlauncher/DllBlocklistWin.cpp +++ b/browser/app/winlauncher/DllBlocklistWin.cpp @@ -11,9 +11,19 @@ #include "mozilla/Types.h" #include "mozilla/WindowsDllBlocklist.h" +#define MOZ_LITERAL_UNICODE_STRING(s) \ + { \ + /* Length of the string in bytes, less the null terminator */ \ + sizeof(s) - sizeof(wchar_t), \ + /* Length of the string in bytes, including the null terminator */ \ + sizeof(s), \ + /* Pointer to the buffer */ \ + const_cast(s) \ + } + #define DLL_BLOCKLIST_ENTRY(name, ...) \ - { L##name, __VA_ARGS__ }, -#define DLL_BLOCKLIST_CHAR_TYPE wchar_t + { MOZ_LITERAL_UNICODE_STRING(L##name), __VA_ARGS__ }, +#define DLL_BLOCKLIST_STRING_TYPE UNICODE_STRING // Restrict the blocklist definitions to Nightly-only for now #if defined(NIGHTLY_BUILD) @@ -34,13 +44,13 @@ class MOZ_STATIC_CLASS MOZ_TRIVIAL_CTOR_DTOR NativeNtBlockSet final { NativeNtBlockSetEntry() = default; ~NativeNtBlockSetEntry() = default; - NativeNtBlockSetEntry(const wchar_t* aName, uint64_t aVersion, + NativeNtBlockSetEntry(const UNICODE_STRING& aName, uint64_t aVersion, NativeNtBlockSetEntry* aNext) : mName(aName) , mVersion(aVersion) , mNext(aNext) {} - const wchar_t* mName; + UNICODE_STRING mName; uint64_t mVersion; NativeNtBlockSetEntry* mNext; }; @@ -50,11 +60,12 @@ public: NativeNtBlockSet() = default; ~NativeNtBlockSet() = default; - void Add(const wchar_t* aName, uint64_t aVersion); + void Add(const UNICODE_STRING& aName, uint64_t aVersion); void Write(HANDLE aFile); private: - static NativeNtBlockSetEntry* NewEntry(const wchar_t* aName, uint64_t aVersion, + static NativeNtBlockSetEntry* NewEntry(const UNICODE_STRING& aName, + uint64_t aVersion, NativeNtBlockSetEntry* aNextEntry); private: @@ -65,7 +76,7 @@ private: }; NativeNtBlockSet::NativeNtBlockSetEntry* -NativeNtBlockSet::NewEntry(const wchar_t* aName, uint64_t aVersion, +NativeNtBlockSet::NewEntry(const UNICODE_STRING& aName, uint64_t aVersion, NativeNtBlockSet::NativeNtBlockSetEntry* aNextEntry) { HANDLE processHeap = mozilla::nt::RtlGetProcessHeap(); @@ -82,14 +93,13 @@ NativeNtBlockSet::NewEntry(const wchar_t* aName, uint64_t aVersion, } void -NativeNtBlockSet::Add(const wchar_t* aName, uint64_t aVersion) +NativeNtBlockSet::Add(const UNICODE_STRING& aName, uint64_t aVersion) { ::RtlAcquireSRWLockExclusive(&mLock); for (NativeNtBlockSetEntry* entry = mFirstEntry; entry; entry = entry->mNext) { - // We just need to compare the string pointers, not the strings themselves, - // as we always pass in the strings statically defined in the blocklist. - if (aName == entry->mName && aVersion == entry->mVersion) { + if (::RtlEqualUnicodeString(&entry->mName, &aName, TRUE) && + aVersion == entry->mVersion) { ::RtlReleaseSRWLockExclusive(&mLock); return; } @@ -118,8 +128,9 @@ NativeNtBlockSet::Write(HANDLE aFile) MOZ_SEH_TRY { for (auto entry = mFirstEntry; entry; entry = entry->mNext) { - int convOk = ::WideCharToMultiByte(CP_UTF8, 0, entry->mName, -1, buf, - sizeof(buf), nullptr, nullptr); + int convOk = ::WideCharToMultiByte(CP_UTF8, 0, entry->mName.Buffer, + entry->mName.Length / sizeof(wchar_t), + buf, sizeof(buf), nullptr, nullptr); if (!convOk) { continue; } @@ -225,11 +236,11 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress) return false; } - UNICODE_STRING testStr; DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(info); - while (info->name) { - ::RtlInitUnicodeString(&testStr, info->name); - if (::RtlEqualUnicodeString(&aLeafName, &testStr, TRUE)) { + DECLARE_POINTER_TO_LAST_DLL_BLOCKLIST_ENTRY(end); + + while (info < end) { + if (::RtlEqualUnicodeString(&aLeafName, &info->name, TRUE)) { break; } @@ -237,7 +248,7 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress) } uint64_t version; - if (info->name && !CheckBlockInfo(info, aBaseAddress, version)) { + if (info->name.Length && !CheckBlockInfo(info, aBaseAddress, version)) { gBlockSet.Add(info->name, version); return false; } diff --git a/browser/app/winlauncher/NativeNt.h b/browser/app/winlauncher/NativeNt.h index a504275343ac..40c087110b96 100644 --- a/browser/app/winlauncher/NativeNt.h +++ b/browser/app/winlauncher/NativeNt.h @@ -148,6 +148,13 @@ MatchUnicodeString(const UNICODE_STRING& aStr, bool (*aPredicate)(WCHAR)) inline bool Contains12DigitHexString(const UNICODE_STRING& aLeafName) { + // Quick check: If the string is too short, don't bother + // (We need at least 12 hex digits, one char for '.', and 3 for extension) + const USHORT kMinLen = (12 + 1 + 3) * sizeof(wchar_t); + if (aLeafName.Length < kMinLen) { + return false; + } + uint16_t start, end; if (!FindCharInUnicodeString(aLeafName, L'.', start)) { return false; @@ -173,6 +180,13 @@ Contains12DigitHexString(const UNICODE_STRING& aLeafName) inline bool IsFileNameAtLeast16HexDigits(const UNICODE_STRING& aLeafName) { + // Quick check: If the string is too short, don't bother + // (We need 16 hex digits, one char for '.', and 3 for extension) + const USHORT kMinLen = (16 + 1 + 3) * sizeof(wchar_t); + if (aLeafName.Length < kMinLen) { + return false; + } + uint16_t dotIndex; if (!FindCharInUnicodeString(aLeafName, L'.', dotIndex)) { return false; diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index da72366774ab..50bd1e88e7b8 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -40,7 +40,7 @@ using namespace mozilla; #define DLL_BLOCKLIST_ENTRY(name, ...) \ { name, __VA_ARGS__ }, -#define DLL_BLOCKLIST_CHAR_TYPE char +#define DLL_BLOCKLIST_STRING_TYPE const char* #include "mozilla/WindowsDllBlocklistDefs.h" // define this for very verbose dll load debug spew diff --git a/mozglue/build/WindowsDllBlocklistCommon.h b/mozglue/build/WindowsDllBlocklistCommon.h index 1b2f871eca7e..1da94c482ae1 100644 --- a/mozglue/build/WindowsDllBlocklistCommon.h +++ b/mozglue/build/WindowsDllBlocklistCommon.h @@ -9,13 +9,15 @@ #include +#include "mozilla/ArrayUtils.h" + namespace mozilla { -template +template struct DllBlockInfoT { // The name of the DLL -- in LOWERCASE! It will be compared to // a lowercase version of the DLL name only. - const CharType* name; + StrType name; // If maxVersion is ALL_VERSIONS, we'll block all versions of this // dll. Otherwise, we'll block all versions less than or equal to @@ -73,22 +75,25 @@ MAKE_VERSION(uint16_t a, uint16_t b, uint16_t c, uint16_t d) #endif -#if !defined(DLL_BLOCKLIST_CHAR_TYPE) -#error "You must define DLL_BLOCKLIST_CHAR_TYPE" -#endif // !defined(DLL_BLOCKLIST_CHAR_TYPE) +#if !defined(DLL_BLOCKLIST_STRING_TYPE) +#error "You must define DLL_BLOCKLIST_STRING_TYPE" +#endif // !defined(DLL_BLOCKLIST_STRING_TYPE) #define DLL_BLOCKLIST_DEFINITIONS_BEGIN \ - using DllBlockInfo = mozilla::DllBlockInfoT; \ + using DllBlockInfo = mozilla::DllBlockInfoT; \ static const DllBlockInfo gWindowsDllBlocklist[] = { #define ALL_VERSIONS DllBlockInfo::ALL_VERSIONS #define UNVERSIONED DllBlockInfo::UNVERSIONED #define DLL_BLOCKLIST_DEFINITIONS_END \ - {nullptr, 0} \ + {} \ }; #define DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(name) \ const DllBlockInfo* name = &gWindowsDllBlocklist[0] +#define DECLARE_POINTER_TO_LAST_DLL_BLOCKLIST_ENTRY(name) \ + const DllBlockInfo* name = &gWindowsDllBlocklist[mozilla::ArrayLength(gWindowsDllBlocklist) - 1] + #endif // mozilla_WindowsDllBlocklistCommon_h