diff --git a/mozglue/build/MozglueUtils.h b/mozglue/build/MozglueUtils.h new file mode 100644 index 000000000000..6ebdd984840b --- /dev/null +++ b/mozglue/build/MozglueUtils.h @@ -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 + +#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 diff --git a/mozglue/build/UntrustedDllsHandler.cpp b/mozglue/build/UntrustedDllsHandler.cpp new file mode 100644 index 000000000000..4e0dcd5f3ff0 --- /dev/null +++ b/mozglue/build/UntrustedDllsHandler.cpp @@ -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 + +#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 +CopyString(const UniquePtr& aOther) +{ + if (!aOther) { + return nullptr; + } + size_t chars = wcslen(aOther.get()); + auto ret = MakeUnique(chars + 1); + if (wcsncpy_s(ret.get(), chars + 1, aOther.get(), chars)) { + return nullptr; + } + return ret; +} + +// Creates a UniquePtr from a PCUNICODE_STRING string. +// Upon error, returns nullptr. +static UniquePtr +CopyString(PCUNICODE_STRING aOther) +{ + if (!aOther || !aOther->Buffer) { + return nullptr; + } + size_t chars = aOther->Length / sizeof(wchar_t); + auto ret = MakeUnique(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 +GetModuleFullPath(uintptr_t aModuleBase) +{ + size_t allocated = MAX_PATH; + auto ret = MakeUnique(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(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 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 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 sInstanceHasBeenSet; + + // Singleton reference + static StaticRefPtr sInstance; + + // Holds a list of module load events. This gets emptied upon calling + // UntrustedDllsHandler::TakePendingEvents + Vector mModuleLoadEvents; + + // Holds a list of module full paths that we've already handled, so we can + // skip duplicates. + Vector> 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 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 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(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& aOut) + { + // Hold a reference to ensure we don't get deleted during this call. + RefPtr refHolder(this); + if (!refHolder) { + return false; + } + + AutoCriticalSection lock(&mDataLock); + mModuleLoadEvents.swap(aOut); + return !aOut.empty(); + } +}; + +Atomic UntrustedDllsHandlerImpl::sInstanceHasBeenSet; +StaticRefPtr 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 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& aOut) +{ + RefPtr p(UntrustedDllsHandlerImpl::GetInstance()); + if (!p) { + return false; + } + return p->TakePendingEvents(aOut); +} + +} // namespace glue +} // namespace mozilla diff --git a/mozglue/build/UntrustedDllsHandler.h b/mozglue/build/UntrustedDllsHandler.h new file mode 100644 index 000000000000..917cf84dcd1f --- /dev/null +++ b/mozglue/build/UntrustedDllsHandler.h @@ -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 +#include // 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& aOut); +}; + +} // namespace glue +} // namespace mozilla + +#endif // mozilla_glue_UntrustedDllsHandler_h + diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index b22565389e5d..8068b267e759 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -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 @@ -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 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 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; #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 events; + if (glue::UntrustedDllsHandler::TakePendingEvents(events)) { + gDllServices->NotifyUntrustedModuleLoads(events); + } + } +} diff --git a/mozglue/build/WindowsDllServices.h b/mozglue/build/WindowsDllServices.h index 9e86374de7ce..6ad3e4355649 100644 --- a/mozglue/build/WindowsDllServices.h +++ b/mozglue/build/WindowsDllServices.h @@ -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 mLdrName; + UniquePtr 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 mModules; + + // Stores instruction pointers, top-to-bottom. + Vector 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& 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& aEvents) override {} }; #endif // defined(MOZILLA_INTERNAL_API) diff --git a/mozglue/build/moz.build b/mozglue/build/moz.build index bf086fb154f7..5a32598445b6 100644 --- a/mozglue/build/moz.build +++ b/mozglue/build/moz.build @@ -67,6 +67,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT']: SOURCES += ['WindowsCFGStatus.cpp'] SOURCES += [ 'Authenticode.cpp', + 'UntrustedDllsHandler.cpp', 'WindowsDllBlocklist.cpp', ] diff --git a/toolkit/xre/WinDllServices.cpp b/toolkit/xre/WinDllServices.cpp index 244104130a14..9063ded05266 100644 --- a/toolkit/xre/WinDllServices.cpp +++ b/toolkit/xre/WinDllServices.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& aEvents) +{ +} + +}// namespace mozilla diff --git a/toolkit/xre/WinDllServices.h b/toolkit/xre/WinDllServices.h index fb0ae15f4a01..be11ae35d4d1 100644 --- a/toolkit/xre/WinDllServices.h +++ b/toolkit/xre/WinDllServices.h @@ -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& aEvents) override; }; } // namespace mozilla