зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1435827 part 1/9: Send DLL load event info to xul;r=aklotz
We now record DLL load events along with stack trace and other data so we can later determine trustworthiness and report the DLL via telemetry. Differential Revision: https://phabricator.services.mozilla.com/D7175 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
7a42d37605
Коммит
13f66b51b6
|
@ -0,0 +1,66 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_glue_MozglueUtils_h
|
||||
#define mozilla_glue_MozglueUtils_h
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
class MOZ_RAII AutoSharedLock final
|
||||
{
|
||||
public:
|
||||
explicit AutoSharedLock(SRWLOCK& aLock)
|
||||
: mLock(aLock)
|
||||
{
|
||||
::AcquireSRWLockShared(&aLock);
|
||||
}
|
||||
|
||||
~AutoSharedLock()
|
||||
{
|
||||
::ReleaseSRWLockShared(&mLock);
|
||||
}
|
||||
|
||||
AutoSharedLock(const AutoSharedLock&) = delete;
|
||||
AutoSharedLock(AutoSharedLock&&) = delete;
|
||||
AutoSharedLock& operator=(const AutoSharedLock&) = delete;
|
||||
AutoSharedLock& operator=(AutoSharedLock&&) = delete;
|
||||
|
||||
private:
|
||||
SRWLOCK& mLock;
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoExclusiveLock final
|
||||
{
|
||||
public:
|
||||
explicit AutoExclusiveLock(SRWLOCK& aLock)
|
||||
: mLock(aLock)
|
||||
{
|
||||
::AcquireSRWLockExclusive(&aLock);
|
||||
}
|
||||
|
||||
~AutoExclusiveLock()
|
||||
{
|
||||
::ReleaseSRWLockExclusive(&mLock);
|
||||
}
|
||||
|
||||
AutoExclusiveLock(const AutoExclusiveLock&) = delete;
|
||||
AutoExclusiveLock(AutoExclusiveLock&&) = delete;
|
||||
AutoExclusiveLock& operator=(const AutoExclusiveLock&) = delete;
|
||||
AutoExclusiveLock& operator=(AutoExclusiveLock&&) = delete;
|
||||
|
||||
private:
|
||||
SRWLOCK& mLock;
|
||||
};
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_glue_MozglueUtils_h
|
|
@ -0,0 +1,356 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifdef MOZ_MEMORY
|
||||
#define MOZ_MEMORY_IMPL
|
||||
#include "mozmemory_wrap.h"
|
||||
#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
|
||||
// See mozmemory_wrap.h for more details. This file is part of libmozglue, so
|
||||
// it needs to use _impl suffixes.
|
||||
#define MALLOC_DECL(name, return_type, ...) \
|
||||
MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__);
|
||||
#include "malloc_decls.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#endif
|
||||
|
||||
#include "UntrustedDllsHandler.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsWindowsHelpers.h" // For AutoCriticalSection
|
||||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
// Copies a null-terminated string. Upon error, returns nullptr.
|
||||
static UniquePtr<wchar_t[]>
|
||||
CopyString(const UniquePtr<wchar_t[]>& aOther)
|
||||
{
|
||||
if (!aOther) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t chars = wcslen(aOther.get());
|
||||
auto ret = MakeUnique<wchar_t[]>(chars + 1);
|
||||
if (wcsncpy_s(ret.get(), chars + 1, aOther.get(), chars)) {
|
||||
return nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Creates a UniquePtr<wchar_t[]> from a PCUNICODE_STRING string.
|
||||
// Upon error, returns nullptr.
|
||||
static UniquePtr<wchar_t[]>
|
||||
CopyString(PCUNICODE_STRING aOther)
|
||||
{
|
||||
if (!aOther || !aOther->Buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t chars = aOther->Length / sizeof(wchar_t);
|
||||
auto ret = MakeUnique<wchar_t[]>(chars + 1);
|
||||
if (wcsncpy_s(ret.get(), chars + 1, aOther->Buffer, chars)) {
|
||||
return nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Basic wrapper around ::GetModuleFileNameW.
|
||||
// Returns the full path of the loaded module specified by aModuleBase.
|
||||
// Upon error, returns nullptr.
|
||||
static UniquePtr<wchar_t[]>
|
||||
GetModuleFullPath(uintptr_t aModuleBase)
|
||||
{
|
||||
size_t allocated = MAX_PATH;
|
||||
auto ret = MakeUnique<wchar_t[]>(allocated);
|
||||
size_t len;
|
||||
while (true) {
|
||||
len = (size_t)::GetModuleFileNameW((HMODULE)aModuleBase, ret.get(),
|
||||
allocated);
|
||||
if (!len) {
|
||||
return nullptr;
|
||||
}
|
||||
if (len == allocated && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
allocated *= 2;
|
||||
ret = MakeUnique<wchar_t[]>(allocated);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// The buffer may much bigger than needed. Return an efficiently-allocated
|
||||
// buffer.
|
||||
return CopyString(ret);
|
||||
}
|
||||
|
||||
// To track call depth and recursively-loaded modules, we must store this data
|
||||
// in thread local storage.
|
||||
class TLSData
|
||||
{
|
||||
public:
|
||||
Vector<ModuleLoadEvent::ModuleInfo, 0, InfallibleAllocPolicy> mModulesLoaded;
|
||||
int mCallDepth = 0;
|
||||
};
|
||||
|
||||
static MOZ_THREAD_LOCAL(TLSData*) sTlsData;
|
||||
|
||||
// This singleton class does the underlying work for UntrustedDllsHandler
|
||||
class UntrustedDllsHandlerImpl
|
||||
{
|
||||
// Refcounting gives us a way to synchronize call lifetime vs object lifetime.
|
||||
// We don't have access to NS_INLINE_DECL_THREADSAFE_REFCOUNTING from mozglue,
|
||||
// but it's easy to roll our own.
|
||||
Atomic<int32_t> mRefCnt;
|
||||
|
||||
// In order to prevent sInstance from being "woken back up" after it's been
|
||||
// cleared on shutdown, this will let us know if sInstance is empty because
|
||||
// it's not initialized yet, or because it's been cleared on shutdown.
|
||||
static Atomic<bool> sInstanceHasBeenSet;
|
||||
|
||||
// Singleton reference
|
||||
static StaticRefPtr<UntrustedDllsHandlerImpl> sInstance;
|
||||
|
||||
// Holds a list of module load events. This gets emptied upon calling
|
||||
// UntrustedDllsHandler::TakePendingEvents
|
||||
Vector<ModuleLoadEvent, 0, InfallibleAllocPolicy> mModuleLoadEvents;
|
||||
|
||||
// Holds a list of module full paths that we've already handled, so we can
|
||||
// skip duplicates.
|
||||
Vector<mozilla::UniquePtr<wchar_t[]>> mModuleHistory;
|
||||
|
||||
// This lock protects gModuleLoadEvents and gModuleHistory.
|
||||
//
|
||||
// You must only make trivial, loader-lock-friendly calls within the lock. We
|
||||
// cannot risk re-entering the loader at this point.
|
||||
CRITICAL_SECTION mDataLock;
|
||||
|
||||
UntrustedDllsHandlerImpl()
|
||||
{
|
||||
InitializeCriticalSection(&mDataLock);
|
||||
}
|
||||
|
||||
~UntrustedDllsHandlerImpl()
|
||||
{
|
||||
{ // Scope for lock
|
||||
// Ensure pending ops are complete.
|
||||
AutoCriticalSection lock(&mDataLock);
|
||||
}
|
||||
DeleteCriticalSection(&mDataLock);
|
||||
}
|
||||
|
||||
public:
|
||||
static RefPtr<UntrustedDllsHandlerImpl> GetInstance()
|
||||
{
|
||||
if (sInstanceHasBeenSet) {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
sInstance = new UntrustedDllsHandlerImpl();
|
||||
sInstanceHasBeenSet = true;
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
static void Shutdown()
|
||||
{
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
int32_t AddRef()
|
||||
{
|
||||
return ++mRefCnt;
|
||||
}
|
||||
|
||||
int32_t Release()
|
||||
{
|
||||
int32_t ret = --mRefCnt;
|
||||
if (!ret) {
|
||||
delete this;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Called after a successful module load at the top level. Now we are safe
|
||||
// to package up the event and save for later processing.
|
||||
void OnAfterTopLevelModuleLoad()
|
||||
{
|
||||
// Hold a reference to ensure we don't get deleted during this call.
|
||||
RefPtr<UntrustedDllsHandlerImpl> refHolder(this);
|
||||
if (!refHolder) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleLoadEvent thisEvent;
|
||||
|
||||
TLSData* tlsData = sTlsData.get();
|
||||
if (!tlsData) {
|
||||
return;
|
||||
}
|
||||
|
||||
{ // Scope for lock
|
||||
// Lock around gModuleHistory to prune out modules we've handled before.
|
||||
// Only trivial calls allowed during lock (don't invoke the loader)
|
||||
AutoCriticalSection lock(&mDataLock);
|
||||
|
||||
// There will rarely be more than a couple items in tlsData->mModulesLoaded,
|
||||
// so this is efficient enough.
|
||||
for (auto& module : tlsData->mModulesLoaded) {
|
||||
if (module.mFullPath && wcslen(module.mFullPath.get())) {
|
||||
bool foundInHistory = false;
|
||||
for (auto& h : mModuleHistory) {
|
||||
if (!wcsicmp(h.get(), module.mFullPath.get())) {
|
||||
foundInHistory = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundInHistory) {
|
||||
continue;
|
||||
}
|
||||
Unused << mModuleHistory.append(CopyString(module.mFullPath));
|
||||
}
|
||||
Unused << thisEvent.mModules.emplaceBack(std::move(module));
|
||||
}
|
||||
}
|
||||
|
||||
tlsData->mModulesLoaded.clear();
|
||||
|
||||
if (thisEvent.mModules.empty()) {
|
||||
return; // All modules have been filtered out; nothing further to do.
|
||||
}
|
||||
|
||||
thisEvent.mThreadID = GetCurrentThreadId();
|
||||
|
||||
TimeStamp processCreation = TimeStamp::ProcessCreation();
|
||||
TimeDuration td = TimeStamp::Now() - processCreation;
|
||||
thisEvent.mProcessUptimeMS = (uint64_t)td.ToMilliseconds();
|
||||
|
||||
static const uint32_t kMaxFrames = 500;
|
||||
auto frames = MakeUnique<void*[]>(kMaxFrames);
|
||||
|
||||
// Setting FramesToSkip to 1 so the caller will see itself as the top frame.
|
||||
USHORT frameCount = CaptureStackBackTrace(1, kMaxFrames, frames.get(), nullptr);
|
||||
if (thisEvent.mStack.reserve(frameCount)) {
|
||||
for (size_t i = 0; i < frameCount; ++i) {
|
||||
Unused << thisEvent.mStack.append((uintptr_t)frames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Lock in order to store the new event.
|
||||
// Only trivial calls allowed during lock (don't invoke the loader)
|
||||
AutoCriticalSection lock(&mDataLock);
|
||||
Unused << mModuleLoadEvents.emplaceBack(std::move(thisEvent));
|
||||
}
|
||||
|
||||
// Returns true if aOut is no longer empty.
|
||||
bool TakePendingEvents(Vector<ModuleLoadEvent, 0, InfallibleAllocPolicy>& aOut)
|
||||
{
|
||||
// Hold a reference to ensure we don't get deleted during this call.
|
||||
RefPtr<UntrustedDllsHandlerImpl> refHolder(this);
|
||||
if (!refHolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoCriticalSection lock(&mDataLock);
|
||||
mModuleLoadEvents.swap(aOut);
|
||||
return !aOut.empty();
|
||||
}
|
||||
};
|
||||
|
||||
Atomic<bool> UntrustedDllsHandlerImpl::sInstanceHasBeenSet;
|
||||
StaticRefPtr<UntrustedDllsHandlerImpl> UntrustedDllsHandlerImpl::sInstance;
|
||||
|
||||
/* static */
|
||||
void
|
||||
UntrustedDllsHandler::Init()
|
||||
{
|
||||
Unused << sTlsData.init();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* static */
|
||||
void
|
||||
UntrustedDllsHandler::Shutdown()
|
||||
{
|
||||
UntrustedDllsHandlerImpl::Shutdown();
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
/* static */
|
||||
void
|
||||
UntrustedDllsHandler::EnterLoaderCall()
|
||||
{
|
||||
if (!sTlsData.initialized()) {
|
||||
return;
|
||||
}
|
||||
if (!sTlsData.get()) {
|
||||
sTlsData.set(new TLSData());
|
||||
}
|
||||
sTlsData.get()->mCallDepth++;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
UntrustedDllsHandler::ExitLoaderCall()
|
||||
{
|
||||
if (!sTlsData.initialized()) {
|
||||
return;
|
||||
}
|
||||
if (!--(sTlsData.get()->mCallDepth)) {
|
||||
delete sTlsData.get();
|
||||
sTlsData.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
UntrustedDllsHandler::OnAfterModuleLoad(uintptr_t aBaseAddr,
|
||||
PUNICODE_STRING aLdrModuleName)
|
||||
{
|
||||
RefPtr<UntrustedDllsHandlerImpl> p(UntrustedDllsHandlerImpl::GetInstance());
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sTlsData.initialized()) {
|
||||
return;
|
||||
}
|
||||
TLSData* tlsData = sTlsData.get();
|
||||
if (!tlsData) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleLoadEvent::ModuleInfo moduleInfo;
|
||||
moduleInfo.mLdrName = CopyString(aLdrModuleName);
|
||||
moduleInfo.mBase = aBaseAddr;
|
||||
moduleInfo.mFullPath = GetModuleFullPath(aBaseAddr);
|
||||
|
||||
Unused << tlsData->mModulesLoaded.emplaceBack(std::move(moduleInfo));
|
||||
|
||||
if (tlsData->mCallDepth > 1) {
|
||||
// Recursive call; bail and wait until top-level call can proceed.
|
||||
return;
|
||||
}
|
||||
|
||||
p->OnAfterTopLevelModuleLoad();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
UntrustedDllsHandler::TakePendingEvents(
|
||||
Vector<ModuleLoadEvent, 0, InfallibleAllocPolicy>& aOut)
|
||||
{
|
||||
RefPtr<UntrustedDllsHandlerImpl> p(UntrustedDllsHandlerImpl::GetInstance());
|
||||
if (!p) {
|
||||
return false;
|
||||
}
|
||||
return p->TakePendingEvents(aOut);
|
||||
}
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_glue_UntrustedDllsHandler_h
|
||||
#define mozilla_glue_UntrustedDllsHandler_h
|
||||
|
||||
#include <windows.h>
|
||||
#include <winternl.h> // For PUNICODE_STRING
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/glue/WindowsDllServices.h" // For ModuleLoadEvent
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
// This class examines successful module loads, converts them to a
|
||||
// glue::ModuleLoadEvent, and stores them for consumption by the caller.
|
||||
// In the process, we capture data about the event that is later used to
|
||||
// evaluate trustworthiness of the module.
|
||||
class UntrustedDllsHandler
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
|
||||
#ifdef DEBUG
|
||||
static void Shutdown();
|
||||
#endif // DEBUG
|
||||
|
||||
/**
|
||||
* To prevent issues with re-entrancy, we only capture module load events at
|
||||
* the top-level call. Recursive module loads get bundled with the top-level
|
||||
* module load. In order to do that, we must track when LdrLoadDLL() enters
|
||||
* and exits, to detect recursion.
|
||||
*
|
||||
* EnterLoaderCall() must be called at the top of LdrLoadDLL(), and
|
||||
* ExitLoaderCall() must be called when LdrLoadDLL() exits.
|
||||
*
|
||||
* These methods may be called even outside of Init() / Shutdown().
|
||||
*/
|
||||
static void EnterLoaderCall();
|
||||
static void ExitLoaderCall();
|
||||
|
||||
/**
|
||||
* OnAfterModuleLoad should be called between calls to EnterLoaderCall() and
|
||||
* ExitLoaderCall(). This handles the successful module load and records it
|
||||
* internally if needed. To handle the resulting recorded event, call
|
||||
* TakePendingEvents().
|
||||
*
|
||||
* This method may be called even outside of Init() / Shutdown().
|
||||
*/
|
||||
static void OnAfterModuleLoad(uintptr_t aBaseAddr,
|
||||
PUNICODE_STRING aLdrModuleName);
|
||||
|
||||
/**
|
||||
* Call TakePendingEvents to get any events that have been recorded since
|
||||
* the last call to TakePendingEvents().
|
||||
*
|
||||
* This method may be called even outside of Init() / Shutdown().
|
||||
*
|
||||
* @param aOut [out] Receives a list of events.
|
||||
* @return true if aOut now contains elements.
|
||||
*/
|
||||
static bool
|
||||
TakePendingEvents(Vector<ModuleLoadEvent, 0, InfallibleAllocPolicy>& aOut);
|
||||
};
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_glue_UntrustedDllsHandler_h
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
#define MALLOC_DECL(name, return_type, ...) \
|
||||
MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__);
|
||||
#include "malloc_decls.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
@ -25,8 +26,11 @@
|
|||
|
||||
#include "Authenticode.h"
|
||||
#include "CrashAnnotations.h"
|
||||
#include "MozglueUtils.h"
|
||||
#include "UntrustedDllsHandler.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsWindowsDllInterceptor.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/StackWalk_windows.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
@ -42,6 +46,9 @@ using namespace mozilla;
|
|||
using CrashReporter::Annotation;
|
||||
using CrashReporter::AnnotationToString;
|
||||
|
||||
static SRWLOCK gDllServicesLock = SRWLOCK_INIT;
|
||||
static glue::detail::DllServicesBase* gDllServices;
|
||||
|
||||
#define DLL_BLOCKLIST_ENTRY(name, ...) \
|
||||
{ name, __VA_ARGS__ },
|
||||
#define DLL_BLOCKLIST_STRING_TYPE const char*
|
||||
|
@ -80,6 +87,16 @@ printf_stderr(const char *fmt, ...)
|
|||
fclose(fp);
|
||||
}
|
||||
|
||||
// This feature is enabled only on NIGHTLY, only for the main process.
|
||||
inline static bool
|
||||
IsUntrustedDllsHandlerEnabled()
|
||||
{
|
||||
#ifdef NIGHTLY_BUILD
|
||||
return !(sInitFlags & eDllBlocklistInitFlagIsChildProcess);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef MOZ_NORETURN_PTR void (__fastcall* BaseThreadInitThunk_func)(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam);
|
||||
static WindowsDllInterceptor::FuncHookType<BaseThreadInitThunk_func> stub_BaseThreadInitThunk;
|
||||
|
@ -454,6 +471,16 @@ DllBlocklist_TestBlocklistIntegrity()
|
|||
static NTSTATUS NTAPI
|
||||
patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle)
|
||||
{
|
||||
if (IsUntrustedDllsHandlerEnabled()) {
|
||||
glue::UntrustedDllsHandler::EnterLoaderCall();
|
||||
}
|
||||
// Warning: this must be at the top function scope.
|
||||
auto exitLoaderCallScopeExit = MakeScopeExit([]() {
|
||||
if (IsUntrustedDllsHandlerEnabled()) {
|
||||
glue::UntrustedDllsHandler::ExitLoaderCall();
|
||||
}
|
||||
});
|
||||
|
||||
// We have UCS2 (UTF16?), we want ASCII, but we also just want the filename portion
|
||||
#define DLLNAME_MAX 128
|
||||
char dllName[DLLNAME_MAX+1];
|
||||
|
@ -650,8 +677,27 @@ continue_loading:
|
|||
// holds the RtlLookupFunctionEntry lock.
|
||||
AutoSuppressStackWalking suppress;
|
||||
#endif
|
||||
NTSTATUS ret;
|
||||
HANDLE myHandle;
|
||||
ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
|
||||
if (handle) {
|
||||
*handle = myHandle;
|
||||
}
|
||||
|
||||
if (IsUntrustedDllsHandlerEnabled() && NT_SUCCESS(ret)) {
|
||||
// Win32 HMODULEs use the bottom two bits as flags. Ensure those bits are
|
||||
// cleared so we're left with the base address value.
|
||||
glue::UntrustedDllsHandler::OnAfterModuleLoad(
|
||||
(uintptr_t)myHandle & ~(uintptr_t)3, moduleFileName);
|
||||
glue::AutoSharedLock lock(gDllServicesLock);
|
||||
if (gDllServices) {
|
||||
Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy> events;
|
||||
if (glue::UntrustedDllsHandler::TakePendingEvents(events)) {
|
||||
gDllServices->NotifyUntrustedModuleLoads(events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS ret = stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
|
||||
CallDllLoadHook(NT_SUCCESS(ret), ret, handle ? *handle : 0, moduleFileName);
|
||||
return ret;
|
||||
}
|
||||
|
@ -732,6 +778,10 @@ DllBlocklist_Initialize(uint32_t aInitFlags)
|
|||
gStartAddressesToBlock = new mozilla::Vector<void*, 4>;
|
||||
#endif
|
||||
|
||||
if (IsUntrustedDllsHandlerEnabled()) {
|
||||
glue::UntrustedDllsHandler::Init();
|
||||
}
|
||||
|
||||
// In order to be effective against AppInit DLLs, the blocklist must be
|
||||
// initialized before user32.dll is loaded into the process (bug 932100).
|
||||
if (GetModuleHandleA("user32.dll")) {
|
||||
|
@ -821,6 +871,9 @@ DllBlocklist_Initialize(uint32_t aInitFlags)
|
|||
MFBT_API void
|
||||
DllBlocklist_Shutdown()
|
||||
{
|
||||
if (IsUntrustedDllsHandlerEnabled()) {
|
||||
glue::UntrustedDllsHandler::Shutdown();
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
|
@ -884,56 +937,6 @@ DllBlocklist_CheckStatus()
|
|||
// This section is for DLL Services
|
||||
// ============================================================================
|
||||
|
||||
|
||||
static SRWLOCK gDllServicesLock = SRWLOCK_INIT;
|
||||
static mozilla::glue::detail::DllServicesBase* gDllServices;
|
||||
|
||||
class MOZ_RAII AutoSharedLock final
|
||||
{
|
||||
public:
|
||||
explicit AutoSharedLock(SRWLOCK& aLock)
|
||||
: mLock(aLock)
|
||||
{
|
||||
::AcquireSRWLockShared(&aLock);
|
||||
}
|
||||
|
||||
~AutoSharedLock()
|
||||
{
|
||||
::ReleaseSRWLockShared(&mLock);
|
||||
}
|
||||
|
||||
AutoSharedLock(const AutoSharedLock&) = delete;
|
||||
AutoSharedLock(AutoSharedLock&&) = delete;
|
||||
AutoSharedLock& operator=(const AutoSharedLock&) = delete;
|
||||
AutoSharedLock& operator=(AutoSharedLock&&) = delete;
|
||||
|
||||
private:
|
||||
SRWLOCK& mLock;
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoExclusiveLock final
|
||||
{
|
||||
public:
|
||||
explicit AutoExclusiveLock(SRWLOCK& aLock)
|
||||
: mLock(aLock)
|
||||
{
|
||||
::AcquireSRWLockExclusive(&aLock);
|
||||
}
|
||||
|
||||
~AutoExclusiveLock()
|
||||
{
|
||||
::ReleaseSRWLockExclusive(&mLock);
|
||||
}
|
||||
|
||||
AutoExclusiveLock(const AutoExclusiveLock&) = delete;
|
||||
AutoExclusiveLock(AutoExclusiveLock&&) = delete;
|
||||
AutoExclusiveLock& operator=(const AutoExclusiveLock&) = delete;
|
||||
AutoExclusiveLock& operator=(AutoExclusiveLock&&) = delete;
|
||||
|
||||
private:
|
||||
SRWLOCK& mLock;
|
||||
};
|
||||
|
||||
// These types are documented on MSDN but not provided in any SDK headers
|
||||
|
||||
enum DllNotificationReason
|
||||
|
@ -986,7 +989,7 @@ DllLoadNotification(ULONG aReason, PCLDR_DLL_NOTIFICATION_DATA aNotificationData
|
|||
return;
|
||||
}
|
||||
|
||||
AutoSharedLock lock(gDllServicesLock);
|
||||
glue::AutoSharedLock lock(gDllServicesLock);
|
||||
if (!gDllServices) {
|
||||
return;
|
||||
}
|
||||
|
@ -1002,8 +1005,7 @@ Authenticode* GetAuthenticode();
|
|||
MFBT_API void
|
||||
DllBlocklist_SetDllServices(mozilla::glue::detail::DllServicesBase* aSvc)
|
||||
{
|
||||
AutoExclusiveLock lock(gDllServicesLock);
|
||||
|
||||
glue::AutoExclusiveLock lock(gDllServicesLock);
|
||||
if (aSvc) {
|
||||
aSvc->SetAuthenticodeImpl(GetAuthenticode());
|
||||
|
||||
|
@ -1022,5 +1024,11 @@ DllBlocklist_SetDllServices(mozilla::glue::detail::DllServicesBase* aSvc)
|
|||
}
|
||||
|
||||
gDllServices = aSvc;
|
||||
}
|
||||
|
||||
if (IsUntrustedDllsHandlerEnabled() && gDllServices) {
|
||||
Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy> events;
|
||||
if (glue::UntrustedDllsHandler::TakePendingEvents(events)) {
|
||||
gDllServices->NotifyUntrustedModuleLoads(events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Authenticode.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
|
@ -26,6 +29,45 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
// Holds data about a top-level DLL load event, for the purposes of later
|
||||
// evaluating the DLLs for trustworthiness. DLLs are loaded recursively,
|
||||
// so we hold the top-level DLL and all child DLLs in mModules.
|
||||
class ModuleLoadEvent
|
||||
{
|
||||
public:
|
||||
class ModuleInfo
|
||||
{
|
||||
public:
|
||||
ModuleInfo() = default;
|
||||
~ModuleInfo() = default;
|
||||
ModuleInfo(const ModuleInfo& aOther) = delete;
|
||||
ModuleInfo(ModuleInfo&& aOther) = default;
|
||||
|
||||
ModuleInfo operator =(const ModuleInfo& aOther) = delete;
|
||||
ModuleInfo operator =(ModuleInfo&& aOther) = delete;
|
||||
|
||||
uintptr_t mBase;
|
||||
UniquePtr<wchar_t[]> mLdrName;
|
||||
UniquePtr<wchar_t[]> mFullPath;
|
||||
};
|
||||
|
||||
ModuleLoadEvent() = default;
|
||||
~ModuleLoadEvent() = default;
|
||||
ModuleLoadEvent(const ModuleLoadEvent& aOther) = delete;
|
||||
ModuleLoadEvent(ModuleLoadEvent&& aOther) = default;
|
||||
|
||||
ModuleLoadEvent& operator =(const ModuleLoadEvent& aOther) = delete;
|
||||
ModuleLoadEvent& operator =(ModuleLoadEvent&& aOther) = delete;
|
||||
|
||||
DWORD mThreadID;
|
||||
uint64_t mProcessUptimeMS;
|
||||
Vector<ModuleInfo, 0, InfallibleAllocPolicy> mModules;
|
||||
|
||||
// Stores instruction pointers, top-to-bottom.
|
||||
Vector<uintptr_t, 0, InfallibleAllocPolicy> mStack;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
class DllServicesBase : public Authenticode
|
||||
|
@ -39,6 +81,16 @@ public:
|
|||
*/
|
||||
virtual void DispatchDllLoadNotification(PCUNICODE_STRING aDllName) = 0;
|
||||
|
||||
/**
|
||||
* This function accepts module load events to be processed later for
|
||||
* the untrusted modules telemetry ping.
|
||||
*
|
||||
* WARNING: This method is run from within the Windows loader and should
|
||||
* only perform trivial, loader-friendly, operations.
|
||||
*/
|
||||
virtual void NotifyUntrustedModuleLoads(
|
||||
const Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy>& aEvents) = 0;
|
||||
|
||||
void SetAuthenticodeImpl(Authenticode* aAuthenticode)
|
||||
{
|
||||
mAuthenticode = aAuthenticode;
|
||||
|
@ -142,6 +194,9 @@ public:
|
|||
}
|
||||
|
||||
virtual void DispatchDllLoadNotification(PCUNICODE_STRING aDllName) override {}
|
||||
|
||||
virtual void NotifyUntrustedModuleLoads(
|
||||
const Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy>& aEvents) override {}
|
||||
};
|
||||
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
|
|
@ -67,6 +67,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|||
SOURCES += ['WindowsCFGStatus.cpp']
|
||||
SOURCES += [
|
||||
'Authenticode.cpp',
|
||||
'UntrustedDllsHandler.cpp',
|
||||
'WindowsDllBlocklist.cpp',
|
||||
]
|
||||
|
||||
|
|
|
@ -50,5 +50,11 @@ DllServices::NotifyDllLoad(const bool aIsMainThread, const nsString& aDllName)
|
|||
obsServ->NotifyObservers(nullptr, topic, aDllName.get());
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
void
|
||||
DllServices::NotifyUntrustedModuleLoads(
|
||||
const Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy>& aEvents)
|
||||
{
|
||||
}
|
||||
|
||||
}// namespace mozilla
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#define mozilla_WinDllServices_h
|
||||
|
||||
#include "mozilla/glue/WindowsDllServices.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -24,6 +26,9 @@ private:
|
|||
~DllServices() = default;
|
||||
|
||||
void NotifyDllLoad(const bool aIsMainThread, const nsString& aDllName) override;
|
||||
|
||||
void NotifyUntrustedModuleLoads(
|
||||
const Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy>& aEvents) override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
Загрузка…
Ссылка в новой задаче