mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1587642 - Make the blocklist work when the process heap is not initialized. r=aklotz
`patched_NtMapViewOfSection` uses the process default heap to copy a string. However, `patched_NtMapViewOfSection` can be invoked even before the process heap is initialized. One example we found is Windows Defender's EAF, with which "verifier.dll" is loaded before the process heap is initialized. This patch adds a check whether the heap is initialized or not in `patched_NtMapViewOfSection` and `NativeNtBlockSet::Add`. This also minimizes the usage of the heap, i.e. not copying a string when we block a dll. Differential Revision: https://phabricator.services.mozilla.com/D51028 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
a1a57a8bc5
commit
bd457a84a8
@ -90,7 +90,9 @@ void NativeNtBlockSet::Add(const UNICODE_STRING& aName, uint64_t aVersion) {
|
||||
|
||||
// Not present, add it
|
||||
NativeNtBlockSetEntry* newEntry = NewEntry(aName, aVersion, mFirstEntry);
|
||||
mFirstEntry = newEntry;
|
||||
if (newEntry) {
|
||||
mFirstEntry = newEntry;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeNtBlockSet::Write(HANDLE aFile) {
|
||||
@ -311,30 +313,39 @@ NTSTATUS NTAPI patched_NtMapViewOfSection(
|
||||
}
|
||||
|
||||
// Get the section name
|
||||
nt::AllocatedUnicodeString sectionFileName(
|
||||
gLoaderPrivateAPI.GetSectionName(*aBaseAddress));
|
||||
nt::MemorySectionNameBuf sectionFileName(
|
||||
gLoaderPrivateAPI.GetSectionNameBuffer(*aBaseAddress));
|
||||
if (sectionFileName.IsEmpty()) {
|
||||
::NtUnmapViewOfSection(aProcess, *aBaseAddress);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
// Find the leaf name
|
||||
UNICODE_STRING leaf;
|
||||
nt::GetLeafName(&leaf, sectionFileName);
|
||||
UNICODE_STRING leafOnStack;
|
||||
nt::GetLeafName(&leafOnStack, sectionFileName);
|
||||
|
||||
// Check blocklist
|
||||
BlockAction blockAction = IsDllAllowed(leaf, *aBaseAddress);
|
||||
BlockAction blockAction = IsDllAllowed(leafOnStack, *aBaseAddress);
|
||||
|
||||
if (blockAction == BlockAction::Allow) {
|
||||
ModuleLoadFrame::NotifySectionMap(std::move(sectionFileName), *aBaseAddress,
|
||||
stubStatus);
|
||||
if (nt::RtlGetProcessHeap()) {
|
||||
ModuleLoadFrame::NotifySectionMap(
|
||||
nt::AllocatedUnicodeString(sectionFileName), *aBaseAddress,
|
||||
stubStatus);
|
||||
}
|
||||
return stubStatus;
|
||||
}
|
||||
|
||||
if (blockAction == BlockAction::SubstituteLSP) {
|
||||
// The process heap needs to be available here because
|
||||
// NotifyLSPSubstitutionRequired below copies a given string into the heap.
|
||||
// We use a soft assert here, assuming LSP load always occurs after the heap
|
||||
// is initialized.
|
||||
MOZ_ASSERT(nt::RtlGetProcessHeap());
|
||||
|
||||
// Notify patched_LdrLoadDll that it will be necessary to perform a
|
||||
// substitution before returning.
|
||||
ModuleLoadFrame::NotifyLSPSubstitutionRequired(&leaf);
|
||||
ModuleLoadFrame::NotifyLSPSubstitutionRequired(&leafOnStack);
|
||||
}
|
||||
|
||||
::NtUnmapViewOfSection(aProcess, *aBaseAddress);
|
||||
|
@ -29,7 +29,14 @@ namespace freestanding {
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
inline static T* RtlNew(Args&&... aArgs) {
|
||||
void* ptr = ::RtlAllocateHeap(nt::RtlGetProcessHeap(), 0, sizeof(T));
|
||||
HANDLE processHeap = nt::RtlGetProcessHeap();
|
||||
if (!processHeap) {
|
||||
// Handle the case where the process heap is not initialized because
|
||||
// passing nullptr to RtlAllocateHeap crashes the process.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* ptr = ::RtlAllocateHeap(processHeap, 0, sizeof(T));
|
||||
if (!ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS LoaderPrivateAPIImp final
|
||||
void NotifyEndDllLoad(void* aContext, NTSTATUS aLoadNtStatus,
|
||||
ModuleLoadInfo&& aModuleLoadInfo) final;
|
||||
nt::AllocatedUnicodeString GetSectionName(void* aSectionAddr) final;
|
||||
nt::MemorySectionNameBuf GetSectionNameBuffer(void* aSectionAddr) final;
|
||||
|
||||
// LoaderPrivateAPI
|
||||
void NotifyBeginDllLoad(void** aContext,
|
||||
@ -207,6 +208,21 @@ nt::AllocatedUnicodeString LoaderPrivateAPIImp::GetSectionName(
|
||||
return nt::AllocatedUnicodeString(&buf.mSectionFileName);
|
||||
}
|
||||
|
||||
nt::MemorySectionNameBuf LoaderPrivateAPIImp::GetSectionNameBuffer(
|
||||
void* aSectionAddr) {
|
||||
const HANDLE kCurrentProcess = reinterpret_cast<HANDLE>(-1);
|
||||
|
||||
nt::MemorySectionNameBuf buf;
|
||||
NTSTATUS ntStatus =
|
||||
::NtQueryVirtualMemory(kCurrentProcess, aSectionAddr, MemorySectionName,
|
||||
&buf, sizeof(buf), nullptr);
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
return nt::MemorySectionNameBuf();
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void LoaderPrivateAPIImp::NotifyBeginDllLoad(
|
||||
void** aContext, PCUNICODE_STRING aRequestedDllName) {
|
||||
nt::AutoSharedLock lock(gLoaderObserverLock);
|
||||
|
@ -41,6 +41,12 @@ class NS_NO_VTABLE LoaderPrivateAPI : public nt::LoaderAPI {
|
||||
* built-in observer.
|
||||
*/
|
||||
virtual bool IsDefaultObserver() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the name of a given mapped section address as a local instance of
|
||||
* nt::MemorySectionNameBuf. This does not involve heap allocation.
|
||||
*/
|
||||
virtual nt::MemorySectionNameBuf GetSectionNameBuffer(void* aSectionAddr) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -242,6 +242,12 @@ struct MemorySectionNameBuf : public _MEMORY_SECTION_NAME {
|
||||
|
||||
// Native NT paths, so we can't assume MAX_PATH. Use a larger buffer.
|
||||
WCHAR mBuf[2 * MAX_PATH];
|
||||
|
||||
bool IsEmpty() const {
|
||||
return !mSectionFileName.Buffer || !mSectionFileName.Length;
|
||||
}
|
||||
|
||||
operator PCUNICODE_STRING() const { return &mSectionFileName; }
|
||||
};
|
||||
|
||||
inline bool FindCharInUnicodeString(const UNICODE_STRING& aStr, WCHAR aChar,
|
||||
|
Loading…
Reference in New Issue
Block a user