mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1686229 - Part1. Add a member to ModuleLoadInfo to indicate the status of DLL load. r=mhowell
We used to record a DLL loading event only when a module was loaded. With this patch, we record an event for a module blocked by our DLL blocklist as well as a loaded module. It is achieved by calling to `ModuleLoadFrame::NotifySectionMap` in `patched_NtMapViewOfSection` regardless of the block action. This patch introduces a new member `ModuleLoadInfo::mStatus` and `ProcessedModuleLoadEvent::mLoadStatus` to keep the DLL loading status, which will be added to the third-party-modules ping by a following patch. Differential Revision: https://phabricator.services.mozilla.com/D102407
This commit is contained in:
parent
42abfd5b8c
commit
3aef28a656
@ -437,28 +437,41 @@ NTSTATUS NTAPI patched_NtMapViewOfSection(
|
||||
resultView.isOk() ? &resultView.inspect()->mK32Exports : nullptr);
|
||||
}
|
||||
|
||||
if (blockAction == BlockAction::Allow) {
|
||||
if (nt::RtlGetProcessHeap()) {
|
||||
ModuleLoadFrame::NotifySectionMap(
|
||||
nt::AllocatedUnicodeString(sectionFileName), *aBaseAddress,
|
||||
stubStatus);
|
||||
}
|
||||
return stubStatus;
|
||||
ModuleLoadInfo::Status loadStatus = ModuleLoadInfo::Status::Blocked;
|
||||
|
||||
switch (blockAction) {
|
||||
case BlockAction::Allow:
|
||||
loadStatus = ModuleLoadInfo::Status::Loaded;
|
||||
break;
|
||||
|
||||
case BlockAction::NoOpEntryPoint:
|
||||
loadStatus = ModuleLoadInfo::Status::Redirected;
|
||||
break;
|
||||
|
||||
case 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(&leafOnStack);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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(&leafOnStack);
|
||||
if (nt::RtlGetProcessHeap()) {
|
||||
ModuleLoadFrame::NotifySectionMap(
|
||||
nt::AllocatedUnicodeString(sectionFileName), *aBaseAddress, stubStatus,
|
||||
loadStatus);
|
||||
}
|
||||
|
||||
if (blockAction == BlockAction::NoOpEntryPoint) {
|
||||
if (loadStatus == ModuleLoadInfo::Status::Loaded ||
|
||||
loadStatus == ModuleLoadInfo::Status::Redirected) {
|
||||
return stubStatus;
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,13 @@ ModuleLoadFrame::ModuleLoadFrame(PCUNICODE_STRING aRequestedDllName)
|
||||
}
|
||||
|
||||
ModuleLoadFrame::ModuleLoadFrame(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aMapBaseAddr, NTSTATUS aNtStatus)
|
||||
const void* aMapBaseAddr, NTSTATUS aNtStatus,
|
||||
ModuleLoadInfo::Status aLoadStatus)
|
||||
: mPrev(sTopFrame.get()),
|
||||
mContext(nullptr),
|
||||
mLSPSubstitutionRequired(false),
|
||||
mLoadNtStatus(aNtStatus),
|
||||
mLoadInfo(std::move(aSectionName), aMapBaseAddr) {
|
||||
mLoadInfo(std::move(aSectionName), aMapBaseAddr, aLoadStatus) {
|
||||
sTopFrame.set(this);
|
||||
|
||||
gLoaderPrivateAPI.NotifyBeginDllLoad(&mContext, mLoadInfo.mSectionName);
|
||||
@ -69,7 +70,7 @@ void ModuleLoadFrame::SetLSPSubstitutionRequired(PCUNICODE_STRING aLeafName) {
|
||||
/* static */
|
||||
void ModuleLoadFrame::NotifySectionMap(
|
||||
nt::AllocatedUnicodeString&& aSectionName, const void* aMapBaseAddr,
|
||||
NTSTATUS aMapNtStatus) {
|
||||
NTSTATUS aMapNtStatus, ModuleLoadInfo::Status aLoadStatus) {
|
||||
ModuleLoadFrame* topFrame = sTopFrame.get();
|
||||
if (!topFrame) {
|
||||
// The only time that this data is useful is during initial mapping of
|
||||
@ -77,12 +78,14 @@ void ModuleLoadFrame::NotifySectionMap(
|
||||
// IsDefaultObserver will return false, indicating that we are beyond
|
||||
// initial process startup.
|
||||
if (gLoaderPrivateAPI.IsDefaultObserver()) {
|
||||
OnBareSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus);
|
||||
OnBareSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus,
|
||||
aLoadStatus);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
topFrame->OnSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus);
|
||||
topFrame->OnSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus,
|
||||
aLoadStatus);
|
||||
}
|
||||
|
||||
/* static */
|
||||
@ -90,24 +93,28 @@ bool ModuleLoadFrame::ExistsTopFrame() { return !!sTopFrame.get(); }
|
||||
|
||||
void ModuleLoadFrame::OnSectionMap(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aMapBaseAddr,
|
||||
NTSTATUS aMapNtStatus) {
|
||||
NTSTATUS aMapNtStatus,
|
||||
ModuleLoadInfo::Status aLoadStatus) {
|
||||
if (mLoadInfo.mBaseAddr) {
|
||||
// If mBaseAddr is not null then |this| has already seen a module load. This
|
||||
// means that we are witnessing a bare section map.
|
||||
OnBareSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus);
|
||||
OnBareSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus,
|
||||
aLoadStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
mLoadInfo.mSectionName = std::move(aSectionName);
|
||||
mLoadInfo.mBaseAddr = aMapBaseAddr;
|
||||
mLoadInfo.mStatus = aLoadStatus;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void ModuleLoadFrame::OnBareSectionMap(
|
||||
nt::AllocatedUnicodeString&& aSectionName, const void* aMapBaseAddr,
|
||||
NTSTATUS aMapNtStatus) {
|
||||
NTSTATUS aMapNtStatus, ModuleLoadInfo::Status aLoadStatus) {
|
||||
// We call the special constructor variant that is used for bare mappings.
|
||||
ModuleLoadFrame frame(std::move(aSectionName), aMapBaseAddr, aMapNtStatus);
|
||||
ModuleLoadFrame frame(std::move(aSectionName), aMapBaseAddr, aMapNtStatus,
|
||||
aLoadStatus);
|
||||
}
|
||||
|
||||
NTSTATUS ModuleLoadFrame::SetLoadStatus(NTSTATUS aNtStatus,
|
||||
|
@ -36,7 +36,8 @@ class MOZ_RAII ModuleLoadFrame final {
|
||||
* This static method is called by the NtMapViewOfSection hook.
|
||||
*/
|
||||
static void NotifySectionMap(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aMapBaseAddr, NTSTATUS aMapNtStatus);
|
||||
const void* aMapBaseAddr, NTSTATUS aMapNtStatus,
|
||||
ModuleLoadInfo::Status aLoadStatus);
|
||||
static bool ExistsTopFrame();
|
||||
|
||||
/**
|
||||
@ -55,11 +56,13 @@ class MOZ_RAII ModuleLoadFrame final {
|
||||
* Called by OnBareSectionMap to construct a frame for a bare load.
|
||||
*/
|
||||
ModuleLoadFrame(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aMapBaseAddr, NTSTATUS aNtStatus);
|
||||
const void* aMapBaseAddr, NTSTATUS aNtStatus,
|
||||
ModuleLoadInfo::Status aLoadStatus);
|
||||
|
||||
void SetLSPSubstitutionRequired(PCUNICODE_STRING aLeafName);
|
||||
void OnSectionMap(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aMapBaseAddr, NTSTATUS aMapNtStatus);
|
||||
const void* aMapBaseAddr, NTSTATUS aMapNtStatus,
|
||||
ModuleLoadInfo::Status aLoadStatus);
|
||||
|
||||
/**
|
||||
* A "bare" section mapping is one that was mapped without the code passing
|
||||
@ -67,7 +70,8 @@ class MOZ_RAII ModuleLoadFrame final {
|
||||
* that condition.
|
||||
*/
|
||||
static void OnBareSectionMap(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aMapBaseAddr, NTSTATUS aMapNtStatus);
|
||||
const void* aMapBaseAddr, NTSTATUS aMapNtStatus,
|
||||
ModuleLoadInfo::Status aLoadStatus);
|
||||
|
||||
private:
|
||||
// Link to the previous frame
|
||||
|
@ -74,7 +74,10 @@ void LoaderObserver::OnEndDllLoad(void* aContext, NTSTATUS aNtStatus,
|
||||
loadContext->mDynamicStringStorage.get()));
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(aNtStatus) || !aModuleLoadInfo.WasMapped()) {
|
||||
// We want to record a denied DLL load regardless of |aNtStatus| because
|
||||
// |aNtStatus| is set to access-denied when DLL load was blocked.
|
||||
if ((!NT_SUCCESS(aNtStatus) && !aModuleLoadInfo.WasDenied()) ||
|
||||
!aModuleLoadInfo.WasMapped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,12 @@
|
||||
namespace mozilla {
|
||||
|
||||
struct ModuleLoadInfo final {
|
||||
enum class Status : uint32_t {
|
||||
Loaded = 0,
|
||||
Blocked,
|
||||
Redirected,
|
||||
};
|
||||
|
||||
// We do not provide these methods inside Gecko proper.
|
||||
#if !defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
@ -24,7 +30,8 @@ struct ModuleLoadInfo final {
|
||||
: mLoadTimeInfo(),
|
||||
mThreadId(nt::RtlGetCurrentThreadId()),
|
||||
mRequestedDllName(aRequestedDllName),
|
||||
mBaseAddr(nullptr) {
|
||||
mBaseAddr(nullptr),
|
||||
mStatus(Status::Loaded) {
|
||||
# if defined(IMPL_MFBT)
|
||||
::QueryPerformanceCounter(&mBeginTimestamp);
|
||||
# else
|
||||
@ -39,11 +46,12 @@ struct ModuleLoadInfo final {
|
||||
* of another library.
|
||||
*/
|
||||
ModuleLoadInfo(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aBaseAddr)
|
||||
const void* aBaseAddr, Status aLoadStatus)
|
||||
: mLoadTimeInfo(),
|
||||
mThreadId(nt::RtlGetCurrentThreadId()),
|
||||
mSectionName(std::move(aSectionName)),
|
||||
mBaseAddr(aBaseAddr) {
|
||||
mBaseAddr(aBaseAddr),
|
||||
mStatus(aLoadStatus) {
|
||||
# if defined(IMPL_MFBT)
|
||||
::QueryPerformanceCounter(&mBeginTimestamp);
|
||||
# else
|
||||
@ -127,6 +135,14 @@ struct ModuleLoadInfo final {
|
||||
*/
|
||||
bool WasMapped() const { return !mSectionName.IsEmpty(); }
|
||||
|
||||
/**
|
||||
* Returns true for DLL load which was denied by our blocklist.
|
||||
*/
|
||||
bool WasDenied() const {
|
||||
return mStatus == ModuleLoadInfo::Status::Blocked ||
|
||||
mStatus == ModuleLoadInfo::Status::Redirected;
|
||||
}
|
||||
|
||||
// Timestamp for the creation of this event
|
||||
LARGE_INTEGER mBeginTimestamp;
|
||||
// Duration of the LdrLoadDll call
|
||||
@ -143,6 +159,8 @@ struct ModuleLoadInfo final {
|
||||
const void* mBaseAddr;
|
||||
// If the module was successfully loaded, stack trace of the DLL load request
|
||||
Vector<PVOID, 0, nt::RtlAllocPolicy> mBacktrace;
|
||||
// The status of DLL load
|
||||
Status mStatus;
|
||||
};
|
||||
|
||||
using ModuleLoadInfoVec = Vector<ModuleLoadInfo, 0, nt::RtlAllocPolicy>;
|
||||
|
@ -200,7 +200,8 @@ ProcessedModuleLoadEvent::ProcessedModuleLoadEvent()
|
||||
: mProcessUptimeMS(0ULL),
|
||||
mThreadId(0UL),
|
||||
mBaseAddress(0U),
|
||||
mIsDependent(false) {}
|
||||
mIsDependent(false),
|
||||
mLoadStatus(0) {}
|
||||
|
||||
ProcessedModuleLoadEvent::ProcessedModuleLoadEvent(
|
||||
glue::EnhancedModuleLoadInfo&& aModLoadInfo,
|
||||
@ -213,7 +214,8 @@ ProcessedModuleLoadEvent::ProcessedModuleLoadEvent(
|
||||
mBaseAddress(
|
||||
reinterpret_cast<uintptr_t>(aModLoadInfo.mNtLoadInfo.mBaseAddr)),
|
||||
mModule(std::move(aModuleRecord)),
|
||||
mIsDependent(aIsDependent) {
|
||||
mIsDependent(aIsDependent),
|
||||
mLoadStatus(static_cast<uint32_t>(aModLoadInfo.mNtLoadInfo.mStatus)) {
|
||||
if (!mModule || !(*mModule)) {
|
||||
return;
|
||||
}
|
||||
|
@ -145,6 +145,7 @@ class ProcessedModuleLoadEvent final {
|
||||
uintptr_t mBaseAddress;
|
||||
RefPtr<ModuleRecord> mModule;
|
||||
bool mIsDependent;
|
||||
uint32_t mLoadStatus; // corresponding to enum ModuleLoadInfo::Status
|
||||
|
||||
ProcessedModuleLoadEvent(const ProcessedModuleLoadEvent&) = delete;
|
||||
ProcessedModuleLoadEvent& operator=(const ProcessedModuleLoadEvent&) = delete;
|
||||
@ -515,6 +516,7 @@ struct ParamTraits<mozilla::UntrustedModulesData> {
|
||||
WriteParam(aMsg, aParam.mRequestedDllName);
|
||||
WriteParam(aMsg, aParam.mBaseAddress);
|
||||
WriteParam(aMsg, aParam.mIsDependent);
|
||||
WriteParam(aMsg, aParam.mLoadStatus);
|
||||
|
||||
// We don't write the ModuleRecord directly; we write its key into the
|
||||
// UntrustedModulesData::mModules hash table.
|
||||
@ -556,6 +558,10 @@ struct ParamTraits<mozilla::UntrustedModulesData> {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadParam(aMsg, aIter, &aResult->mLoadStatus)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString resolvedNtName;
|
||||
if (!ReadParam(aMsg, aIter, &resolvedNtName)) {
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user