Bug 1475067: Faster handling of UNICODE_STRINGs in bootstrap blocklist; r=mhowell

This commit is contained in:
Aaron Klotz 2018-07-06 18:11:48 -06:00
Родитель fc3ec4ef85
Коммит 9f11895c62
4 изменённых файлов: 56 добавлений и 26 удалений

Просмотреть файл

@ -11,9 +11,19 @@
#include "mozilla/Types.h" #include "mozilla/Types.h"
#include "mozilla/WindowsDllBlocklist.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<wchar_t*>(s) \
}
#define DLL_BLOCKLIST_ENTRY(name, ...) \ #define DLL_BLOCKLIST_ENTRY(name, ...) \
{ L##name, __VA_ARGS__ }, { MOZ_LITERAL_UNICODE_STRING(L##name), __VA_ARGS__ },
#define DLL_BLOCKLIST_CHAR_TYPE wchar_t #define DLL_BLOCKLIST_STRING_TYPE UNICODE_STRING
// Restrict the blocklist definitions to Nightly-only for now // Restrict the blocklist definitions to Nightly-only for now
#if defined(NIGHTLY_BUILD) #if defined(NIGHTLY_BUILD)
@ -34,13 +44,13 @@ class MOZ_STATIC_CLASS MOZ_TRIVIAL_CTOR_DTOR NativeNtBlockSet final
{ {
NativeNtBlockSetEntry() = default; NativeNtBlockSetEntry() = default;
~NativeNtBlockSetEntry() = default; ~NativeNtBlockSetEntry() = default;
NativeNtBlockSetEntry(const wchar_t* aName, uint64_t aVersion, NativeNtBlockSetEntry(const UNICODE_STRING& aName, uint64_t aVersion,
NativeNtBlockSetEntry* aNext) NativeNtBlockSetEntry* aNext)
: mName(aName) : mName(aName)
, mVersion(aVersion) , mVersion(aVersion)
, mNext(aNext) , mNext(aNext)
{} {}
const wchar_t* mName; UNICODE_STRING mName;
uint64_t mVersion; uint64_t mVersion;
NativeNtBlockSetEntry* mNext; NativeNtBlockSetEntry* mNext;
}; };
@ -50,11 +60,12 @@ public:
NativeNtBlockSet() = default; NativeNtBlockSet() = default;
~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); void Write(HANDLE aFile);
private: private:
static NativeNtBlockSetEntry* NewEntry(const wchar_t* aName, uint64_t aVersion, static NativeNtBlockSetEntry* NewEntry(const UNICODE_STRING& aName,
uint64_t aVersion,
NativeNtBlockSetEntry* aNextEntry); NativeNtBlockSetEntry* aNextEntry);
private: private:
@ -65,7 +76,7 @@ private:
}; };
NativeNtBlockSet::NativeNtBlockSetEntry* NativeNtBlockSet::NativeNtBlockSetEntry*
NativeNtBlockSet::NewEntry(const wchar_t* aName, uint64_t aVersion, NativeNtBlockSet::NewEntry(const UNICODE_STRING& aName, uint64_t aVersion,
NativeNtBlockSet::NativeNtBlockSetEntry* aNextEntry) NativeNtBlockSet::NativeNtBlockSetEntry* aNextEntry)
{ {
HANDLE processHeap = mozilla::nt::RtlGetProcessHeap(); HANDLE processHeap = mozilla::nt::RtlGetProcessHeap();
@ -82,14 +93,13 @@ NativeNtBlockSet::NewEntry(const wchar_t* aName, uint64_t aVersion,
} }
void void
NativeNtBlockSet::Add(const wchar_t* aName, uint64_t aVersion) NativeNtBlockSet::Add(const UNICODE_STRING& aName, uint64_t aVersion)
{ {
::RtlAcquireSRWLockExclusive(&mLock); ::RtlAcquireSRWLockExclusive(&mLock);
for (NativeNtBlockSetEntry* entry = mFirstEntry; entry; entry = entry->mNext) { for (NativeNtBlockSetEntry* entry = mFirstEntry; entry; entry = entry->mNext) {
// We just need to compare the string pointers, not the strings themselves, if (::RtlEqualUnicodeString(&entry->mName, &aName, TRUE) &&
// as we always pass in the strings statically defined in the blocklist. aVersion == entry->mVersion) {
if (aName == entry->mName && aVersion == entry->mVersion) {
::RtlReleaseSRWLockExclusive(&mLock); ::RtlReleaseSRWLockExclusive(&mLock);
return; return;
} }
@ -118,8 +128,9 @@ NativeNtBlockSet::Write(HANDLE aFile)
MOZ_SEH_TRY { MOZ_SEH_TRY {
for (auto entry = mFirstEntry; entry; entry = entry->mNext) { for (auto entry = mFirstEntry; entry; entry = entry->mNext) {
int convOk = ::WideCharToMultiByte(CP_UTF8, 0, entry->mName, -1, buf, int convOk = ::WideCharToMultiByte(CP_UTF8, 0, entry->mName.Buffer,
sizeof(buf), nullptr, nullptr); entry->mName.Length / sizeof(wchar_t),
buf, sizeof(buf), nullptr, nullptr);
if (!convOk) { if (!convOk) {
continue; continue;
} }
@ -225,11 +236,11 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress)
return false; return false;
} }
UNICODE_STRING testStr;
DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(info); DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(info);
while (info->name) { DECLARE_POINTER_TO_LAST_DLL_BLOCKLIST_ENTRY(end);
::RtlInitUnicodeString(&testStr, info->name);
if (::RtlEqualUnicodeString(&aLeafName, &testStr, TRUE)) { while (info < end) {
if (::RtlEqualUnicodeString(&aLeafName, &info->name, TRUE)) {
break; break;
} }
@ -237,7 +248,7 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress)
} }
uint64_t version; uint64_t version;
if (info->name && !CheckBlockInfo(info, aBaseAddress, version)) { if (info->name.Length && !CheckBlockInfo(info, aBaseAddress, version)) {
gBlockSet.Add(info->name, version); gBlockSet.Add(info->name, version);
return false; return false;
} }

Просмотреть файл

@ -148,6 +148,13 @@ MatchUnicodeString(const UNICODE_STRING& aStr, bool (*aPredicate)(WCHAR))
inline bool inline bool
Contains12DigitHexString(const UNICODE_STRING& aLeafName) 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; uint16_t start, end;
if (!FindCharInUnicodeString(aLeafName, L'.', start)) { if (!FindCharInUnicodeString(aLeafName, L'.', start)) {
return false; return false;
@ -173,6 +180,13 @@ Contains12DigitHexString(const UNICODE_STRING& aLeafName)
inline bool inline bool
IsFileNameAtLeast16HexDigits(const UNICODE_STRING& aLeafName) 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; uint16_t dotIndex;
if (!FindCharInUnicodeString(aLeafName, L'.', dotIndex)) { if (!FindCharInUnicodeString(aLeafName, L'.', dotIndex)) {
return false; return false;

Просмотреть файл

@ -40,7 +40,7 @@ using namespace mozilla;
#define DLL_BLOCKLIST_ENTRY(name, ...) \ #define DLL_BLOCKLIST_ENTRY(name, ...) \
{ name, __VA_ARGS__ }, { name, __VA_ARGS__ },
#define DLL_BLOCKLIST_CHAR_TYPE char #define DLL_BLOCKLIST_STRING_TYPE const char*
#include "mozilla/WindowsDllBlocklistDefs.h" #include "mozilla/WindowsDllBlocklistDefs.h"
// define this for very verbose dll load debug spew // define this for very verbose dll load debug spew

Просмотреть файл

@ -9,13 +9,15 @@
#include <stdint.h> #include <stdint.h>
#include "mozilla/ArrayUtils.h"
namespace mozilla { namespace mozilla {
template <typename CharType> template <typename StrType>
struct DllBlockInfoT { struct DllBlockInfoT {
// The name of the DLL -- in LOWERCASE! It will be compared to // The name of the DLL -- in LOWERCASE! It will be compared to
// a lowercase version of the DLL name only. // 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 // If maxVersion is ALL_VERSIONS, we'll block all versions of this
// dll. Otherwise, we'll block all versions less than or equal to // 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 #endif
#if !defined(DLL_BLOCKLIST_CHAR_TYPE) #if !defined(DLL_BLOCKLIST_STRING_TYPE)
#error "You must define DLL_BLOCKLIST_CHAR_TYPE" #error "You must define DLL_BLOCKLIST_STRING_TYPE"
#endif // !defined(DLL_BLOCKLIST_CHAR_TYPE) #endif // !defined(DLL_BLOCKLIST_STRING_TYPE)
#define DLL_BLOCKLIST_DEFINITIONS_BEGIN \ #define DLL_BLOCKLIST_DEFINITIONS_BEGIN \
using DllBlockInfo = mozilla::DllBlockInfoT<DLL_BLOCKLIST_CHAR_TYPE>; \ using DllBlockInfo = mozilla::DllBlockInfoT<DLL_BLOCKLIST_STRING_TYPE>; \
static const DllBlockInfo gWindowsDllBlocklist[] = { static const DllBlockInfo gWindowsDllBlocklist[] = {
#define ALL_VERSIONS DllBlockInfo::ALL_VERSIONS #define ALL_VERSIONS DllBlockInfo::ALL_VERSIONS
#define UNVERSIONED DllBlockInfo::UNVERSIONED #define UNVERSIONED DllBlockInfo::UNVERSIONED
#define DLL_BLOCKLIST_DEFINITIONS_END \ #define DLL_BLOCKLIST_DEFINITIONS_END \
{nullptr, 0} \ {} \
}; };
#define DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(name) \ #define DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(name) \
const DllBlockInfo* name = &gWindowsDllBlocklist[0] 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 #endif // mozilla_WindowsDllBlocklistCommon_h