forked from mirrors/gecko-dev
Bug 1542830: Part 4 - Modify mozglue to use new untrusted modules interfaces; r=mhowell
* At this point our DLL blocking infra is complicated enough that I decided to bite the bullet and move all of this code out of `mozglue/build` and into its own subdirectory, `mozglue/dllservices`. * We delete the original `UntrustedDllsHandler` code which is now obsolete. * We implement mozglue's `LoaderObserver`: ** When this observer registers itself with the launcher process API, it receives a vector containing all saved records of loaded DLLs that happened until that moment. ** This code handles profiler labels and stackwalking suppression. ** Once a load has completed, we either pass the load on to XUL for further processing, or save it for later if XUL is not initialized yet. * mozglue has its own `ModuleLoadFrame` implementation for the legacy blocklist. * `DllServicesBase` is updated to support the new interfaces. * We implement `FallbackLoaderAPI` for `plugin-container`, `xpcshell`, and any other non-`firefox` processes that do not have a launcher process providing a loader API. * We add some wide to UTF8 conversion functions. Depends on D43157 Differential Revision: https://phabricator.services.mozilla.com/D43158 --HG-- rename : mozglue/build/Authenticode.cpp => mozglue/dllservices/Authenticode.cpp rename : mozglue/build/Authenticode.h => mozglue/dllservices/Authenticode.h rename : browser/app/winlauncher/freestanding/LoaderAPIInterfaces.h => mozglue/dllservices/LoaderAPIInterfaces.h rename : browser/app/winlauncher/freestanding/ModuleLoadInfo.h => mozglue/dllservices/ModuleLoadInfo.h rename : browser/app/winlauncher/NtLoaderAPI.h => mozglue/dllservices/NtLoaderAPI.h rename : mozglue/build/WindowsDllBlocklist.cpp => mozglue/dllservices/WindowsDllBlocklist.cpp rename : mozglue/build/WindowsDllBlocklist.h => mozglue/dllservices/WindowsDllBlocklist.h rename : mozglue/build/WindowsDllBlocklistCommon.h => mozglue/dllservices/WindowsDllBlocklistCommon.h rename : mozglue/build/WindowsDllBlocklistDefs.in => mozglue/dllservices/WindowsDllBlocklistDefs.in rename : mozglue/build/WindowsDllServices.h => mozglue/dllservices/WindowsDllServices.h rename : mozglue/build/gen_dll_blocklist_defs.py => mozglue/dllservices/gen_dll_blocklist_defs.py rename : mozglue/build/moz.build => mozglue/dllservices/moz.build rename : mozglue/build/MozglueUtils.h => mozglue/misc/WinUtils.h extra : moz-landing-system : lando
This commit is contained in:
parent
f9be0e1c7f
commit
fccd6eb9ba
36 changed files with 707 additions and 705 deletions
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#ifdef XP_WIN
|
||||
# include "LauncherProcessWin.h"
|
||||
# include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
# define XRE_WANT_ENVIRON
|
||||
# define strcasecmp _stricmp
|
||||
|
|
@ -38,7 +39,6 @@
|
|||
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/StartupTimeline.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
#include "BaseProfiler.h"
|
||||
|
||||
#ifdef LIBFUZZER
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef mozilla_freestanding_LoaderPrivateAPI_h
|
||||
#define mozilla_freestanding_LoaderPrivateAPI_h
|
||||
|
||||
#include "LoaderAPIInterfaces.h"
|
||||
#include "mozilla/LoaderAPIInterfaces.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace freestanding {
|
||||
|
|
|
|||
|
|
@ -13,11 +13,6 @@ FORCE_STATIC_LIB = True
|
|||
# that might call an import.
|
||||
NO_PGO = True
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'LoaderAPIInterfaces.h',
|
||||
'ModuleLoadInfo.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DllBlocklist.cpp',
|
||||
'LoaderPrivateAPI.cpp',
|
||||
|
|
|
|||
|
|
@ -8,10 +8,6 @@ Library('winlauncher')
|
|||
|
||||
FORCE_STATIC_LIB = True
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'NtLoaderAPI.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'/ipc/mscom/ProcessRuntime.cpp',
|
||||
'/widget/windows/WindowsConsole.cpp',
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
#include "../contentproc/plugin-container.cpp"
|
||||
|
||||
#include "mozilla/Bootstrap.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
#if defined(XP_WIN)
|
||||
# include "mozilla/WindowsDllBlocklist.h"
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/mscom/ProcessRuntimeShared.h"
|
||||
#include "MozglueUtils.h"
|
||||
|
||||
#include "mozilla/glue/WinUtils.h"
|
||||
|
||||
// We allow multiple ProcessRuntime instances to exist simultaneously (even
|
||||
// on separate threads), but only one should be doing the process-wide
|
||||
|
|
|
|||
|
|
@ -10,10 +10,6 @@ EXPORTS.mozilla.mscom += [
|
|||
'ProcessRuntimeShared.h',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/mozglue/build',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ProcessRuntimeShared.cpp',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
#include "mozilla/Bootstrap.h"
|
||||
|
||||
#include "nsXULAppAPI.h"
|
||||
|
|
@ -16,6 +15,8 @@
|
|||
# include "xpcshellMacUtils.h"
|
||||
#endif
|
||||
#ifdef XP_WIN
|
||||
# include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
# include <windows.h>
|
||||
# include <shlobj.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,310 +0,0 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#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,
|
||||
double aLoadDurationMS) {
|
||||
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);
|
||||
moduleInfo.mLoadDurationMS = aLoadDurationMS;
|
||||
|
||||
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
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/* -*- 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,
|
||||
double aLoadDurationMS);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
@ -58,48 +58,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|||
'/memory/build',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'Authenticode.cpp',
|
||||
'UntrustedDllsHandler.cpp',
|
||||
'WindowsDllBlocklist.cpp',
|
||||
]
|
||||
|
||||
OS_LIBS += [
|
||||
'crypt32',
|
||||
'version',
|
||||
'wintrust',
|
||||
]
|
||||
DELAYLOAD_DLLS += [
|
||||
'crypt32.dll',
|
||||
'wintrust.dll',
|
||||
]
|
||||
EXPORTS.mozilla += [
|
||||
'Authenticode.h',
|
||||
'WindowsDllBlocklistCommon.h',
|
||||
]
|
||||
EXPORTS.mozilla.glue += [
|
||||
'WindowsDllServices.h',
|
||||
]
|
||||
|
||||
# Generate DLL Blocklists
|
||||
blocklist_header_types = ['A11y', 'Launcher', 'Legacy', 'Test']
|
||||
blocklist_file_leaf_tpl = 'WindowsDllBlocklist{0}Defs.h'
|
||||
blocklist_files = tuple([blocklist_file_leaf_tpl.format(type)
|
||||
for type in blocklist_header_types])
|
||||
GENERATED_FILES += [
|
||||
blocklist_files
|
||||
]
|
||||
blocklist_defs = GENERATED_FILES[blocklist_files]
|
||||
blocklist_defs.script = 'gen_dll_blocklist_defs.py:gen_blocklists'
|
||||
blocklist_defs.inputs = ['WindowsDllBlocklistDefs.in']
|
||||
EXPORTS.mozilla += ['!' + hdr for hdr in blocklist_files]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'arm.h',
|
||||
'mips.h',
|
||||
'ppc.h',
|
||||
'SSE.h',
|
||||
'WindowsDllBlocklist.h',
|
||||
]
|
||||
|
||||
if CONFIG['CPU_ARCH'].startswith('x86'):
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_LoaderAPIInternal_h
|
||||
#define mozilla_LoaderAPIInternal_h
|
||||
#ifndef mozilla_LoaderAPIInterfaces_h
|
||||
#define mozilla_LoaderAPIInterfaces_h
|
||||
|
||||
#include "mozilla/ModuleLoadInfo.h"
|
||||
|
||||
|
|
@ -97,4 +97,4 @@ class NS_NO_VTABLE LoaderAPI {
|
|||
} // namespace nt
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_LoaderAPIInternal_h
|
||||
#endif // mozilla_LoaderAPIInterfaces_h
|
||||
150
mozglue/dllservices/LoaderObserver.cpp
Normal file
150
mozglue/dllservices/LoaderObserver.cpp
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "LoaderObserver.h"
|
||||
|
||||
#include "mozilla/AutoProfilerLabel.h"
|
||||
#include "mozilla/glue/WindowsUnicode.h"
|
||||
#include "mozilla/StackWalk_windows.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct LoadContext {
|
||||
LoadContext(mozilla::ProfilerLabel&& aLabel,
|
||||
mozilla::UniquePtr<char[]>&& aDynamicStringStorage)
|
||||
: mProfilerLabel(std::move(aLabel)),
|
||||
mDynamicStringStorage(std::move(aDynamicStringStorage)) {}
|
||||
mozilla::ProfilerLabel mProfilerLabel;
|
||||
mozilla::UniquePtr<char[]> mDynamicStringStorage;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern glue::Win32SRWLock gDllServicesLock;
|
||||
extern glue::detail::DllServicesBase* gDllServices;
|
||||
|
||||
namespace glue {
|
||||
|
||||
void LoaderObserver::OnBeginDllLoad(void** aContext,
|
||||
PCUNICODE_STRING aRequestedDllName) {
|
||||
MOZ_ASSERT(aContext);
|
||||
if (IsProfilerPresent()) {
|
||||
UniquePtr<char[]> utf8RequestedDllName(WideToUTF8(aRequestedDllName));
|
||||
const char* dynamicString = utf8RequestedDllName.get();
|
||||
*aContext = new LoadContext(
|
||||
ProfilerLabelBegin("mozilla::glue::LoaderObserver::OnBeginDllLoad",
|
||||
dynamicString, &aContext),
|
||||
std::move(utf8RequestedDllName));
|
||||
}
|
||||
|
||||
#ifdef _M_AMD64
|
||||
// Prevent the stack walker from suspending this thread when LdrLoadDll
|
||||
// holds the RtlLookupFunctionEntry lock.
|
||||
SuppressStackWalking();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LoaderObserver::SubstituteForLSP(PCUNICODE_STRING aLSPLeafName,
|
||||
PHANDLE aOutHandle) {
|
||||
// Currently unsupported
|
||||
return false;
|
||||
}
|
||||
|
||||
void LoaderObserver::OnEndDllLoad(void* aContext, NTSTATUS aNtStatus,
|
||||
ModuleLoadInfo&& aModuleLoadInfo) {
|
||||
#ifdef _M_AMD64
|
||||
DesuppressStackWalking();
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT_IF(IsProfilerPresent(), aContext);
|
||||
UniquePtr<LoadContext> loadContext(static_cast<LoadContext*>(aContext));
|
||||
if (loadContext && IsValidProfilerLabel(loadContext->mProfilerLabel)) {
|
||||
ProfilerLabelEnd(loadContext->mProfilerLabel);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(aNtStatus) || !aModuleLoadInfo.WasMapped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{ // Scope for lock
|
||||
AutoSharedLock lock(gDllServicesLock);
|
||||
if (gDllServices) {
|
||||
gDllServices->DispatchDllLoadNotification(std::move(aModuleLoadInfo));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No dll services, save for later
|
||||
AutoExclusiveLock lock(mLock);
|
||||
if (!mModuleLoads) {
|
||||
mModuleLoads = new ModuleLoadInfoVec();
|
||||
}
|
||||
|
||||
Unused << mModuleLoads->emplaceBack(
|
||||
std::forward<ModuleLoadInfo>(aModuleLoadInfo));
|
||||
}
|
||||
|
||||
void LoaderObserver::Forward(nt::LoaderObserver* aNext) {
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"This implementation does not forward to any more "
|
||||
"nt::LoaderObserver objects");
|
||||
}
|
||||
|
||||
void LoaderObserver::Forward(detail::DllServicesBase* aNext) {
|
||||
MOZ_ASSERT(aNext);
|
||||
if (!aNext) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleLoadInfoVec* moduleLoads = nullptr;
|
||||
|
||||
{ // Scope for lock
|
||||
AutoExclusiveLock lock(mLock);
|
||||
moduleLoads = mModuleLoads;
|
||||
mModuleLoads = nullptr;
|
||||
}
|
||||
|
||||
if (!moduleLoads) {
|
||||
return;
|
||||
}
|
||||
|
||||
aNext->DispatchModuleLoadBacklogNotification(std::move(*moduleLoads));
|
||||
delete moduleLoads;
|
||||
}
|
||||
|
||||
void LoaderObserver::Clear() {
|
||||
ModuleLoadInfoVec* moduleLoads = nullptr;
|
||||
|
||||
{ // Scope for lock
|
||||
AutoExclusiveLock lock(mLock);
|
||||
moduleLoads = mModuleLoads;
|
||||
mModuleLoads = nullptr;
|
||||
}
|
||||
|
||||
delete moduleLoads;
|
||||
}
|
||||
|
||||
void LoaderObserver::OnForward(ModuleLoadInfoVec&& aInfo) {
|
||||
AutoExclusiveLock lock(mLock);
|
||||
if (!mModuleLoads) {
|
||||
mModuleLoads = new ModuleLoadInfoVec();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mModuleLoads->empty());
|
||||
if (mModuleLoads->empty()) {
|
||||
*mModuleLoads = std::move(aInfo);
|
||||
} else {
|
||||
// This should not happen, but we can handle it
|
||||
for (auto&& item : aInfo) {
|
||||
Unused << mModuleLoads->append(std::move(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
||||
44
mozglue/dllservices/LoaderObserver.h
Normal file
44
mozglue/dllservices/LoaderObserver.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- 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_LoaderObserver_h
|
||||
#define mozilla_glue_LoaderObserver_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LoaderAPIInterfaces.h"
|
||||
#include "mozilla/glue/WindowsDllServices.h"
|
||||
#include "mozilla/glue/WinUtils.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS LoaderObserver final
|
||||
: public nt::LoaderObserver {
|
||||
public:
|
||||
constexpr LoaderObserver() : mModuleLoads(nullptr) {}
|
||||
|
||||
void OnBeginDllLoad(void** aContext,
|
||||
PCUNICODE_STRING aPreliminaryDllName) final;
|
||||
bool SubstituteForLSP(PCUNICODE_STRING aLspLeafName,
|
||||
PHANDLE aOutHandle) final;
|
||||
void OnEndDllLoad(void* aContext, NTSTATUS aNtStatus,
|
||||
ModuleLoadInfo&& aModuleLoadInfo) final;
|
||||
void Forward(nt::LoaderObserver* aNext) final;
|
||||
void OnForward(ModuleLoadInfoVec&& aInfo) final;
|
||||
|
||||
void Forward(mozilla::glue::detail::DllServicesBase* aSvc);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
Win32SRWLock mLock;
|
||||
ModuleLoadInfoVec* mModuleLoads;
|
||||
};
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_glue_LoaderObserver_h
|
||||
88
mozglue/dllservices/ModuleLoadFrame.cpp
Normal file
88
mozglue/dllservices/ModuleLoadFrame.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "ModuleLoadFrame.h"
|
||||
#include "mozilla/NativeNt.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "NtLoaderAPI.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "WindowsFallbackLoaderAPI.h"
|
||||
|
||||
static bool IsNullTerminated(PCUNICODE_STRING aStr) {
|
||||
return aStr && (aStr->MaximumLength >= (aStr->Length + sizeof(WCHAR))) &&
|
||||
aStr->Buffer && aStr->Buffer[aStr->Length / sizeof(WCHAR)] == 0;
|
||||
}
|
||||
|
||||
static mozilla::FallbackLoaderAPI gFallbackLoaderAPI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
nt::LoaderAPI* ModuleLoadFrame::sLoaderAPI;
|
||||
|
||||
using GetNtLoaderAPIFn = decltype(&mozilla::GetNtLoaderAPI);
|
||||
|
||||
/* static */
|
||||
void ModuleLoadFrame::StaticInit(nt::LoaderObserver* aNewObserver) {
|
||||
const auto pGetNtLoaderAPI = reinterpret_cast<GetNtLoaderAPIFn>(
|
||||
::GetProcAddress(::GetModuleHandleW(nullptr), "GetNtLoaderAPI"));
|
||||
if (!pGetNtLoaderAPI) {
|
||||
// This case occurs in processes other than firefox.exe that do not contain
|
||||
// the launcher process blocklist.
|
||||
gFallbackLoaderAPI.SetObserver(aNewObserver);
|
||||
sLoaderAPI = &gFallbackLoaderAPI;
|
||||
return;
|
||||
}
|
||||
|
||||
sLoaderAPI = pGetNtLoaderAPI(aNewObserver);
|
||||
}
|
||||
|
||||
ModuleLoadFrame::ModuleLoadFrame(PCUNICODE_STRING aRequestedDllName)
|
||||
: mAlreadyLoaded(false),
|
||||
mContext(nullptr),
|
||||
mDllLoadStatus(STATUS_UNSUCCESSFUL),
|
||||
mLoadInfo(sLoaderAPI->ConstructAndNotifyBeginDllLoad(&mContext,
|
||||
aRequestedDllName)) {
|
||||
if (!aRequestedDllName) {
|
||||
return;
|
||||
}
|
||||
|
||||
UniquePtr<WCHAR[]> nameBuf;
|
||||
const WCHAR* name = nullptr;
|
||||
|
||||
if (IsNullTerminated(aRequestedDllName)) {
|
||||
name = aRequestedDllName->Buffer;
|
||||
} else {
|
||||
USHORT charLenExclNul = aRequestedDllName->Length / sizeof(WCHAR);
|
||||
USHORT charLenInclNul = charLenExclNul + 1;
|
||||
nameBuf = MakeUnique<WCHAR[]>(charLenInclNul);
|
||||
if (!wcsncpy_s(nameBuf.get(), charLenInclNul, aRequestedDllName->Buffer,
|
||||
charLenExclNul)) {
|
||||
name = nameBuf.get();
|
||||
}
|
||||
}
|
||||
|
||||
mAlreadyLoaded = name && !!::GetModuleHandleW(name);
|
||||
}
|
||||
|
||||
ModuleLoadFrame::~ModuleLoadFrame() {
|
||||
sLoaderAPI->NotifyEndDllLoad(mContext, mDllLoadStatus, std::move(mLoadInfo));
|
||||
}
|
||||
|
||||
void ModuleLoadFrame::SetLoadStatus(NTSTATUS aNtStatus, HANDLE aHandle) {
|
||||
mDllLoadStatus = aNtStatus;
|
||||
void* baseAddr = mozilla::nt::PEHeaders::HModuleToBaseAddr(
|
||||
reinterpret_cast<HMODULE>(aHandle));
|
||||
mLoadInfo.mBaseAddr = baseAddr;
|
||||
if (!mAlreadyLoaded) {
|
||||
mLoadInfo.mSectionName = sLoaderAPI->GetSectionName(baseAddr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
||||
43
mozglue/dllservices/ModuleLoadFrame.h
Normal file
43
mozglue/dllservices/ModuleLoadFrame.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- 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_ModuleLoadFrame_h
|
||||
#define mozilla_glue_ModuleLoadFrame_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LoaderAPIInterfaces.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
class MOZ_RAII ModuleLoadFrame final {
|
||||
public:
|
||||
explicit ModuleLoadFrame(PCUNICODE_STRING aRequestedDllName);
|
||||
~ModuleLoadFrame();
|
||||
|
||||
void SetLoadStatus(NTSTATUS aNtStatus, HANDLE aHandle);
|
||||
|
||||
ModuleLoadFrame(const ModuleLoadFrame&) = delete;
|
||||
ModuleLoadFrame(ModuleLoadFrame&&) = delete;
|
||||
ModuleLoadFrame& operator=(const ModuleLoadFrame&) = delete;
|
||||
ModuleLoadFrame& operator=(ModuleLoadFrame&&) = delete;
|
||||
|
||||
static void StaticInit(nt::LoaderObserver* aNewObserver);
|
||||
|
||||
private:
|
||||
bool mAlreadyLoaded;
|
||||
void* mContext;
|
||||
NTSTATUS mDllLoadStatus;
|
||||
ModuleLoadInfo mLoadInfo;
|
||||
|
||||
private:
|
||||
static nt::LoaderAPI* sLoaderAPI;
|
||||
};
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_glue_ModuleLoadFrame_h
|
||||
|
|
@ -14,8 +14,6 @@
|
|||
#include "Authenticode.h"
|
||||
#include "BaseProfiler.h"
|
||||
#include "CrashAnnotations.h"
|
||||
#include "MozglueUtils.h"
|
||||
#include "UntrustedDllsHandler.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsWindowsDllInterceptor.h"
|
||||
#include "mozilla/CmdLineAndEnvUtils.h"
|
||||
|
|
@ -32,15 +30,25 @@
|
|||
#include "mozilla/AutoProfilerLabel.h"
|
||||
#include "mozilla/glue/Debug.h"
|
||||
#include "mozilla/glue/WindowsDllServices.h"
|
||||
#include "mozilla/glue/WinUtils.h"
|
||||
|
||||
// Start new implementation
|
||||
#include "LoaderObserver.h"
|
||||
#include "ModuleLoadFrame.h"
|
||||
#include "mozilla/glue/WindowsUnicode.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
glue::Win32SRWLock gDllServicesLock;
|
||||
glue::detail::DllServicesBase* gDllServices;
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
using CrashReporter::Annotation;
|
||||
using CrashReporter::AnnotationToString;
|
||||
|
||||
static glue::Win32SRWLock gDllServicesLock;
|
||||
static glue::detail::DllServicesBase* gDllServices;
|
||||
|
||||
#define DLL_BLOCKLIST_ENTRY(name, ...) {name, __VA_ARGS__},
|
||||
#define DLL_BLOCKLIST_STRING_TYPE const char*
|
||||
#include "mozilla/WindowsDllBlocklistLegacyDefs.h"
|
||||
|
|
@ -53,15 +61,6 @@ static bool sBlocklistInitAttempted;
|
|||
static bool sBlocklistInitFailed;
|
||||
static bool sUser32BeforeBlocklist;
|
||||
|
||||
// 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>
|
||||
|
|
@ -337,16 +336,6 @@ static wchar_t* lastslash(wchar_t* s, int len) {
|
|||
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
|
||||
|
|
@ -516,63 +505,35 @@ continue_loading:
|
|||
moduleFileName->Buffer);
|
||||
#endif
|
||||
|
||||
// A few DLLs such as xul.dll and nss3.dll get loaded before mozglue's
|
||||
// AutoProfilerLabel is initialized, and this is a no-op in those cases. But
|
||||
// the vast majority of DLLs do get labelled here.
|
||||
AutoProfilerLabel label("WindowsDllBlocklist::patched_LdrLoadDll", dllName);
|
||||
|
||||
#ifdef _M_AMD64
|
||||
// Prevent the stack walker from suspending this thread when LdrLoadDll
|
||||
// holds the RtlLookupFunctionEntry lock.
|
||||
AutoSuppressStackWalking suppress;
|
||||
#endif
|
||||
glue::ModuleLoadFrame loadFrame(moduleFileName);
|
||||
|
||||
NTSTATUS ret;
|
||||
HANDLE myHandle;
|
||||
|
||||
if (IsUntrustedDllsHandlerEnabled()) {
|
||||
TimeStamp loadStart = TimeStamp::Now();
|
||||
ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
|
||||
TimeStamp loadEnd = TimeStamp::Now();
|
||||
|
||||
if (NT_SUCCESS(ret)) {
|
||||
double loadDurationMS = (loadEnd - loadStart).ToMilliseconds();
|
||||
// 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, loadDurationMS);
|
||||
glue::AutoSharedLock lock(gDllServicesLock);
|
||||
if (gDllServices) {
|
||||
Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy> events;
|
||||
if (glue::UntrustedDllsHandler::TakePendingEvents(events)) {
|
||||
gDllServices->NotifyUntrustedModuleLoads(events);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
|
||||
}
|
||||
ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
|
||||
|
||||
if (handle) {
|
||||
*handle = myHandle;
|
||||
}
|
||||
|
||||
loadFrame.SetLoadStatus(ret, myHandle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
// Map of specific thread proc addresses we should block. In particular,
|
||||
// LoadLibrary* APIs which indicate DLL injection
|
||||
static mozilla::Vector<void*, 4>* gStartAddressesToBlock;
|
||||
#endif
|
||||
static void* gStartAddressesToBlock[4];
|
||||
#endif // defined(NIGHTLY_BUILD)
|
||||
|
||||
static bool ShouldBlockThread(void* aStartAddress) {
|
||||
// Allows crashfirefox.exe to continue to work. Also if your threadproc is
|
||||
// null, this crash is intentional.
|
||||
if (aStartAddress == 0) return false;
|
||||
if (aStartAddress == nullptr) return false;
|
||||
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
for (auto p : *gStartAddressesToBlock) {
|
||||
for (auto p : gStartAddressesToBlock) {
|
||||
if (p == aStartAddress) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -608,56 +569,32 @@ static WindowsDllInterceptor Kernel32Intercept;
|
|||
|
||||
static void GetNativeNtBlockSetWriter();
|
||||
|
||||
static glue::LoaderObserver gMozglueLoaderObserver;
|
||||
|
||||
MFBT_API void DllBlocklist_Initialize(uint32_t aInitFlags) {
|
||||
if (sBlocklistInitAttempted) {
|
||||
return;
|
||||
}
|
||||
sBlocklistInitAttempted = true;
|
||||
|
||||
sInitFlags = aInitFlags;
|
||||
|
||||
if (sInitFlags & eDllBlocklistInitFlagWasBootstrapped) {
|
||||
GetNativeNtBlockSetWriter();
|
||||
glue::ModuleLoadFrame::StaticInit(&gMozglueLoaderObserver);
|
||||
|
||||
#ifdef _M_AMD64
|
||||
if (!IsWin8OrLater()) {
|
||||
Kernel32Intercept.Init("kernel32.dll");
|
||||
|
||||
// The crash that this hook works around is only seen on Win7.
|
||||
stub_RtlInstallFunctionTableCallback.Set(
|
||||
Kernel32Intercept, "RtlInstallFunctionTableCallback",
|
||||
&patched_RtlInstallFunctionTableCallback);
|
||||
}
|
||||
|
||||
sBlocklistInitAttempted = true;
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
gStartAddressesToBlock = new mozilla::Vector<void*, 4>;
|
||||
#endif
|
||||
|
||||
if (IsUntrustedDllsHandlerEnabled()) {
|
||||
#ifdef ENABLE_TESTS
|
||||
// Check whether we are running as an xpcshell test.
|
||||
if (mozilla::EnvHasValue("XPCSHELL_TEST_PROFILE_DIR")) {
|
||||
// For xpcshell tests, load this untrusted DLL early enough that the
|
||||
// untrusted module evaluator counts it as a startup module.
|
||||
// It is located in the current directory; the full path must be specified
|
||||
// or LoadLibrary() fails during xpcshell tests with ERROR_MOD_NOT_FOUND.
|
||||
|
||||
// This buffer will hold current directory + dll name
|
||||
wchar_t dllFullPath[MAX_PATH] = {};
|
||||
static const wchar_t kTestDllName[] = L"\\untrusted-startup-test-dll.dll";
|
||||
|
||||
// The amount of the buffer available to store the current directory,
|
||||
// leaving room for the dll name.
|
||||
static const DWORD kBufferDirLen =
|
||||
ArrayLength(dllFullPath) - ArrayLength(kTestDllName);
|
||||
|
||||
DWORD ret = ::GetCurrentDirectoryW(kBufferDirLen, dllFullPath);
|
||||
if ((ret > kBufferDirLen) || !ret) {
|
||||
// Buffer too small or the call failed
|
||||
printf_stderr("Unable to load %S; GetCurrentDirectoryW failed: %lu",
|
||||
kTestDllName, GetLastError());
|
||||
} else {
|
||||
wcscat_s(dllFullPath, kTestDllName);
|
||||
HMODULE hTestDll = ::LoadLibraryW(dllFullPath);
|
||||
if (!hTestDll) {
|
||||
printf_stderr("Unable to load %S; LoadLibraryW failed: %lu",
|
||||
kTestDllName, GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glue::UntrustedDllsHandler::Init();
|
||||
if (aInitFlags & eDllBlocklistInitFlagWasBootstrapped) {
|
||||
GetNativeNtBlockSetWriter();
|
||||
return;
|
||||
}
|
||||
|
||||
// There are a couple of exceptional cases where we skip user32.dll check.
|
||||
|
|
@ -712,15 +649,6 @@ MFBT_API void DllBlocklist_Initialize(uint32_t aInitFlags) {
|
|||
|
||||
Kernel32Intercept.Init("kernel32.dll");
|
||||
|
||||
#ifdef _M_AMD64
|
||||
if (!IsWin8OrLater()) {
|
||||
// The crash that this hook works around is only seen on Win7.
|
||||
stub_RtlInstallFunctionTableCallback.Set(
|
||||
Kernel32Intercept, "RtlInstallFunctionTableCallback",
|
||||
&patched_RtlInstallFunctionTableCallback);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Bug 1361410: WRusr.dll will overwrite our hook and cause a crash.
|
||||
// Workaround: If we detect WRusr.dll, don't hook.
|
||||
if (!GetModuleHandleW(L"WRusr.dll")) {
|
||||
|
|
@ -740,34 +668,22 @@ MFBT_API void DllBlocklist_Initialize(uint32_t aInitFlags) {
|
|||
void* pProc;
|
||||
|
||||
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryA");
|
||||
if (pProc) {
|
||||
Unused << gStartAddressesToBlock->append(pProc);
|
||||
}
|
||||
gStartAddressesToBlock[0] = pProc;
|
||||
|
||||
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryW");
|
||||
if (pProc) {
|
||||
Unused << gStartAddressesToBlock->append(pProc);
|
||||
}
|
||||
gStartAddressesToBlock[1] = pProc;
|
||||
|
||||
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryExA");
|
||||
if (pProc) {
|
||||
Unused << gStartAddressesToBlock->append(pProc);
|
||||
}
|
||||
gStartAddressesToBlock[2] = pProc;
|
||||
|
||||
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryExW");
|
||||
if (pProc) {
|
||||
Unused << gStartAddressesToBlock->append(pProc);
|
||||
}
|
||||
gStartAddressesToBlock[3] = pProc;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
MFBT_API void DllBlocklist_Shutdown() {
|
||||
if (IsUntrustedDllsHandlerEnabled()) {
|
||||
glue::UntrustedDllsHandler::Shutdown();
|
||||
}
|
||||
}
|
||||
MFBT_API void DllBlocklist_Shutdown() {}
|
||||
#endif // DEBUG
|
||||
|
||||
static void WriteAnnotation(HANDLE aFile, Annotation aAnnotation,
|
||||
|
|
@ -819,63 +735,6 @@ MFBT_API bool DllBlocklist_CheckStatus() {
|
|||
// This section is for DLL Services
|
||||
// ============================================================================
|
||||
|
||||
// These types are documented on MSDN but not provided in any SDK headers
|
||||
|
||||
enum DllNotificationReason {
|
||||
LDR_DLL_NOTIFICATION_REASON_LOADED = 1,
|
||||
LDR_DLL_NOTIFICATION_REASON_UNLOADED = 2
|
||||
};
|
||||
|
||||
typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA {
|
||||
ULONG Flags; // Reserved.
|
||||
PCUNICODE_STRING FullDllName; // The full path name of the DLL module.
|
||||
PCUNICODE_STRING BaseDllName; // The base file name of the DLL module.
|
||||
PVOID DllBase; // A pointer to the base address for the DLL in memory.
|
||||
ULONG SizeOfImage; // The size of the DLL image, in bytes.
|
||||
} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA;
|
||||
|
||||
typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA {
|
||||
ULONG Flags; // Reserved.
|
||||
PCUNICODE_STRING FullDllName; // The full path name of the DLL module.
|
||||
PCUNICODE_STRING BaseDllName; // The base file name of the DLL module.
|
||||
PVOID DllBase; // A pointer to the base address for the DLL in memory.
|
||||
ULONG SizeOfImage; // The size of the DLL image, in bytes.
|
||||
} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;
|
||||
|
||||
typedef union _LDR_DLL_NOTIFICATION_DATA {
|
||||
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
|
||||
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
|
||||
} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA;
|
||||
|
||||
typedef const LDR_DLL_NOTIFICATION_DATA* PCLDR_DLL_NOTIFICATION_DATA;
|
||||
|
||||
typedef VOID(CALLBACK* PLDR_DLL_NOTIFICATION_FUNCTION)(
|
||||
ULONG aReason, PCLDR_DLL_NOTIFICATION_DATA aNotificationData,
|
||||
PVOID aContext);
|
||||
|
||||
NTSTATUS NTAPI LdrRegisterDllNotification(
|
||||
ULONG aFlags, PLDR_DLL_NOTIFICATION_FUNCTION aCallback, PVOID aContext,
|
||||
PVOID* aCookie);
|
||||
|
||||
static PVOID gNotificationCookie;
|
||||
|
||||
static VOID CALLBACK DllLoadNotification(
|
||||
ULONG aReason, PCLDR_DLL_NOTIFICATION_DATA aNotificationData,
|
||||
PVOID aContext) {
|
||||
if (aReason != LDR_DLL_NOTIFICATION_REASON_LOADED) {
|
||||
// We don't care about unloads
|
||||
return;
|
||||
}
|
||||
|
||||
glue::AutoSharedLock lock(gDllServicesLock);
|
||||
if (!gDllServices) {
|
||||
return;
|
||||
}
|
||||
|
||||
PCUNICODE_STRING fullDllName = aNotificationData->Loaded.FullDllName;
|
||||
gDllServices->DispatchDllLoadNotification(fullDllName);
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
Authenticode* GetAuthenticode();
|
||||
} // namespace mozilla
|
||||
|
|
@ -885,29 +744,10 @@ MFBT_API void DllBlocklist_SetFullDllServices(
|
|||
glue::AutoExclusiveLock lock(gDllServicesLock);
|
||||
if (aSvc) {
|
||||
aSvc->SetAuthenticodeImpl(GetAuthenticode());
|
||||
|
||||
if (!gNotificationCookie) {
|
||||
auto pLdrRegisterDllNotification =
|
||||
reinterpret_cast<decltype(&::LdrRegisterDllNotification)>(
|
||||
::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"),
|
||||
"LdrRegisterDllNotification"));
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(pLdrRegisterDllNotification);
|
||||
|
||||
mozilla::DebugOnly<NTSTATUS> ntStatus = pLdrRegisterDllNotification(
|
||||
0, &DllLoadNotification, nullptr, &gNotificationCookie);
|
||||
MOZ_ASSERT(NT_SUCCESS(ntStatus));
|
||||
}
|
||||
gMozglueLoaderObserver.Forward(aSvc);
|
||||
}
|
||||
|
||||
gDllServices = aSvc;
|
||||
|
||||
if (IsUntrustedDllsHandlerEnabled() && gDllServices) {
|
||||
Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy> events;
|
||||
if (glue::UntrustedDllsHandler::TakePendingEvents(events)) {
|
||||
gDllServices->NotifyUntrustedModuleLoads(events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MFBT_API void DllBlocklist_SetBasicDllServices(
|
||||
|
|
@ -917,4 +757,5 @@ MFBT_API void DllBlocklist_SetBasicDllServices(
|
|||
}
|
||||
|
||||
aSvc->SetAuthenticodeImpl(GetAuthenticode());
|
||||
gMozglueLoaderObserver.Clear();
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Authenticode.h"
|
||||
#include "mozilla/LoaderAPIInterfaces.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
# include "nsISupportsImpl.h"
|
||||
# include "nsString.h"
|
||||
# include "nsThreadUtils.h"
|
||||
# include "prthread.h"
|
||||
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
|
|
@ -29,44 +31,6 @@
|
|||
|
||||
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;
|
||||
double mLoadDurationMS;
|
||||
};
|
||||
|
||||
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 {
|
||||
|
|
@ -77,24 +41,23 @@ class DllServicesBase : public Authenticode {
|
|||
* this function should be used for is dispatching the event to our
|
||||
* event loop so that it may be handled in a safe context.
|
||||
*/
|
||||
virtual void DispatchDllLoadNotification(PCUNICODE_STRING aDllName) = 0;
|
||||
virtual void DispatchDllLoadNotification(ModuleLoadInfo&& aModLoadInfo) = 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.
|
||||
* only perform trivial, loader-friendly operations.
|
||||
*/
|
||||
virtual void NotifyUntrustedModuleLoads(
|
||||
const Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy>&
|
||||
aEvents) = 0;
|
||||
virtual void DispatchModuleLoadBacklogNotification(
|
||||
ModuleLoadInfoVec&& aEvents) = 0;
|
||||
|
||||
void SetAuthenticodeImpl(Authenticode* aAuthenticode) {
|
||||
mAuthenticode = aAuthenticode;
|
||||
}
|
||||
|
||||
// In debug builds, we override GetBinaryOrgName to add a Gecko-specific
|
||||
// In debug builds we override GetBinaryOrgName to add a Gecko-specific
|
||||
// assertion. OTOH, we normally do not want people overriding this function,
|
||||
// so we'll make it final in the release case, thus covering all bases.
|
||||
#if defined(DEBUG)
|
||||
|
|
@ -133,15 +96,49 @@ class DllServicesBase : public Authenticode {
|
|||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
struct EnhancedModuleLoadInfo final {
|
||||
explicit EnhancedModuleLoadInfo(ModuleLoadInfo&& aModLoadInfo)
|
||||
: mNtLoadInfo(std::move(aModLoadInfo)) {
|
||||
// Only populate mThreadName when we're on the same thread as the event
|
||||
if (mNtLoadInfo.mThreadId == ::GetCurrentThreadId()) {
|
||||
mThreadName = PR_GetThreadName(PR_GetCurrentThread());
|
||||
}
|
||||
MOZ_ASSERT(!mNtLoadInfo.mSectionName.IsEmpty());
|
||||
}
|
||||
|
||||
EnhancedModuleLoadInfo(EnhancedModuleLoadInfo&&) = default;
|
||||
EnhancedModuleLoadInfo& operator=(EnhancedModuleLoadInfo&&) = default;
|
||||
|
||||
EnhancedModuleLoadInfo(const EnhancedModuleLoadInfo&) = delete;
|
||||
EnhancedModuleLoadInfo& operator=(const EnhancedModuleLoadInfo&) = delete;
|
||||
|
||||
nsDependentString GetSectionName() const {
|
||||
return mNtLoadInfo.mSectionName.AsString();
|
||||
}
|
||||
|
||||
using BacktraceType = decltype(ModuleLoadInfo::mBacktrace);
|
||||
|
||||
ModuleLoadInfo mNtLoadInfo;
|
||||
nsCString mThreadName;
|
||||
};
|
||||
|
||||
class DllServices : public detail::DllServicesBase {
|
||||
public:
|
||||
void DispatchDllLoadNotification(PCUNICODE_STRING aDllName) final {
|
||||
nsDependentSubstring strDllName(aDllName->Buffer,
|
||||
aDllName->Length / sizeof(wchar_t));
|
||||
void DispatchDllLoadNotification(ModuleLoadInfo&& aModLoadInfo) final {
|
||||
nsCOMPtr<nsIRunnable> runnable(
|
||||
NewRunnableMethod<StoreCopyPassByRRef<EnhancedModuleLoadInfo>>(
|
||||
"DllServices::NotifyDllLoad", this, &DllServices::NotifyDllLoad,
|
||||
std::move(aModLoadInfo)));
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable(NewRunnableMethod<bool, nsString>(
|
||||
"DllServices::NotifyDllLoad", this, &DllServices::NotifyDllLoad,
|
||||
NS_IsMainThread(), strDllName));
|
||||
SystemGroup::Dispatch(TaskCategory::Other, runnable.forget());
|
||||
}
|
||||
|
||||
void DispatchModuleLoadBacklogNotification(
|
||||
ModuleLoadInfoVec&& aEvents) final {
|
||||
nsCOMPtr<nsIRunnable> runnable(
|
||||
NewRunnableMethod<StoreCopyPassByRRef<ModuleLoadInfoVec>>(
|
||||
"DllServices::NotifyModuleLoadBacklog", this,
|
||||
&DllServices::NotifyModuleLoadBacklog, std::move(aEvents)));
|
||||
|
||||
SystemGroup::Dispatch(TaskCategory::Other, runnable.forget());
|
||||
}
|
||||
|
|
@ -161,8 +158,8 @@ class DllServices : public detail::DllServicesBase {
|
|||
DllServices() = default;
|
||||
~DllServices() = default;
|
||||
|
||||
virtual void NotifyDllLoad(const bool aIsMainThread,
|
||||
const nsString& aDllName) = 0;
|
||||
virtual void NotifyDllLoad(EnhancedModuleLoadInfo&& aModLoadInfo) = 0;
|
||||
virtual void NotifyModuleLoadBacklog(ModuleLoadInfoVec&& aEvents) = 0;
|
||||
};
|
||||
|
||||
#else
|
||||
|
|
@ -174,12 +171,11 @@ class BasicDllServices final : public detail::DllServicesBase {
|
|||
~BasicDllServices() = default;
|
||||
|
||||
// Not useful in this class, so provide a default implementation
|
||||
virtual void DispatchDllLoadNotification(PCUNICODE_STRING aDllName) override {
|
||||
}
|
||||
virtual void DispatchDllLoadNotification(
|
||||
ModuleLoadInfo&& aModLoadInfo) override {}
|
||||
|
||||
virtual void NotifyUntrustedModuleLoads(
|
||||
const Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy>& aEvents)
|
||||
override {}
|
||||
virtual void DispatchModuleLoadBacklogNotification(
|
||||
ModuleLoadInfoVec&& aEvents) override {}
|
||||
};
|
||||
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
74
mozglue/dllservices/WindowsFallbackLoaderAPI.cpp
Normal file
74
mozglue/dllservices/WindowsFallbackLoaderAPI.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WindowsFallbackLoaderAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
ModuleLoadInfo FallbackLoaderAPI::ConstructAndNotifyBeginDllLoad(
|
||||
void** aContext, PCUNICODE_STRING aRequestedDllName) {
|
||||
ModuleLoadInfo loadInfo(aRequestedDllName);
|
||||
|
||||
MOZ_ASSERT(mLoaderObserver);
|
||||
if (mLoaderObserver) {
|
||||
mLoaderObserver->OnBeginDllLoad(aContext, aRequestedDllName);
|
||||
}
|
||||
|
||||
return loadInfo;
|
||||
}
|
||||
|
||||
bool FallbackLoaderAPI::SubstituteForLSP(PCUNICODE_STRING aLSPLeafName,
|
||||
PHANDLE aOutHandle) {
|
||||
MOZ_ASSERT(mLoaderObserver);
|
||||
if (!mLoaderObserver) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mLoaderObserver->SubstituteForLSP(aLSPLeafName, aOutHandle);
|
||||
}
|
||||
|
||||
void FallbackLoaderAPI::NotifyEndDllLoad(void* aContext, NTSTATUS aLoadNtStatus,
|
||||
ModuleLoadInfo&& aModuleLoadInfo) {
|
||||
aModuleLoadInfo.SetEndLoadTimeStamp();
|
||||
|
||||
if (NT_SUCCESS(aLoadNtStatus)) {
|
||||
aModuleLoadInfo.CaptureBacktrace();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mLoaderObserver);
|
||||
if (mLoaderObserver) {
|
||||
mLoaderObserver->OnEndDllLoad(aContext, aLoadNtStatus,
|
||||
std::move(aModuleLoadInfo));
|
||||
}
|
||||
}
|
||||
|
||||
nt::AllocatedUnicodeString FallbackLoaderAPI::GetSectionName(
|
||||
void* aSectionAddr) {
|
||||
static const StaticDynamicallyLinkedFunctionPtr<decltype(
|
||||
&::NtQueryVirtualMemory)>
|
||||
pNtQueryVirtualMemory(L"ntdll.dll", "NtQueryVirtualMemory");
|
||||
MOZ_ASSERT(pNtQueryVirtualMemory);
|
||||
|
||||
if (!pNtQueryVirtualMemory) {
|
||||
return nt::AllocatedUnicodeString();
|
||||
}
|
||||
|
||||
nt::MemorySectionNameBuf buf;
|
||||
NTSTATUS ntStatus =
|
||||
pNtQueryVirtualMemory(::GetCurrentProcess(), aSectionAddr,
|
||||
MemorySectionName, &buf, sizeof(buf), nullptr);
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
return nt::AllocatedUnicodeString();
|
||||
}
|
||||
|
||||
return nt::AllocatedUnicodeString(&buf.mSectionFileName);
|
||||
}
|
||||
|
||||
void FallbackLoaderAPI::SetObserver(nt::LoaderObserver* aLoaderObserver) {
|
||||
mLoaderObserver = aLoaderObserver;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
36
mozglue/dllservices/WindowsFallbackLoaderAPI.h
Normal file
36
mozglue/dllservices/WindowsFallbackLoaderAPI.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_WindowsFallbackLoaderAPI_h
|
||||
#define mozilla_WindowsFallbackLoaderAPI_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "NtLoaderAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FallbackLoaderAPI final
|
||||
: public nt::LoaderAPI {
|
||||
public:
|
||||
constexpr FallbackLoaderAPI() : mLoaderObserver(nullptr) {}
|
||||
|
||||
ModuleLoadInfo ConstructAndNotifyBeginDllLoad(
|
||||
void** aContext, PCUNICODE_STRING aRequestedDllName) final;
|
||||
bool SubstituteForLSP(PCUNICODE_STRING aLSPLeafName,
|
||||
PHANDLE aOutHandle) final;
|
||||
void NotifyEndDllLoad(void* aContext, NTSTATUS aLoadNtStatus,
|
||||
ModuleLoadInfo&& aModuleLoadInfo) final;
|
||||
nt::AllocatedUnicodeString GetSectionName(void* aSectionAddr) final;
|
||||
|
||||
void SetObserver(nt::LoaderObserver* aLoaderObserver);
|
||||
|
||||
private:
|
||||
nt::LoaderObserver* mLoaderObserver;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_WindowsFallbackLoaderAPI_h
|
||||
58
mozglue/dllservices/moz.build
Normal file
58
mozglue/dllservices/moz.build
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||
|
||||
SOURCES += [
|
||||
# This file contains a |using namespace mozilla;| statement
|
||||
'WindowsDllBlocklist.cpp',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'Authenticode.cpp',
|
||||
'LoaderObserver.cpp',
|
||||
'ModuleLoadFrame.cpp',
|
||||
'WindowsFallbackLoaderAPI.cpp',
|
||||
]
|
||||
|
||||
OS_LIBS += [
|
||||
'crypt32',
|
||||
'ntdll',
|
||||
'version',
|
||||
'wintrust',
|
||||
]
|
||||
|
||||
DELAYLOAD_DLLS += [
|
||||
'crypt32.dll',
|
||||
'wintrust.dll',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'Authenticode.h',
|
||||
'LoaderAPIInterfaces.h',
|
||||
'ModuleLoadInfo.h',
|
||||
'WindowsDllBlocklist.h',
|
||||
'WindowsDllBlocklistCommon.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.glue += [
|
||||
'WindowsDllServices.h',
|
||||
]
|
||||
|
||||
# Generate DLL Blocklists
|
||||
blocklist_header_types = ['A11y', 'Launcher', 'Legacy', 'Test']
|
||||
blocklist_file_leaf_tpl = 'WindowsDllBlocklist{0}Defs.h'
|
||||
blocklist_files = tuple([blocklist_file_leaf_tpl.format(type)
|
||||
for type in blocklist_header_types])
|
||||
GENERATED_FILES += [
|
||||
blocklist_files
|
||||
]
|
||||
blocklist_defs = GENERATED_FILES[blocklist_files]
|
||||
blocklist_defs.script = 'gen_dll_blocklist_defs.py:gen_blocklists'
|
||||
blocklist_defs.inputs = ['WindowsDllBlocklistDefs.in']
|
||||
EXPORTS.mozilla += ['!' + hdr for hdr in blocklist_files]
|
||||
|
||||
FINAL_LIBRARY = 'mozglue'
|
||||
59
mozglue/misc/WindowsUnicode.cpp
Normal file
59
mozglue/misc/WindowsUnicode.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WindowsUnicode.h"
|
||||
|
||||
#include <windows.h>
|
||||
// For UNICODE_STRING
|
||||
#include <winternl.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
mozilla::UniquePtr<char[]> WideToUTF8(const wchar_t* aStr,
|
||||
const size_t aStrLenExclNul) {
|
||||
int numConv = ::WideCharToMultiByte(CP_UTF8, 0, aStr, aStrLenExclNul, nullptr,
|
||||
0, nullptr, nullptr);
|
||||
if (!numConv) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Include room for the null terminator by adding one
|
||||
auto buf = mozilla::MakeUnique<char[]>(numConv + 1);
|
||||
|
||||
numConv = ::WideCharToMultiByte(CP_UTF8, 0, aStr, aStrLenExclNul, buf.get(),
|
||||
numConv, nullptr, nullptr);
|
||||
if (!numConv) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add null termination. numConv does not include the terminator, so we don't
|
||||
// subtract 1 when indexing into buf.
|
||||
buf[numConv] = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
mozilla::UniquePtr<char[]> WideToUTF8(const wchar_t* aStr) {
|
||||
return WideToUTF8(aStr, wcslen(aStr));
|
||||
}
|
||||
|
||||
mozilla::UniquePtr<char[]> WideToUTF8(const std::wstring& aStr) {
|
||||
return WideToUTF8(aStr.data(), aStr.length());
|
||||
}
|
||||
|
||||
mozilla::UniquePtr<char[]> WideToUTF8(PCUNICODE_STRING aStr) {
|
||||
if (!aStr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WideToUTF8(aStr->Buffer, aStr->Length / sizeof(WCHAR));
|
||||
}
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
||||
35
mozglue/misc/WindowsUnicode.h
Normal file
35
mozglue/misc/WindowsUnicode.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_glue_WindowsUnicode_h
|
||||
#define mozilla_glue_WindowsUnicode_h
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
struct _UNICODE_STRING;
|
||||
|
||||
namespace mozilla {
|
||||
namespace glue {
|
||||
|
||||
mozilla::UniquePtr<char[]> WideToUTF8(const wchar_t* aStr,
|
||||
const size_t aStrLenExclNul);
|
||||
|
||||
mozilla::UniquePtr<char[]> WideToUTF8(const wchar_t* aStr);
|
||||
mozilla::UniquePtr<char[]> WideToUTF8(const std::wstring& aStr);
|
||||
mozilla::UniquePtr<char[]> WideToUTF8(const _UNICODE_STRING* aStr);
|
||||
|
||||
#if defined(bstr_t)
|
||||
inline mozilla::UniquePtr<char[]> WideToUTF8(const _bstr_t& aStr) {
|
||||
return WideToUTF8(static_cast<const wchar_t*>(aStr), aStr.length());
|
||||
}
|
||||
#endif // defined(bstr_t)
|
||||
|
||||
} // namespace glue
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_glue_WindowsUnicode_h
|
||||
|
|
@ -18,6 +18,7 @@ EXPORTS.mozilla += [
|
|||
|
||||
EXPORTS.mozilla.glue += [
|
||||
'Debug.h',
|
||||
'WinUtils.h',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
|
|
@ -49,10 +50,14 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
'WindowsMapRemoteView.h',
|
||||
'WindowsProcessMitigations.h',
|
||||
]
|
||||
EXPORTS.mozilla.glue += [
|
||||
'WindowsUnicode.h',
|
||||
]
|
||||
SOURCES += [
|
||||
'TimeStamp_windows.cpp',
|
||||
'WindowsMapRemoteView.cpp',
|
||||
'WindowsProcessMitigations.cpp',
|
||||
'WindowsUnicode.cpp',
|
||||
]
|
||||
OS_LIBS += ['dbghelp']
|
||||
elif CONFIG['HAVE_CLOCK_MONOTONIC']:
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ if CONFIG['MOZ_LINKER']:
|
|||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
DIRS += ['android']
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
DIRS += ['dllservices']
|
||||
|
||||
DIRS += [
|
||||
'baseprofiler',
|
||||
'build',
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
# include "nsDirectoryServiceUtils.h"
|
||||
|
||||
# include "nsWindowsDllInterceptor.h"
|
||||
# include "mozilla/WindowsDllBlocklist.h"
|
||||
# include "mozilla/WindowsVersion.h"
|
||||
# include "psapi.h" // For PERFORMANCE_INFORAMTION
|
||||
#elif defined(XP_MACOSX)
|
||||
|
|
@ -96,7 +97,6 @@ using mozilla::InjectCrashRunnable;
|
|||
|
||||
#include "mozilla/IOInterposer.h"
|
||||
#include "mozilla/mozalloc_oom.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
#include "mozilla/recordreplay/ParentIPC.h"
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@
|
|||
#include "mozilla/ipc/XPCShellEnvironment.h"
|
||||
#if defined(XP_WIN)
|
||||
# include "mozilla/WindowsConsole.h"
|
||||
# include "mozilla/WindowsDllBlocklist.h"
|
||||
#endif
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
#include "GMPProcessChild.h"
|
||||
#include "mozilla/gfx/GPUProcessImpl.h"
|
||||
|
|
|
|||
Loading…
Reference in a new issue