зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1707954
) for causing bc failures in ClearOnShutdown.cpp.
CLOSED TREE Backed out changeset 7cb0db27236c (bug1707954
) Backed out changeset fd52d202d10b (bug1707954
) Backed out changeset 55586d8f7bf4 (bug1707954
) Backed out changeset 49406bdac5ec (bug1707954
)
This commit is contained in:
Родитель
ddb9da34fc
Коммит
5c483b46df
|
@ -128,8 +128,7 @@ namespace mozilla {
|
|||
LauncherVoidResult LaunchUnelevated(int aArgc, wchar_t* aArgv[]) {
|
||||
// We need COM to talk to Explorer. Using ProcessRuntime so that
|
||||
// process-global COM configuration is done correctly
|
||||
mozilla::mscom::ProcessRuntime mscom(
|
||||
mozilla::mscom::ProcessRuntime::ProcessCategory::Launcher);
|
||||
mozilla::mscom::ProcessRuntime mscom(GeckoProcessType_Default);
|
||||
if (!mscom) {
|
||||
return LAUNCHER_ERROR_FROM_HRESULT(mscom.GetHResult());
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ CubebDeviceEnumerator::CubebDeviceEnumerator()
|
|||
// Ensure the MTA thread exists and gets instantiated before the
|
||||
// CubebDeviceEnumerator so that this instance will always gets destructed
|
||||
// before the MTA thread gets shutdown.
|
||||
mozilla::mscom::EnsureMTA();
|
||||
mozilla::mscom::EnsureMTA([&]() -> void {
|
||||
#endif
|
||||
int rv = cubeb_register_device_collection_changed(
|
||||
|
|
|
@ -6,25 +6,14 @@
|
|||
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
#include "mozilla/SchedulerGroup.h"
|
||||
#include "mozilla/StaticLocalPtr.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "private/pprthred.h"
|
||||
|
||||
#include <combaseapi.h>
|
||||
|
||||
#if (NTDDI_VERSION < NTDDI_WIN8)
|
||||
// Win8+ API that we use very carefully
|
||||
DECLARE_HANDLE(CO_MTA_USAGE_COOKIE);
|
||||
HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE* pCookie);
|
||||
#endif // (NTDDI_VERSION < NTDDI_WIN8)
|
||||
|
||||
namespace {
|
||||
|
||||
class EnterMTARunnable : public mozilla::Runnable {
|
||||
|
@ -42,8 +31,8 @@ class BackgroundMTAData {
|
|||
public:
|
||||
BackgroundMTAData() {
|
||||
nsCOMPtr<nsIRunnable> runnable = new EnterMTARunnable();
|
||||
mozilla::DebugOnly<nsresult> rv = NS_NewNamedThread(
|
||||
"COM MTA", getter_AddRefs(mThread), runnable.forget());
|
||||
mozilla::DebugOnly<nsresult> rv =
|
||||
NS_NewNamedThread("COM MTA", getter_AddRefs(mThread), runnable);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_NewNamedThread failed");
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
@ -69,54 +58,6 @@ class BackgroundMTAData {
|
|||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
EnsureMTA::EnsureMTA() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// It is possible that we're running so early that we might need to start
|
||||
// the thread manager ourselves. We do this here to guarantee that we have
|
||||
// the ability to start the persistent MTA thread at any moment beyond this
|
||||
// point.
|
||||
nsresult rv = nsThreadManager::get().Init();
|
||||
// We intentionally don't check rv unless we need it when
|
||||
// CoIncremementMTAUsage is unavailable.
|
||||
|
||||
// This API is only available beginning with Windows 8. Even though this
|
||||
// constructor will only be called once, we intentionally use
|
||||
// StaticDynamicallyLinkedFunctionPtr here to hang onto the ole32 module.
|
||||
static const StaticDynamicallyLinkedFunctionPtr<
|
||||
decltype(&::CoIncrementMTAUsage)>
|
||||
pCoIncrementMTAUsage(L"ole32.dll", "CoIncrementMTAUsage");
|
||||
if (pCoIncrementMTAUsage) {
|
||||
// Calling this function initializes the MTA without needing to explicitly
|
||||
// create a thread and call CoInitializeEx to do it.
|
||||
// We don't retain the cookie because once we've incremented the MTA, we
|
||||
// leave it that way for the lifetime of the process.
|
||||
CO_MTA_USAGE_COOKIE mtaCookie = nullptr;
|
||||
HRESULT hr = pCoIncrementMTAUsage(&mtaCookie);
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
if (SUCCEEDED(hr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// In the fallback case, we simply initialize our persistent MTA thread.
|
||||
|
||||
// Make sure thread manager init succeeded before trying to initialize the
|
||||
// persistent MTA thread.
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Before proceeding any further, pump a runnable through the persistent MTA
|
||||
// thread to ensure that it is up and running and has finished initializing
|
||||
// the multi-threaded apartment.
|
||||
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
|
||||
"EnsureMTA::EnsureMTA()",
|
||||
[]() { MOZ_RELEASE_ASSERT(IsCurrentThreadExplicitMTA()); }));
|
||||
SyncDispatchToPersistentThread(runnable);
|
||||
}
|
||||
|
||||
/* static */
|
||||
RefPtr<EnsureMTA::CreateInstanceAgileRefPromise>
|
||||
EnsureMTA::CreateInstanceInternal(REFCLSID aClsid, REFIID aIid) {
|
||||
|
@ -172,14 +113,14 @@ RefPtr<EnsureMTA::CreateInstanceAgileRefPromise> EnsureMTA::CreateInstance(
|
|||
return CreateInstanceInternal(localClsid, localIid);
|
||||
};
|
||||
|
||||
nsCOMPtr<nsIThread> mtaThread(GetPersistentMTAThread());
|
||||
nsCOMPtr<nsIThread> mtaThread(GetMTAThread());
|
||||
|
||||
return InvokeAsync(mtaThread->SerialEventTarget(), __func__,
|
||||
std::move(invoker));
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsCOMPtr<nsIThread> EnsureMTA::GetPersistentMTAThread() {
|
||||
nsCOMPtr<nsIThread> EnsureMTA::GetMTAThread() {
|
||||
static StaticLocalAutoPtr<BackgroundMTAData> sMTAData(
|
||||
[]() -> BackgroundMTAData* {
|
||||
BackgroundMTAData* bgData = new BackgroundMTAData();
|
||||
|
@ -195,7 +136,7 @@ nsCOMPtr<nsIThread> EnsureMTA::GetPersistentMTAThread() {
|
|||
|
||||
SchedulerGroup::Dispatch(
|
||||
TaskCategory::Other,
|
||||
NS_NewRunnableFunction("mscom::EnsureMTA::GetPersistentMTAThread",
|
||||
NS_NewRunnableFunction("mscom::EnsureMTA::GetMTAThread",
|
||||
std::move(setClearOnShutdown)));
|
||||
|
||||
return bgData;
|
||||
|
@ -206,57 +147,5 @@ nsCOMPtr<nsIThread> EnsureMTA::GetPersistentMTAThread() {
|
|||
return sMTAData->GetThread();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void EnsureMTA::SyncDispatchToPersistentThread(nsIRunnable* aRunnable) {
|
||||
nsCOMPtr<nsIThread> thread(GetPersistentMTAThread());
|
||||
MOZ_ASSERT(thread);
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that, due to APC dispatch, we might reenter this function while we
|
||||
// wait on this event. We therefore need a unique event object for each
|
||||
// entry into this function. If perf becomes an issue then we will want to
|
||||
// maintain an array of events where the Nth event is unique to the Nth
|
||||
// reentry.
|
||||
nsAutoHandle event(::CreateEventW(nullptr, FALSE, FALSE, nullptr));
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE eventHandle = event.get();
|
||||
auto eventSetter = [&aRunnable, eventHandle]() -> void {
|
||||
aRunnable->Run();
|
||||
::SetEvent(eventHandle);
|
||||
};
|
||||
|
||||
nsresult rv = thread->Dispatch(
|
||||
NS_NewRunnableFunction("mscom::EnsureMTA::SyncDispatchToPersistentThread",
|
||||
std::move(eventSetter)),
|
||||
NS_DISPATCH_NORMAL);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const BOOL alertable = XRE_IsContentProcess() && NS_IsMainThread();
|
||||
|
||||
DWORD waitResult;
|
||||
while ((waitResult = ::WaitForSingleObjectEx(event, INFINITE, alertable)) ==
|
||||
WAIT_IO_COMPLETION) {
|
||||
}
|
||||
MOZ_ASSERT(waitResult == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
/**
|
||||
* While this function currently appears to be redundant, it may become more
|
||||
* sophisticated in the future. For example, we could optionally dispatch to an
|
||||
* MTA context if we wanted to utilize the MTA thread pool.
|
||||
*/
|
||||
/* static */
|
||||
void EnsureMTA::SyncDispatch(nsCOMPtr<nsIRunnable>&& aRunnable, Option aOpt) {
|
||||
SyncDispatchToPersistentThread(aRunnable);
|
||||
}
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -40,37 +40,74 @@ struct PreservedStreamDeleter;
|
|||
|
||||
} // namespace detail
|
||||
|
||||
class ProcessRuntime;
|
||||
|
||||
// This class is OK to use as a temporary on the stack.
|
||||
class MOZ_STACK_CLASS EnsureMTA final {
|
||||
public:
|
||||
/**
|
||||
* This constructor just ensures that the MTA thread is up and running.
|
||||
*/
|
||||
EnsureMTA() {
|
||||
nsCOMPtr<nsIThread> thread = GetMTAThread();
|
||||
MOZ_ASSERT(thread);
|
||||
Unused << thread;
|
||||
}
|
||||
|
||||
enum class Option {
|
||||
Default,
|
||||
// Forcibly dispatch to the thread returned by GetPersistentMTAThread(),
|
||||
// even if the current thread is already inside a MTA.
|
||||
ForceDispatchToPersistentThread,
|
||||
// Forcibly dispatch to the thread returned by GetMTAThread(), even if the
|
||||
// current thread is already inside a MTA.
|
||||
ForceDispatch,
|
||||
};
|
||||
|
||||
/**
|
||||
* Synchronously run |aClosure| on a thread living in the COM multithreaded
|
||||
* apartment. If the current thread lives inside the COM MTA, then it runs
|
||||
* |aClosure| immediately unless |aOpt| ==
|
||||
* Option::ForceDispatchToPersistentThread.
|
||||
* |aClosure| immediately unless |aOpt| == Option::ForceDispatch.
|
||||
*/
|
||||
template <typename FuncT>
|
||||
explicit EnsureMTA(FuncT&& aClosure, Option aOpt = Option::Default) {
|
||||
if (aOpt != Option::ForceDispatchToPersistentThread &&
|
||||
IsCurrentThreadMTA()) {
|
||||
if (aOpt != Option::ForceDispatch && IsCurrentThreadMTA()) {
|
||||
// We're already on the MTA, we can run aClosure directly
|
||||
aClosure();
|
||||
return;
|
||||
}
|
||||
|
||||
// In this case we need to run aClosure on a background thread in the MTA
|
||||
nsCOMPtr<nsIRunnable> runnable(
|
||||
NS_NewRunnableFunction("EnsureMTA::EnsureMTA", std::move(aClosure)));
|
||||
SyncDispatch(std::move(runnable), aOpt);
|
||||
nsCOMPtr<nsIThread> thread = GetMTAThread();
|
||||
MOZ_ASSERT(thread);
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that we might reenter the EnsureMTA constructor while we wait on
|
||||
// this event due to APC dispatch, therefore we need a unique event object
|
||||
// for each entry. If perf becomes an issue then we will want to maintain
|
||||
// an array of events where the Nth event is unique to the Nth reentry.
|
||||
nsAutoHandle event(::CreateEventW(nullptr, FALSE, FALSE, nullptr));
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE eventHandle = event.get();
|
||||
|
||||
auto eventSetter = [&aClosure, eventHandle]() -> void {
|
||||
aClosure();
|
||||
::SetEvent(eventHandle);
|
||||
};
|
||||
|
||||
nsresult rv = thread->Dispatch(
|
||||
NS_NewRunnableFunction("EnsureMTA", std::move(eventSetter)),
|
||||
NS_DISPATCH_NORMAL);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD waitResult;
|
||||
while ((waitResult = ::WaitForSingleObjectEx(event, INFINITE, TRUE)) ==
|
||||
WAIT_IO_COMPLETION) {
|
||||
}
|
||||
MOZ_ASSERT(waitResult == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
using CreateInstanceAgileRefPromise =
|
||||
|
@ -136,10 +173,7 @@ class MOZ_STACK_CLASS EnsureMTA final {
|
|||
static RefPtr<CreateInstanceAgileRefPromise> CreateInstanceInternal(
|
||||
REFCLSID aClsid, REFIID aIid);
|
||||
|
||||
static nsCOMPtr<nsIThread> GetPersistentMTAThread();
|
||||
|
||||
static void SyncDispatch(nsCOMPtr<nsIRunnable>&& aRunnable, Option aOpt);
|
||||
static void SyncDispatchToPersistentThread(nsIRunnable* aRunnable);
|
||||
static nsCOMPtr<nsIThread> GetMTAThread();
|
||||
|
||||
// The following function is private in order to force any consumers to be
|
||||
// declared as friends of EnsureMTA. The intention is to prevent
|
||||
|
@ -152,7 +186,7 @@ class MOZ_STACK_CLASS EnsureMTA final {
|
|||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread(GetPersistentMTAThread());
|
||||
nsCOMPtr<nsIThread> thread(GetMTAThread());
|
||||
MOZ_ASSERT(thread);
|
||||
if (!thread) {
|
||||
return;
|
||||
|
@ -165,14 +199,6 @@ class MOZ_STACK_CLASS EnsureMTA final {
|
|||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor just ensures that the MTA is up and running. This should
|
||||
* only be called by ProcessRuntime.
|
||||
*/
|
||||
EnsureMTA();
|
||||
|
||||
friend class mozilla::mscom::ProcessRuntime;
|
||||
|
||||
template <typename T>
|
||||
friend struct mozilla::mscom::detail::MTADelete;
|
||||
|
||||
|
|
|
@ -16,15 +16,14 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "mozilla/WindowsProcessMitigations.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#if defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
|
||||
# include "mozilla/mscom/EnsureMTA.h"
|
||||
# if defined(MOZ_SANDBOX)
|
||||
# include "mozilla/sandboxTarget.h"
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
# include "mozilla/sandboxTarget.h"
|
||||
# include "nsThreadManager.h"
|
||||
#endif // defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
|
||||
|
||||
#include <accctrl.h>
|
||||
#include <aclapi.h>
|
||||
|
@ -37,18 +36,12 @@ extern "C" void __cdecl SetOaNoCache(void);
|
|||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
ProcessRuntime* ProcessRuntime::sInstance = nullptr;
|
||||
|
||||
ProcessRuntime::ProcessRuntime() : ProcessRuntime(XRE_GetProcessType()) {}
|
||||
|
||||
ProcessRuntime::ProcessRuntime(const GeckoProcessType aProcessType)
|
||||
ProcessRuntime::ProcessRuntime(GeckoProcessType aProcessType)
|
||||
: ProcessRuntime(aProcessType == GeckoProcessType_Default
|
||||
? ProcessCategory::GeckoBrowserParent
|
||||
: ProcessCategory::GeckoChild) {}
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
ProcessRuntime::ProcessRuntime(const ProcessCategory aProcessCategory)
|
||||
ProcessRuntime::ProcessRuntime(ProcessRuntime::ProcessCategory aProcessCategory)
|
||||
: mInitResult(CO_E_NOTINITIALIZED),
|
||||
mProcessCategory(aProcessCategory)
|
||||
#if defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
|
||||
|
@ -56,38 +49,23 @@ ProcessRuntime::ProcessRuntime(const ProcessCategory aProcessCategory)
|
|||
mActCtxRgn(a11y::Compatibility::GetActCtxResourceId())
|
||||
#endif // defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
|
||||
{
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
MOZ_DIAGNOSTIC_ASSERT(!sInstance);
|
||||
sInstance = this;
|
||||
|
||||
EnsureMTA();
|
||||
/**
|
||||
* From this point forward, all threads in this process are implicitly
|
||||
* members of the multi-threaded apartment, with the following exceptions:
|
||||
* 1. If any Win32 GUI APIs were called on the current thread prior to
|
||||
* executing this constructor, then this thread has already been implicitly
|
||||
* initialized as the process's main STA thread; or
|
||||
* 2. A thread explicitly calls CoInitialize(Ex) to specify otherwise.
|
||||
*/
|
||||
|
||||
const bool isCurThreadImplicitMTA = IsCurrentThreadImplicitMTA();
|
||||
// We only assert that the implicit MTA precondition holds when not running
|
||||
// as the Gecko parent process.
|
||||
MOZ_DIAGNOSTIC_ASSERT(aProcessCategory ==
|
||||
ProcessCategory::GeckoBrowserParent ||
|
||||
isCurThreadImplicitMTA);
|
||||
|
||||
# if defined(MOZ_SANDBOX)
|
||||
const bool isLockedDownChildProcess =
|
||||
mProcessCategory == ProcessCategory::GeckoChild && IsWin32kLockedDown();
|
||||
#if defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
|
||||
// If our process is running under Win32k lockdown, we cannot initialize
|
||||
// COM with a single-threaded apartment. This is because STAs create a hidden
|
||||
// COM with single-threaded apartments. This is because STAs create a hidden
|
||||
// window, which implicitly requires user32 and Win32k, which are blocked.
|
||||
// Instead we start the multi-threaded apartment and conduct our process-wide
|
||||
// COM initialization there.
|
||||
if (isLockedDownChildProcess) {
|
||||
// Make sure we're still running with the sandbox's privileged impersonation
|
||||
// token.
|
||||
// Instead we start a multi-threaded apartment and conduct our process-wide
|
||||
// COM initialization on that MTA background thread.
|
||||
if (mProcessCategory == ProcessCategory::GeckoChild && IsWin32kLockedDown()) {
|
||||
// It is possible that we're running so early that we might need to start
|
||||
// the thread manager ourselves.
|
||||
nsresult rv = nsThreadManager::get().Init();
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the current thread's impersonation token to initialize COM, as
|
||||
// it might fail otherwise (depending on sandbox policy).
|
||||
HANDLE rawCurThreadImpToken;
|
||||
if (!::OpenThreadToken(::GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY,
|
||||
FALSE, &rawCurThreadImpToken)) {
|
||||
|
@ -96,26 +74,51 @@ ProcessRuntime::ProcessRuntime(const ProcessCategory aProcessCategory)
|
|||
}
|
||||
nsAutoHandle curThreadImpToken(rawCurThreadImpToken);
|
||||
|
||||
# if defined(DEBUG)
|
||||
// Ensure that our current token is still an impersonation token (ie, we
|
||||
// have not yet called RevertToSelf() on this thread).
|
||||
DWORD len;
|
||||
TOKEN_TYPE tokenType;
|
||||
MOZ_RELEASE_ASSERT(
|
||||
::GetTokenInformation(rawCurThreadImpToken, TokenType, &tokenType,
|
||||
sizeof(tokenType), &len) &&
|
||||
len == sizeof(tokenType) && tokenType == TokenImpersonation);
|
||||
MOZ_ASSERT(::GetTokenInformation(rawCurThreadImpToken, TokenType,
|
||||
&tokenType, sizeof(tokenType), &len) &&
|
||||
len == sizeof(tokenType) && tokenType == TokenImpersonation);
|
||||
# endif // defined(DEBUG)
|
||||
|
||||
// Ideally we want our current thread to be running implicitly inside the
|
||||
// MTA, but if for some wacky reason we did not end up with that, we may
|
||||
// compensate by completing initialization via EnsureMTA's persistent
|
||||
// thread.
|
||||
if (!isCurThreadImplicitMTA) {
|
||||
InitUsingPersistentMTAThread(curThreadImpToken);
|
||||
// Create an impersonation token based on the current thread's token
|
||||
HANDLE rawMtaThreadImpToken = nullptr;
|
||||
if (!::DuplicateToken(rawCurThreadImpToken, SecurityImpersonation,
|
||||
&rawMtaThreadImpToken)) {
|
||||
mInitResult = HRESULT_FROM_WIN32(::GetLastError());
|
||||
return;
|
||||
}
|
||||
nsAutoHandle mtaThreadImpToken(rawMtaThreadImpToken);
|
||||
|
||||
SandboxTarget::Instance()->RegisterSandboxStartCallback([]() -> void {
|
||||
EnsureMTA(
|
||||
[]() -> void {
|
||||
// This is a security risk if it fails, so we release assert
|
||||
MOZ_RELEASE_ASSERT(::RevertToSelf(),
|
||||
"mscom::ProcessRuntime RevertToSelf failed");
|
||||
},
|
||||
EnsureMTA::Option::ForceDispatch);
|
||||
});
|
||||
|
||||
// Impersonate and initialize.
|
||||
EnsureMTA(
|
||||
[this, rawMtaThreadImpToken]() -> void {
|
||||
if (!::SetThreadToken(nullptr, rawMtaThreadImpToken)) {
|
||||
mInitResult = HRESULT_FROM_WIN32(::GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
InitInsideApartment();
|
||||
},
|
||||
EnsureMTA::Option::ForceDispatch);
|
||||
|
||||
return;
|
||||
}
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
mAptRegion.Init(GetDesiredApartmentType(mProcessCategory));
|
||||
|
||||
|
@ -128,94 +131,18 @@ ProcessRuntime::ProcessRuntime(const ProcessCategory aProcessCategory)
|
|||
}
|
||||
|
||||
InitInsideApartment();
|
||||
if (FAILED(mInitResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# if defined(MOZ_SANDBOX)
|
||||
if (isLockedDownChildProcess) {
|
||||
// In locked-down child processes, defer PostInit until priv drop
|
||||
SandboxTarget::Instance()->RegisterSandboxStartCallback([self = this]() {
|
||||
// Ensure that we're still live and the init was successful before
|
||||
// calling PostInit()
|
||||
if (self == sInstance && SUCCEEDED(self->mInitResult)) {
|
||||
PostInit();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
|
||||
PostInit();
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
}
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
ProcessRuntime::~ProcessRuntime() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(sInstance == this);
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
# if defined(MOZ_SANDBOX)
|
||||
void ProcessRuntime::InitUsingPersistentMTAThread(
|
||||
const nsAutoHandle& aCurThreadToken) {
|
||||
// Create an impersonation token based on the current thread's token
|
||||
HANDLE rawMtaThreadImpToken = nullptr;
|
||||
if (!::DuplicateToken(aCurThreadToken, SecurityImpersonation,
|
||||
&rawMtaThreadImpToken)) {
|
||||
mInitResult = HRESULT_FROM_WIN32(::GetLastError());
|
||||
return;
|
||||
}
|
||||
nsAutoHandle mtaThreadImpToken(rawMtaThreadImpToken);
|
||||
|
||||
SandboxTarget::Instance()->RegisterSandboxStartCallback(
|
||||
[self = this]() -> void {
|
||||
EnsureMTA(
|
||||
[]() -> void {
|
||||
// This is a security risk if it fails, so we release assert
|
||||
MOZ_RELEASE_ASSERT(::RevertToSelf(),
|
||||
"mscom::ProcessRuntime RevertToSelf failed");
|
||||
},
|
||||
EnsureMTA::Option::ForceDispatchToPersistentThread);
|
||||
|
||||
// Ensure that we're still live and the init was successful before
|
||||
// calling PostInit()
|
||||
if (self == sInstance && SUCCEEDED(self->mInitResult)) {
|
||||
PostInit();
|
||||
}
|
||||
});
|
||||
|
||||
// Impersonate and initialize.
|
||||
EnsureMTA(
|
||||
[this, rawMtaThreadImpToken]() -> void {
|
||||
if (!::SetThreadToken(nullptr, rawMtaThreadImpToken)) {
|
||||
mInitResult = HRESULT_FROM_WIN32(::GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
InitInsideApartment();
|
||||
},
|
||||
EnsureMTA::Option::ForceDispatchToPersistentThread);
|
||||
}
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
/* static */
|
||||
COINIT ProcessRuntime::GetDesiredApartmentType(
|
||||
const ProcessRuntime::ProcessCategory aProcessCategory) {
|
||||
ProcessRuntime::ProcessCategory aProcessCategory) {
|
||||
// Gecko processes get single-threaded apartments, others get multithreaded
|
||||
// apartments. We should revisit the GeckoChild case as soon as we deploy
|
||||
// Win32k lockdown.
|
||||
switch (aProcessCategory) {
|
||||
case ProcessCategory::GeckoBrowserParent:
|
||||
return COINIT_APARTMENTTHREADED;
|
||||
case ProcessCategory::GeckoChild:
|
||||
if (!IsWin32kLockedDown()) {
|
||||
// If Win32k is not locked down then we probably still need STA.
|
||||
// We disable DDE since that is not usable from child processes.
|
||||
return static_cast<COINIT>(COINIT_APARTMENTTHREADED |
|
||||
COINIT_DISABLE_OLE1DDE);
|
||||
}
|
||||
|
||||
[[fallthrough]];
|
||||
return COINIT_APARTMENTTHREADED;
|
||||
default:
|
||||
return COINIT_MULTITHREADED;
|
||||
}
|
||||
|
@ -230,20 +157,16 @@ void ProcessRuntime::InitInsideApartment() {
|
|||
}
|
||||
|
||||
// We are required to initialize security prior to configuring global options.
|
||||
mInitResult = InitializeSecurity(mProcessCategory);
|
||||
MOZ_DIAGNOSTIC_ASSERT(SUCCEEDED(mInitResult));
|
||||
|
||||
// Even though this isn't great, we should try to proceed even when
|
||||
// CoInitializeSecurity has previously been called: the additional settings
|
||||
// we want to change are important enough that we don't want to skip them.
|
||||
if (FAILED(mInitResult) && mInitResult != RPC_E_TOO_LATE) {
|
||||
mInitResult = InitializeSecurity();
|
||||
MOZ_ASSERT(SUCCEEDED(mInitResult));
|
||||
if (FAILED(mInitResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<IGlobalOptions> globalOpts;
|
||||
mInitResult =
|
||||
::CoCreateInstance(CLSID_GlobalOptions, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_IGlobalOptions, getter_AddRefs(globalOpts));
|
||||
mInitResult = ::CoCreateInstance(CLSID_GlobalOptions, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_IGlobalOptions,
|
||||
(void**)getter_AddRefs(globalOpts));
|
||||
MOZ_ASSERT(SUCCEEDED(mInitResult));
|
||||
if (FAILED(mInitResult)) {
|
||||
return;
|
||||
|
@ -264,16 +187,6 @@ void ProcessRuntime::InitInsideApartment() {
|
|||
lock.SetInitialized();
|
||||
}
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
/**
|
||||
* Guaranteed to run *after* the COM (and possible sandboxing) initialization
|
||||
* has successfully completed and stabilized. This method MUST BE IDEMPOTENT!
|
||||
*/
|
||||
/* static */ void ProcessRuntime::PostInit() {
|
||||
// Currently "roughed-in" but unused.
|
||||
}
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
/* static */
|
||||
DWORD
|
||||
ProcessRuntime::GetClientThreadId() {
|
||||
|
@ -288,9 +201,8 @@ ProcessRuntime::GetClientThreadId() {
|
|||
return callerTid;
|
||||
}
|
||||
|
||||
/* static */
|
||||
HRESULT
|
||||
ProcessRuntime::InitializeSecurity(const ProcessCategory aProcessCategory) {
|
||||
ProcessRuntime::InitializeSecurity() {
|
||||
HANDLE rawToken = nullptr;
|
||||
BOOL ok = ::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken);
|
||||
if (!ok) {
|
||||
|
@ -347,13 +259,10 @@ ProcessRuntime::InitializeSecurity(const ProcessCategory aProcessCategory) {
|
|||
return HRESULT_FROM_WIN32(::GetLastError());
|
||||
}
|
||||
|
||||
const bool allowAppContainers =
|
||||
aProcessCategory == ProcessCategory::GeckoBrowserParent &&
|
||||
IsWin8OrLater();
|
||||
|
||||
BYTE appContainersSid[SECURITY_MAX_SID_SIZE];
|
||||
DWORD appContainersSidSize = sizeof(appContainersSid);
|
||||
if (allowAppContainers) {
|
||||
if (mProcessCategory == ProcessCategory::GeckoBrowserParent &&
|
||||
IsWin8OrLater()) {
|
||||
if (!::CreateWellKnownSid(WinBuiltinAnyPackageSid, nullptr,
|
||||
appContainersSid, &appContainersSidSize)) {
|
||||
return HRESULT_FROM_WIN32(::GetLastError());
|
||||
|
@ -386,7 +295,8 @@ ProcessRuntime::InitializeSecurity(const ProcessCategory aProcessCategory) {
|
|||
{nullptr, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID, TRUSTEE_IS_USER,
|
||||
reinterpret_cast<LPWSTR>(tokenUser.User.Sid)}});
|
||||
|
||||
if (allowAppContainers) {
|
||||
if (mProcessCategory == ProcessCategory::GeckoBrowserParent &&
|
||||
IsWin8OrLater()) {
|
||||
Unused << entries.append(
|
||||
EXPLICIT_ACCESS_W{COM_RIGHTS_EXECUTE,
|
||||
GRANT_ACCESS,
|
||||
|
|
|
@ -12,10 +12,8 @@
|
|||
# include "mozilla/mscom/ActivationContext.h"
|
||||
#endif // defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
|
||||
#include "mozilla/mscom/ApartmentRegion.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# include "nsXULAppAPI.h"
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
#include "mozilla/WindowsProcessMitigations.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
@ -34,22 +32,23 @@ class MOZ_NON_TEMPORARY_CLASS ProcessRuntime final {
|
|||
};
|
||||
|
||||
// This constructor is only public when compiled outside of XUL
|
||||
explicit ProcessRuntime(const ProcessCategory aProcessCategory);
|
||||
explicit ProcessRuntime(ProcessCategory aProcessCategory);
|
||||
|
||||
public:
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
ProcessRuntime();
|
||||
~ProcessRuntime();
|
||||
#else
|
||||
~ProcessRuntime() = default;
|
||||
ProcessRuntime() : ProcessRuntime(XRE_GetProcessType()) {}
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
explicit ProcessRuntime(GeckoProcessType aProcessType);
|
||||
|
||||
~ProcessRuntime() = default;
|
||||
|
||||
explicit operator bool() const { return SUCCEEDED(mInitResult); }
|
||||
HRESULT GetHResult() const { return mInitResult; }
|
||||
|
||||
ProcessRuntime(const ProcessRuntime&) = delete;
|
||||
ProcessRuntime(ProcessRuntime&) = delete;
|
||||
ProcessRuntime(ProcessRuntime&&) = delete;
|
||||
ProcessRuntime& operator=(const ProcessRuntime&) = delete;
|
||||
ProcessRuntime& operator=(ProcessRuntime&) = delete;
|
||||
ProcessRuntime& operator=(ProcessRuntime&&) = delete;
|
||||
|
||||
/**
|
||||
|
@ -59,32 +58,16 @@ class MOZ_NON_TEMPORARY_CLASS ProcessRuntime final {
|
|||
static DWORD GetClientThreadId();
|
||||
|
||||
private:
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
explicit ProcessRuntime(const GeckoProcessType aProcessType);
|
||||
# if defined(MOZ_SANDBOX)
|
||||
void InitUsingPersistentMTAThread(const nsAutoHandle& aCurThreadToken);
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
void InitInsideApartment();
|
||||
HRESULT InitializeSecurity();
|
||||
static COINIT GetDesiredApartmentType(ProcessCategory aProcessCategory);
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
static void PostInit();
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
static HRESULT InitializeSecurity(const ProcessCategory aProcessCategory);
|
||||
static COINIT GetDesiredApartmentType(const ProcessCategory aProcessCategory);
|
||||
|
||||
private:
|
||||
HRESULT mInitResult;
|
||||
const ProcessCategory mProcessCategory;
|
||||
#if defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
|
||||
ActivationContextRegion mActCtxRgn;
|
||||
#endif // defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
|
||||
ApartmentRegion mAptRegion;
|
||||
|
||||
private:
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
static ProcessRuntime* sInstance;
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
};
|
||||
|
||||
} // namespace mscom
|
||||
|
|
|
@ -25,6 +25,6 @@ MFBT_API bool& BeginProcessRuntimeInit() {
|
|||
|
||||
MFBT_API void EndProcessRuntimeInit() { gLock.UnlockExclusive(); }
|
||||
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -98,7 +98,7 @@ JumpListBuilder::JumpListBuilder()
|
|||
// Instantiate mJumpListMgr in the multithreaded apartment so that proxied
|
||||
// calls on that object do not need to interact with the main thread's message
|
||||
// pump.
|
||||
mscom::EnsureMTA([&]() {
|
||||
mscom::EnsureMTA([this]() {
|
||||
RefPtr<ICustomDestinationList> jumpListMgr;
|
||||
HRESULT hr = ::CoCreateInstance(
|
||||
CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <cderr.h>
|
||||
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
#include "mozilla/ProfilerLabels.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
using mozilla::IsWin8OrLater;
|
||||
using mozilla::MakeUnique;
|
||||
using mozilla::UniquePtr;
|
||||
using mozilla::mscom::EnsureMTA;
|
||||
|
||||
using namespace mozilla::widget;
|
||||
|
||||
|
@ -108,6 +110,15 @@ NS_IMETHODIMP nsFilePicker::Init(mozIDOMWindowProxy* aParent,
|
|||
* @return true if a file was selected successfully.
|
||||
*/
|
||||
bool nsFilePicker::ShowFolderPicker(const nsString& aInitialDir) {
|
||||
if (!IsWin8OrLater()) {
|
||||
// Some Windows 7 users are experiencing a race condition when some dlls
|
||||
// that are loaded by the file picker cause a crash while attempting to shut
|
||||
// down the COM multithreaded apartment. By instantiating EnsureMTA, we hold
|
||||
// an additional reference to the MTA that should prevent this race, since
|
||||
// the MTA will remain alive until shutdown.
|
||||
EnsureMTA ensureMTA;
|
||||
}
|
||||
|
||||
RefPtr<IFileOpenDialog> dialog;
|
||||
if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_IFileOpenDialog,
|
||||
|
@ -195,6 +206,15 @@ bool nsFilePicker::ShowFolderPicker(const nsString& aInitialDir) {
|
|||
bool nsFilePicker::ShowFilePicker(const nsString& aInitialDir) {
|
||||
AUTO_PROFILER_LABEL("nsFilePicker::ShowFilePicker", OTHER);
|
||||
|
||||
if (!IsWin8OrLater()) {
|
||||
// Some Windows 7 users are experiencing a race condition when some dlls
|
||||
// that are loaded by the file picker cause a crash while attempting to shut
|
||||
// down the COM multithreaded apartment. By instantiating EnsureMTA, we hold
|
||||
// an additional reference to the MTA that should prevent this race, since
|
||||
// the MTA will remain alive until shutdown.
|
||||
EnsureMTA ensureMTA;
|
||||
}
|
||||
|
||||
RefPtr<IFileDialog> dialog;
|
||||
if (mMode != modeSave) {
|
||||
if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr,
|
||||
|
|
Загрузка…
Ссылка в новой задаче