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
|
#ifdef XP_WIN
|
||||||
# include "LauncherProcessWin.h"
|
# include "LauncherProcessWin.h"
|
||||||
|
# include "mozilla/WindowsDllBlocklist.h"
|
||||||
|
|
||||||
# define XRE_WANT_ENVIRON
|
# define XRE_WANT_ENVIRON
|
||||||
# define strcasecmp _stricmp
|
# define strcasecmp _stricmp
|
||||||
|
|
@ -38,7 +39,6 @@
|
||||||
|
|
||||||
#include "mozilla/Sprintf.h"
|
#include "mozilla/Sprintf.h"
|
||||||
#include "mozilla/StartupTimeline.h"
|
#include "mozilla/StartupTimeline.h"
|
||||||
#include "mozilla/WindowsDllBlocklist.h"
|
|
||||||
#include "BaseProfiler.h"
|
#include "BaseProfiler.h"
|
||||||
|
|
||||||
#ifdef LIBFUZZER
|
#ifdef LIBFUZZER
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#ifndef mozilla_freestanding_LoaderPrivateAPI_h
|
#ifndef mozilla_freestanding_LoaderPrivateAPI_h
|
||||||
#define mozilla_freestanding_LoaderPrivateAPI_h
|
#define mozilla_freestanding_LoaderPrivateAPI_h
|
||||||
|
|
||||||
#include "LoaderAPIInterfaces.h"
|
#include "mozilla/LoaderAPIInterfaces.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace freestanding {
|
namespace freestanding {
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,6 @@ FORCE_STATIC_LIB = True
|
||||||
# that might call an import.
|
# that might call an import.
|
||||||
NO_PGO = True
|
NO_PGO = True
|
||||||
|
|
||||||
EXPORTS.mozilla += [
|
|
||||||
'LoaderAPIInterfaces.h',
|
|
||||||
'ModuleLoadInfo.h',
|
|
||||||
]
|
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'DllBlocklist.cpp',
|
'DllBlocklist.cpp',
|
||||||
'LoaderPrivateAPI.cpp',
|
'LoaderPrivateAPI.cpp',
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,6 @@ Library('winlauncher')
|
||||||
|
|
||||||
FORCE_STATIC_LIB = True
|
FORCE_STATIC_LIB = True
|
||||||
|
|
||||||
EXPORTS.mozilla += [
|
|
||||||
'NtLoaderAPI.h',
|
|
||||||
]
|
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'/ipc/mscom/ProcessRuntime.cpp',
|
'/ipc/mscom/ProcessRuntime.cpp',
|
||||||
'/widget/windows/WindowsConsole.cpp',
|
'/widget/windows/WindowsConsole.cpp',
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@
|
||||||
#include "../contentproc/plugin-container.cpp"
|
#include "../contentproc/plugin-container.cpp"
|
||||||
|
|
||||||
#include "mozilla/Bootstrap.h"
|
#include "mozilla/Bootstrap.h"
|
||||||
|
#if defined(XP_WIN)
|
||||||
# include "mozilla/WindowsDllBlocklist.h"
|
# include "mozilla/WindowsDllBlocklist.h"
|
||||||
|
#endif // defined(XP_WIN)
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "mozilla/mscom/ProcessRuntimeShared.h"
|
#include "mozilla/mscom/ProcessRuntimeShared.h"
|
||||||
#include "MozglueUtils.h"
|
|
||||||
|
#include "mozilla/glue/WinUtils.h"
|
||||||
|
|
||||||
// We allow multiple ProcessRuntime instances to exist simultaneously (even
|
// We allow multiple ProcessRuntime instances to exist simultaneously (even
|
||||||
// on separate threads), but only one should be doing the process-wide
|
// on separate threads), but only one should be doing the process-wide
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,6 @@ EXPORTS.mozilla.mscom += [
|
||||||
'ProcessRuntimeShared.h',
|
'ProcessRuntimeShared.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
|
||||||
'/mozglue/build',
|
|
||||||
]
|
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'ProcessRuntimeShared.cpp',
|
'ProcessRuntimeShared.cpp',
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "mozilla/WindowsDllBlocklist.h"
|
|
||||||
#include "mozilla/Bootstrap.h"
|
#include "mozilla/Bootstrap.h"
|
||||||
|
|
||||||
#include "nsXULAppAPI.h"
|
#include "nsXULAppAPI.h"
|
||||||
|
|
@ -16,6 +15,8 @@
|
||||||
# include "xpcshellMacUtils.h"
|
# include "xpcshellMacUtils.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
|
# include "mozilla/WindowsDllBlocklist.h"
|
||||||
|
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include <shlobj.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',
|
'/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 += [
|
EXPORTS.mozilla += [
|
||||||
'arm.h',
|
'arm.h',
|
||||||
'mips.h',
|
'mips.h',
|
||||||
'ppc.h',
|
'ppc.h',
|
||||||
'SSE.h',
|
'SSE.h',
|
||||||
'WindowsDllBlocklist.h',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG['CPU_ARCH'].startswith('x86'):
|
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
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#ifndef mozilla_LoaderAPIInternal_h
|
#ifndef mozilla_LoaderAPIInterfaces_h
|
||||||
#define mozilla_LoaderAPIInternal_h
|
#define mozilla_LoaderAPIInterfaces_h
|
||||||
|
|
||||||
#include "mozilla/ModuleLoadInfo.h"
|
#include "mozilla/ModuleLoadInfo.h"
|
||||||
|
|
||||||
|
|
@ -97,4 +97,4 @@ class NS_NO_VTABLE LoaderAPI {
|
||||||
} // namespace nt
|
} // namespace nt
|
||||||
} // namespace mozilla
|
} // 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 "Authenticode.h"
|
||||||
#include "BaseProfiler.h"
|
#include "BaseProfiler.h"
|
||||||
#include "CrashAnnotations.h"
|
#include "CrashAnnotations.h"
|
||||||
#include "MozglueUtils.h"
|
|
||||||
#include "UntrustedDllsHandler.h"
|
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "nsWindowsDllInterceptor.h"
|
#include "nsWindowsDllInterceptor.h"
|
||||||
#include "mozilla/CmdLineAndEnvUtils.h"
|
#include "mozilla/CmdLineAndEnvUtils.h"
|
||||||
|
|
@ -32,15 +30,25 @@
|
||||||
#include "mozilla/AutoProfilerLabel.h"
|
#include "mozilla/AutoProfilerLabel.h"
|
||||||
#include "mozilla/glue/Debug.h"
|
#include "mozilla/glue/Debug.h"
|
||||||
#include "mozilla/glue/WindowsDllServices.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 namespace mozilla;
|
||||||
|
|
||||||
using CrashReporter::Annotation;
|
using CrashReporter::Annotation;
|
||||||
using CrashReporter::AnnotationToString;
|
using CrashReporter::AnnotationToString;
|
||||||
|
|
||||||
static glue::Win32SRWLock gDllServicesLock;
|
|
||||||
static glue::detail::DllServicesBase* gDllServices;
|
|
||||||
|
|
||||||
#define DLL_BLOCKLIST_ENTRY(name, ...) {name, __VA_ARGS__},
|
#define DLL_BLOCKLIST_ENTRY(name, ...) {name, __VA_ARGS__},
|
||||||
#define DLL_BLOCKLIST_STRING_TYPE const char*
|
#define DLL_BLOCKLIST_STRING_TYPE const char*
|
||||||
#include "mozilla/WindowsDllBlocklistLegacyDefs.h"
|
#include "mozilla/WindowsDllBlocklistLegacyDefs.h"
|
||||||
|
|
@ -53,15 +61,6 @@ static bool sBlocklistInitAttempted;
|
||||||
static bool sBlocklistInitFailed;
|
static bool sBlocklistInitFailed;
|
||||||
static bool sUser32BeforeBlocklist;
|
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)(
|
typedef MOZ_NORETURN_PTR void(__fastcall* BaseThreadInitThunk_func)(
|
||||||
BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam);
|
BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam);
|
||||||
static WindowsDllInterceptor::FuncHookType<BaseThreadInitThunk_func>
|
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,
|
static NTSTATUS NTAPI patched_LdrLoadDll(PWCHAR filePath, PULONG flags,
|
||||||
PUNICODE_STRING moduleFileName,
|
PUNICODE_STRING moduleFileName,
|
||||||
PHANDLE handle) {
|
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
|
// We have UCS2 (UTF16?), we want ASCII, but we also just want the filename
|
||||||
// portion
|
// portion
|
||||||
#define DLLNAME_MAX 128
|
#define DLLNAME_MAX 128
|
||||||
|
|
@ -516,63 +505,35 @@ continue_loading:
|
||||||
moduleFileName->Buffer);
|
moduleFileName->Buffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// A few DLLs such as xul.dll and nss3.dll get loaded before mozglue's
|
glue::ModuleLoadFrame loadFrame(moduleFileName);
|
||||||
// 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
|
|
||||||
|
|
||||||
NTSTATUS ret;
|
NTSTATUS ret;
|
||||||
HANDLE myHandle;
|
HANDLE myHandle;
|
||||||
|
|
||||||
if (IsUntrustedDllsHandlerEnabled()) {
|
|
||||||
TimeStamp loadStart = TimeStamp::Now();
|
|
||||||
ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handle) {
|
if (handle) {
|
||||||
*handle = myHandle;
|
*handle = myHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadFrame.SetLoadStatus(ret, myHandle);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(NIGHTLY_BUILD)
|
#if defined(NIGHTLY_BUILD)
|
||||||
// Map of specific thread proc addresses we should block. In particular,
|
// Map of specific thread proc addresses we should block. In particular,
|
||||||
// LoadLibrary* APIs which indicate DLL injection
|
// LoadLibrary* APIs which indicate DLL injection
|
||||||
static mozilla::Vector<void*, 4>* gStartAddressesToBlock;
|
static void* gStartAddressesToBlock[4];
|
||||||
#endif
|
#endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
static bool ShouldBlockThread(void* aStartAddress) {
|
static bool ShouldBlockThread(void* aStartAddress) {
|
||||||
// Allows crashfirefox.exe to continue to work. Also if your threadproc is
|
// Allows crashfirefox.exe to continue to work. Also if your threadproc is
|
||||||
// null, this crash is intentional.
|
// null, this crash is intentional.
|
||||||
if (aStartAddress == 0) return false;
|
if (aStartAddress == nullptr) return false;
|
||||||
|
|
||||||
#if defined(NIGHTLY_BUILD)
|
#if defined(NIGHTLY_BUILD)
|
||||||
for (auto p : *gStartAddressesToBlock) {
|
for (auto p : gStartAddressesToBlock) {
|
||||||
if (p == aStartAddress) {
|
if (p == aStartAddress) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -608,56 +569,32 @@ static WindowsDllInterceptor Kernel32Intercept;
|
||||||
|
|
||||||
static void GetNativeNtBlockSetWriter();
|
static void GetNativeNtBlockSetWriter();
|
||||||
|
|
||||||
|
static glue::LoaderObserver gMozglueLoaderObserver;
|
||||||
|
|
||||||
MFBT_API void DllBlocklist_Initialize(uint32_t aInitFlags) {
|
MFBT_API void DllBlocklist_Initialize(uint32_t aInitFlags) {
|
||||||
if (sBlocklistInitAttempted) {
|
if (sBlocklistInitAttempted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
sBlocklistInitAttempted = true;
|
||||||
|
|
||||||
sInitFlags = aInitFlags;
|
sInitFlags = aInitFlags;
|
||||||
|
|
||||||
if (sInitFlags & eDllBlocklistInitFlagWasBootstrapped) {
|
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);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (aInitFlags & eDllBlocklistInitFlagWasBootstrapped) {
|
||||||
GetNativeNtBlockSetWriter();
|
GetNativeNtBlockSetWriter();
|
||||||
}
|
return;
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are a couple of exceptional cases where we skip user32.dll check.
|
// 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");
|
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.
|
// Bug 1361410: WRusr.dll will overwrite our hook and cause a crash.
|
||||||
// Workaround: If we detect WRusr.dll, don't hook.
|
// Workaround: If we detect WRusr.dll, don't hook.
|
||||||
if (!GetModuleHandleW(L"WRusr.dll")) {
|
if (!GetModuleHandleW(L"WRusr.dll")) {
|
||||||
|
|
@ -740,34 +668,22 @@ MFBT_API void DllBlocklist_Initialize(uint32_t aInitFlags) {
|
||||||
void* pProc;
|
void* pProc;
|
||||||
|
|
||||||
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryA");
|
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryA");
|
||||||
if (pProc) {
|
gStartAddressesToBlock[0] = pProc;
|
||||||
Unused << gStartAddressesToBlock->append(pProc);
|
|
||||||
}
|
|
||||||
|
|
||||||
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryW");
|
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryW");
|
||||||
if (pProc) {
|
gStartAddressesToBlock[1] = pProc;
|
||||||
Unused << gStartAddressesToBlock->append(pProc);
|
|
||||||
}
|
|
||||||
|
|
||||||
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryExA");
|
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryExA");
|
||||||
if (pProc) {
|
gStartAddressesToBlock[2] = pProc;
|
||||||
Unused << gStartAddressesToBlock->append(pProc);
|
|
||||||
}
|
|
||||||
|
|
||||||
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryExW");
|
pProc = (void*)GetProcAddress(hKernel, "LoadLibraryExW");
|
||||||
if (pProc) {
|
gStartAddressesToBlock[3] = pProc;
|
||||||
Unused << gStartAddressesToBlock->append(pProc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
MFBT_API void DllBlocklist_Shutdown() {
|
MFBT_API void DllBlocklist_Shutdown() {}
|
||||||
if (IsUntrustedDllsHandlerEnabled()) {
|
|
||||||
glue::UntrustedDllsHandler::Shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
|
|
||||||
static void WriteAnnotation(HANDLE aFile, Annotation aAnnotation,
|
static void WriteAnnotation(HANDLE aFile, Annotation aAnnotation,
|
||||||
|
|
@ -819,63 +735,6 @@ MFBT_API bool DllBlocklist_CheckStatus() {
|
||||||
// This section is for DLL Services
|
// 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 {
|
namespace mozilla {
|
||||||
Authenticode* GetAuthenticode();
|
Authenticode* GetAuthenticode();
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
@ -885,29 +744,10 @@ MFBT_API void DllBlocklist_SetFullDllServices(
|
||||||
glue::AutoExclusiveLock lock(gDllServicesLock);
|
glue::AutoExclusiveLock lock(gDllServicesLock);
|
||||||
if (aSvc) {
|
if (aSvc) {
|
||||||
aSvc->SetAuthenticodeImpl(GetAuthenticode());
|
aSvc->SetAuthenticodeImpl(GetAuthenticode());
|
||||||
|
gMozglueLoaderObserver.Forward(aSvc);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gDllServices = 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(
|
MFBT_API void DllBlocklist_SetBasicDllServices(
|
||||||
|
|
@ -917,4 +757,5 @@ MFBT_API void DllBlocklist_SetBasicDllServices(
|
||||||
}
|
}
|
||||||
|
|
||||||
aSvc->SetAuthenticodeImpl(GetAuthenticode());
|
aSvc->SetAuthenticodeImpl(GetAuthenticode());
|
||||||
|
gMozglueLoaderObserver.Clear();
|
||||||
}
|
}
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/Authenticode.h"
|
#include "mozilla/Authenticode.h"
|
||||||
|
#include "mozilla/LoaderAPIInterfaces.h"
|
||||||
#include "mozilla/mozalloc.h"
|
#include "mozilla/mozalloc.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/Vector.h"
|
#include "mozilla/Vector.h"
|
||||||
|
|
@ -21,6 +22,7 @@
|
||||||
# include "nsISupportsImpl.h"
|
# include "nsISupportsImpl.h"
|
||||||
# include "nsString.h"
|
# include "nsString.h"
|
||||||
# include "nsThreadUtils.h"
|
# include "nsThreadUtils.h"
|
||||||
|
# include "prthread.h"
|
||||||
|
|
||||||
#endif // defined(MOZILLA_INTERNAL_API)
|
#endif // defined(MOZILLA_INTERNAL_API)
|
||||||
|
|
||||||
|
|
@ -29,44 +31,6 @@
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace glue {
|
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 {
|
namespace detail {
|
||||||
|
|
||||||
class DllServicesBase : public Authenticode {
|
class DllServicesBase : public Authenticode {
|
||||||
|
|
@ -77,24 +41,23 @@ class DllServicesBase : public Authenticode {
|
||||||
* this function should be used for is dispatching the event to our
|
* this function should be used for is dispatching the event to our
|
||||||
* event loop so that it may be handled in a safe context.
|
* 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
|
* This function accepts module load events to be processed later for
|
||||||
* the untrusted modules telemetry ping.
|
* the untrusted modules telemetry ping.
|
||||||
*
|
*
|
||||||
* WARNING: This method is run from within the Windows loader and should
|
* 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(
|
virtual void DispatchModuleLoadBacklogNotification(
|
||||||
const Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy>&
|
ModuleLoadInfoVec&& aEvents) = 0;
|
||||||
aEvents) = 0;
|
|
||||||
|
|
||||||
void SetAuthenticodeImpl(Authenticode* aAuthenticode) {
|
void SetAuthenticodeImpl(Authenticode* aAuthenticode) {
|
||||||
mAuthenticode = 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,
|
// 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.
|
// so we'll make it final in the release case, thus covering all bases.
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
|
|
@ -133,15 +96,49 @@ class DllServicesBase : public Authenticode {
|
||||||
|
|
||||||
#if defined(MOZILLA_INTERNAL_API)
|
#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 {
|
class DllServices : public detail::DllServicesBase {
|
||||||
public:
|
public:
|
||||||
void DispatchDllLoadNotification(PCUNICODE_STRING aDllName) final {
|
void DispatchDllLoadNotification(ModuleLoadInfo&& aModLoadInfo) final {
|
||||||
nsDependentSubstring strDllName(aDllName->Buffer,
|
nsCOMPtr<nsIRunnable> runnable(
|
||||||
aDllName->Length / sizeof(wchar_t));
|
NewRunnableMethod<StoreCopyPassByRRef<EnhancedModuleLoadInfo>>(
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> runnable(NewRunnableMethod<bool, nsString>(
|
|
||||||
"DllServices::NotifyDllLoad", this, &DllServices::NotifyDllLoad,
|
"DllServices::NotifyDllLoad", this, &DllServices::NotifyDllLoad,
|
||||||
NS_IsMainThread(), strDllName));
|
std::move(aModLoadInfo)));
|
||||||
|
|
||||||
|
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());
|
SystemGroup::Dispatch(TaskCategory::Other, runnable.forget());
|
||||||
}
|
}
|
||||||
|
|
@ -161,8 +158,8 @@ class DllServices : public detail::DllServicesBase {
|
||||||
DllServices() = default;
|
DllServices() = default;
|
||||||
~DllServices() = default;
|
~DllServices() = default;
|
||||||
|
|
||||||
virtual void NotifyDllLoad(const bool aIsMainThread,
|
virtual void NotifyDllLoad(EnhancedModuleLoadInfo&& aModLoadInfo) = 0;
|
||||||
const nsString& aDllName) = 0;
|
virtual void NotifyModuleLoadBacklog(ModuleLoadInfoVec&& aEvents) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
@ -174,12 +171,11 @@ class BasicDllServices final : public detail::DllServicesBase {
|
||||||
~BasicDllServices() = default;
|
~BasicDllServices() = default;
|
||||||
|
|
||||||
// Not useful in this class, so provide a default implementation
|
// 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(
|
virtual void DispatchModuleLoadBacklogNotification(
|
||||||
const Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy>& aEvents)
|
ModuleLoadInfoVec&& aEvents) override {}
|
||||||
override {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // defined(MOZILLA_INTERNAL_API)
|
#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 += [
|
EXPORTS.mozilla.glue += [
|
||||||
'Debug.h',
|
'Debug.h',
|
||||||
|
'WinUtils.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||||
|
|
@ -49,10 +50,14 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||||
'WindowsMapRemoteView.h',
|
'WindowsMapRemoteView.h',
|
||||||
'WindowsProcessMitigations.h',
|
'WindowsProcessMitigations.h',
|
||||||
]
|
]
|
||||||
|
EXPORTS.mozilla.glue += [
|
||||||
|
'WindowsUnicode.h',
|
||||||
|
]
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
'TimeStamp_windows.cpp',
|
'TimeStamp_windows.cpp',
|
||||||
'WindowsMapRemoteView.cpp',
|
'WindowsMapRemoteView.cpp',
|
||||||
'WindowsProcessMitigations.cpp',
|
'WindowsProcessMitigations.cpp',
|
||||||
|
'WindowsUnicode.cpp',
|
||||||
]
|
]
|
||||||
OS_LIBS += ['dbghelp']
|
OS_LIBS += ['dbghelp']
|
||||||
elif CONFIG['HAVE_CLOCK_MONOTONIC']:
|
elif CONFIG['HAVE_CLOCK_MONOTONIC']:
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ if CONFIG['MOZ_LINKER']:
|
||||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||||
DIRS += ['android']
|
DIRS += ['android']
|
||||||
|
|
||||||
|
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||||
|
DIRS += ['dllservices']
|
||||||
|
|
||||||
DIRS += [
|
DIRS += [
|
||||||
'baseprofiler',
|
'baseprofiler',
|
||||||
'build',
|
'build',
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@
|
||||||
# include "nsDirectoryServiceUtils.h"
|
# include "nsDirectoryServiceUtils.h"
|
||||||
|
|
||||||
# include "nsWindowsDllInterceptor.h"
|
# include "nsWindowsDllInterceptor.h"
|
||||||
|
# include "mozilla/WindowsDllBlocklist.h"
|
||||||
# include "mozilla/WindowsVersion.h"
|
# include "mozilla/WindowsVersion.h"
|
||||||
# include "psapi.h" // For PERFORMANCE_INFORAMTION
|
# include "psapi.h" // For PERFORMANCE_INFORAMTION
|
||||||
#elif defined(XP_MACOSX)
|
#elif defined(XP_MACOSX)
|
||||||
|
|
@ -96,7 +97,6 @@ using mozilla::InjectCrashRunnable;
|
||||||
|
|
||||||
#include "mozilla/IOInterposer.h"
|
#include "mozilla/IOInterposer.h"
|
||||||
#include "mozilla/mozalloc_oom.h"
|
#include "mozilla/mozalloc_oom.h"
|
||||||
#include "mozilla/WindowsDllBlocklist.h"
|
|
||||||
#include "mozilla/recordreplay/ParentIPC.h"
|
#include "mozilla/recordreplay/ParentIPC.h"
|
||||||
|
|
||||||
#if defined(XP_MACOSX)
|
#if defined(XP_MACOSX)
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@
|
||||||
#include "mozilla/ipc/XPCShellEnvironment.h"
|
#include "mozilla/ipc/XPCShellEnvironment.h"
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
# include "mozilla/WindowsConsole.h"
|
# include "mozilla/WindowsConsole.h"
|
||||||
#endif
|
|
||||||
# include "mozilla/WindowsDllBlocklist.h"
|
# include "mozilla/WindowsDllBlocklist.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "GMPProcessChild.h"
|
#include "GMPProcessChild.h"
|
||||||
#include "mozilla/gfx/GPUProcessImpl.h"
|
#include "mozilla/gfx/GPUProcessImpl.h"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue