From c601fd8b0ae5edee90c88045f8958cdb7b50d35b Mon Sep 17 00:00:00 2001 From: Toshihito Kikuchi Date: Fri, 4 Mar 2022 21:12:18 +0000 Subject: [PATCH] Bug 1756518 - Delay starting UntrustedModulesProcessor. r=mhowell,necko-reviewers,kershaw This patch is to delay starting `UntrustedModulesProcessor` to avoid processing a massive amount of loaded modules in the browser process during startup. To achive that, this patch introduces "unblock-untrusted-modules-thread" notification. Before the notification, `UntrustedModulesProcessor` is created but marked as not ready. This means the processor does not go beyond `ScheduleNonEmptyQueueProcessing`. Once the notification is observed, we propagate it to all existing child processes, and afterward `UntrustedModulesProcessor` in new processes will be marked ready from the beginning. Differential Revision: https://phabricator.services.mozilla.com/D140123 --- browser/components/BrowserGlue.jsm | 10 ++ dom/ipc/ContentChild.cpp | 19 ++- dom/ipc/ContentChild.h | 7 +- dom/ipc/ContentParent.cpp | 9 +- dom/ipc/PContent.ipdl | 10 +- dom/media/ipc/PRDD.ipdl | 10 +- dom/media/ipc/RDDChild.cpp | 9 +- dom/media/ipc/RDDParent.cpp | 13 +- dom/media/ipc/RDDParent.h | 4 +- ipc/glue/UtilityProcessChild.cpp | 2 +- js/xpconnect/src/XPCShellImpl.cpp | 2 +- netwerk/ipc/PSocketProcess.ipdl | 10 ++ netwerk/ipc/SocketProcessChild.cpp | 20 ++- netwerk/ipc/SocketProcessChild.h | 1 + netwerk/ipc/SocketProcessHost.cpp | 6 + .../dllservices/UntrustedModulesProcessor.cpp | 129 ++++++++++++------ .../dllservices/UntrustedModulesProcessor.h | 13 +- toolkit/xre/dllservices/WinDllServices.cpp | 9 +- toolkit/xre/dllservices/WinDllServices.h | 3 +- .../tests/gtest/TestUntrustedModules.cpp | 2 +- toolkit/xre/nsAppRunner.cpp | 2 +- 21 files changed, 220 insertions(+), 70 deletions(-) diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 435f06c669f9..fde57768680e 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -2766,6 +2766,16 @@ BrowserGlue.prototype = { }, }, + { + condition: AppConstants.platform == "win", + task: () => { + Services.obs.notifyObservers( + null, + "unblock-untrusted-modules-thread" + ); + }, + }, + // WebDriver components (Remote Agent and Marionette) need to be // initialized as very last step. { diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 60e1069eb953..46b4550b035f 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -676,7 +676,8 @@ mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes( FullLookAndFeel&& aLookAndFeelData, dom::SystemFontList&& aFontList, Maybe&& aSharedUASheetHandle, const uintptr_t& aSharedUASheetAddress, - nsTArray&& aSharedFontListBlocks) { + nsTArray&& aSharedFontListBlocks, + const bool& aIsReadyForBackgroundProcessing) { if (!sShutdownCanary) { return IPC_OK(); } @@ -691,7 +692,8 @@ mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes( gfx::gfxVars::SetValuesForInitialize(aXPCOMInit.gfxNonDefaultVarUpdates()); InitSharedUASheets(std::move(aSharedUASheetHandle), aSharedUASheetAddress); - InitXPCOM(std::move(aXPCOMInit), aInitialData); + InitXPCOM(std::move(aXPCOMInit), aInitialData, + aIsReadyForBackgroundProcessing); InitGraphicsDeviceData(aXPCOMInit.contentDeviceData()); return IPC_OK(); @@ -1323,7 +1325,8 @@ void ContentChild::InitSharedUASheets(Maybe&& aHandle, void ContentChild::InitXPCOM( XPCOMInitData&& aXPCOMInit, - const mozilla::dom::ipc::StructuredCloneData& aInitialData) { + const mozilla::dom::ipc::StructuredCloneData& aInitialData, + bool aIsReadyForBackgroundProcessing) { #ifdef MOZ_WIDGET_GTK // LookAndFeel::NativeInit takes a long time to run on Linux, here we schedule // it as soon as possible after BackgroundChild::Startup to give @@ -1336,7 +1339,7 @@ void ContentChild::InitXPCOM( // DLL services untrusted modules processing depends on // BackgroundChild::Startup having been called RefPtr dllSvc(DllServices::Get()); - dllSvc->StartUntrustedModulesProcessor(); + dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing); #endif // defined(XP_WIN) PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); @@ -1463,6 +1466,14 @@ mozilla::ipc::IPCResult ContentChild::RecvGetUntrustedModulesData( [aResolver](nsresult aReason) { aResolver(Nothing()); }); return IPC_OK(); } + +mozilla::ipc::IPCResult ContentChild::RecvUnblockUntrustedModulesThread() { + if (nsCOMPtr obs = + mozilla::services::GetObserverService()) { + obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr); + } + return IPC_OK(); +} #endif // defined(XP_WIN) PCycleCollectWithLogsChild* ContentChild::AllocPCycleCollectWithLogsChild( diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 8bdedfd1f6b0..abeac3759c09 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -124,7 +124,8 @@ class ContentChild final : public PContentChild, bool aIsForBrowser); void InitXPCOM(XPCOMInitData&& aXPCOMInit, - const mozilla::dom::ipc::StructuredCloneData& aInitialData); + const mozilla::dom::ipc::StructuredCloneData& aInitialData, + bool aIsReadyForBackgroundProcessing); void InitSharedUASheets(Maybe&& aHandle, uintptr_t aAddress); @@ -538,6 +539,7 @@ class ContentChild final : public PContentChild, #if defined(XP_WIN) mozilla::ipc::IPCResult RecvGetUntrustedModulesData( GetUntrustedModulesDataResolver&& aResolver); + mozilla::ipc::IPCResult RecvUnblockUntrustedModulesThread(); #endif // defined(XP_WIN) mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes( @@ -545,7 +547,8 @@ class ContentChild final : public PContentChild, FullLookAndFeel&& aLookAndFeelData, SystemFontList&& aFontList, Maybe&& aSharedUASheetHandle, const uintptr_t& aSharedUASheetAddress, - nsTArray&& aSharedFontListBlocks); + nsTArray&& aSharedFontListBlocks, + const bool& aIsReadyForBackgroundProcessing); mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile( const uint64_t& aID, const FileDescOrError& aFD); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index d0e1ff7a2225..424f7e830019 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2990,9 +2990,16 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) { sharedUASheetAddress = 0; } + bool isReadyForBackgroundProcessing = false; +#if defined(XP_WIN) + RefPtr dllSvc(DllServices::Get()); + isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing(); +#endif + Unused << SendSetXPCOMProcessAttributes( xpcomInit, initialData, lnf, fontList, std::move(sharedUASheetHandle), - sharedUASheetAddress, std::move(sharedFontListBlocks)); + sharedUASheetAddress, std::move(sharedFontListBlocks), + isReadyForBackgroundProcessing); ipc::WritableSharedMap* sharedData = nsFrameMessageManager::sParentProcessManager->SharedData(); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 63adacd699b3..cb6e850eb26a 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -580,6 +580,13 @@ child: * to pull data from content processes. */ async GetUntrustedModulesData() returns (UntrustedModulesData? data); + + /** + * This method is used to notifty a child process to start + * processing module loading events in UntrustedModulesProcessor. + * This should be called when the parent process has gone idle. + */ + async UnblockUntrustedModulesThread(); #endif // defined(XP_WIN) /** @@ -750,7 +757,8 @@ child: SystemFontList systemFontList, SharedMemoryHandle? sharedUASheetHandle, uintptr_t sharedUASheetAddress, - SharedMemoryHandle[] sharedFontListBlocks); + SharedMemoryHandle[] sharedFontListBlocks, + bool aIsStartingUp); // Notify child that last-pb-context-exited notification was observed async LastPrivateDocShellDestroyed(); diff --git a/dom/media/ipc/PRDD.ipdl b/dom/media/ipc/PRDD.ipdl index 997bee8aeaf0..36eb7b59c900 100644 --- a/dom/media/ipc/PRDD.ipdl +++ b/dom/media/ipc/PRDD.ipdl @@ -38,7 +38,8 @@ protocol PRDD parent: async Init(GfxVarUpdate[] vars, FileDescriptor? sandboxBroker, - bool canRecordReleaseTelemetry); + bool canRecordReleaseTelemetry, + bool aIsReadyForBackgroundProcessing); async InitProfiler(Endpoint endpoint); @@ -61,6 +62,13 @@ parent: #if defined(XP_WIN) async GetUntrustedModulesData() returns (UntrustedModulesData? data); + + /** + * This method is used to notifty a child process to start + * processing module loading events in UntrustedModulesProcessor. + * This should be called when the parent process has gone idle. + */ + async UnblockUntrustedModulesThread(); #endif // defined(XP_WIN) #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) diff --git a/dom/media/ipc/RDDChild.cpp b/dom/media/ipc/RDDChild.cpp index b3939dd02482..d02512b69c65 100644 --- a/dom/media/ipc/RDDChild.cpp +++ b/dom/media/ipc/RDDChild.cpp @@ -59,7 +59,14 @@ bool RDDChild::Init() { nsTArray updates = gfxVars::FetchNonDefaultVars(); - SendInit(updates, brokerFd, Telemetry::CanRecordReleaseData()); + bool isReadyForBackgroundProcessing = false; +#if defined(XP_WIN) + RefPtr dllSvc(DllServices::Get()); + isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing(); +#endif + + SendInit(updates, brokerFd, Telemetry::CanRecordReleaseData(), + isReadyForBackgroundProcessing); Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid())); diff --git a/dom/media/ipc/RDDParent.cpp b/dom/media/ipc/RDDParent.cpp index 67235b54cbeb..c466959eafef 100644 --- a/dom/media/ipc/RDDParent.cpp +++ b/dom/media/ipc/RDDParent.cpp @@ -124,7 +124,8 @@ void CGSShutdownServerConnections(); mozilla::ipc::IPCResult RDDParent::RecvInit( nsTArray&& vars, const Maybe& aBrokerFd, - const bool& aCanRecordReleaseTelemetry) { + const bool& aCanRecordReleaseTelemetry, + const bool& aIsReadyForBackgroundProcessing) { for (const auto& var : vars) { gfxVars::ApplyUpdate(var); } @@ -151,7 +152,7 @@ mozilla::ipc::IPCResult RDDParent::RecvInit( #if defined(XP_WIN) if (aCanRecordReleaseTelemetry) { RefPtr dllSvc(DllServices::Get()); - dllSvc->StartUntrustedModulesProcessor(); + dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing); } #endif // defined(XP_WIN) return IPC_OK(); @@ -247,6 +248,14 @@ mozilla::ipc::IPCResult RDDParent::RecvGetUntrustedModulesData( [aResolver](nsresult aReason) { aResolver(Nothing()); }); return IPC_OK(); } + +mozilla::ipc::IPCResult RDDParent::RecvUnblockUntrustedModulesThread() { + if (nsCOMPtr obs = + mozilla::services::GetObserverService()) { + obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr); + } + return IPC_OK(); +} #endif // defined(XP_WIN) mozilla::ipc::IPCResult RDDParent::RecvPreferenceUpdate(const Pref& aPref) { diff --git a/dom/media/ipc/RDDParent.h b/dom/media/ipc/RDDParent.h index 84f5d550decd..69e5ea7ccc8b 100644 --- a/dom/media/ipc/RDDParent.h +++ b/dom/media/ipc/RDDParent.h @@ -29,7 +29,8 @@ class RDDParent final : public PRDDParent { mozilla::ipc::IPCResult RecvInit(nsTArray&& vars, const Maybe& aBrokerFd, - const bool& aCanRecordReleaseTelemetry); + const bool& aCanRecordReleaseTelemetry, + const bool& aIsReadyForBackgroundProcessing); mozilla::ipc::IPCResult RecvInitProfiler( Endpoint&& aEndpoint); @@ -47,6 +48,7 @@ class RDDParent final : public PRDDParent { #if defined(XP_WIN) mozilla::ipc::IPCResult RecvGetUntrustedModulesData( GetUntrustedModulesDataResolver&& aResolver); + mozilla::ipc::IPCResult RecvUnblockUntrustedModulesThread(); #endif // defined(XP_WIN) mozilla::ipc::IPCResult RecvPreferenceUpdate(const Pref& pref); mozilla::ipc::IPCResult RecvUpdateVar(const GfxVarUpdate& pref); diff --git a/ipc/glue/UtilityProcessChild.cpp b/ipc/glue/UtilityProcessChild.cpp index 100426dc657b..4963d4abc371 100644 --- a/ipc/glue/UtilityProcessChild.cpp +++ b/ipc/glue/UtilityProcessChild.cpp @@ -138,7 +138,7 @@ mozilla::ipc::IPCResult UtilityProcessChild::RecvInit( #if defined(XP_WIN) if (aCanRecordReleaseTelemetry) { RefPtr dllSvc(DllServices::Get()); - dllSvc->StartUntrustedModulesProcessor(); + dllSvc->StartUntrustedModulesProcessor(false); } #endif // defined(XP_WIN) return IPC_OK(); diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index f8f3492b1c04..76b5cde32284 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1318,7 +1318,7 @@ int XRE_XPCShellMain(int argc, char** argv, char** envp, // Ensure that DLL Services are running RefPtr dllSvc(DllServices::Get()); - dllSvc->StartUntrustedModulesProcessor(); + dllSvc->StartUntrustedModulesProcessor(true); auto dllServicesDisable = MakeScopeExit([&dllSvc]() { dllSvc->DisableFull(); }); diff --git a/netwerk/ipc/PSocketProcess.ipdl b/netwerk/ipc/PSocketProcess.ipdl index 21d22260a97c..6565ca477d3b 100644 --- a/netwerk/ipc/PSocketProcess.ipdl +++ b/netwerk/ipc/PSocketProcess.ipdl @@ -85,6 +85,9 @@ struct SocketPorcessInitAttributes { bool mOffline; bool mConnectivity; bool mInitSandbox; +#if defined(XP_WIN) + bool mIsReadyForBackgroundProcessing; +#endif FileDescriptor? mSandboxBroker; }; @@ -222,6 +225,13 @@ child: #if defined(XP_WIN) async GetUntrustedModulesData() returns (UntrustedModulesData? data); + + /** + * This method is used to notifty a child process to start + * processing module loading events in UntrustedModulesProcessor. + * This should be called when the parent process has gone idle. + */ + async UnblockUntrustedModulesThread(); #endif // defined(XP_WIN) both: diff --git a/netwerk/ipc/SocketProcessChild.cpp b/netwerk/ipc/SocketProcessChild.cpp index b72f6f77d8d1..287c40100a3d 100644 --- a/netwerk/ipc/SocketProcessChild.cpp +++ b/netwerk/ipc/SocketProcessChild.cpp @@ -169,11 +169,6 @@ bool SocketProcessChild::Init(base::ProcessId aParentPid, return false; } -#if defined(XP_WIN) - RefPtr dllSvc(DllServices::Get()); - dllSvc->StartUntrustedModulesProcessor(); -#endif // defined(XP_WIN) - return true; } @@ -228,6 +223,12 @@ mozilla::ipc::IPCResult SocketProcessChild::RecvInit( Unused << RecvInitLinuxSandbox(aAttributes.mSandboxBroker()); } +#if defined(XP_WIN) + RefPtr dllSvc(DllServices::Get()); + dllSvc->StartUntrustedModulesProcessor( + aAttributes.mIsReadyForBackgroundProcessing()); +#endif // defined(XP_WIN) + return IPC_OK(); } @@ -740,6 +741,15 @@ mozilla::ipc::IPCResult SocketProcessChild::RecvGetUntrustedModulesData( [aResolver](nsresult aReason) { aResolver(Nothing()); }); return IPC_OK(); } + +mozilla::ipc::IPCResult +SocketProcessChild::RecvUnblockUntrustedModulesThread() { + if (nsCOMPtr obs = + mozilla::services::GetObserverService()) { + obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr); + } + return IPC_OK(); +} #endif // defined(XP_WIN) } // namespace net diff --git a/netwerk/ipc/SocketProcessChild.h b/netwerk/ipc/SocketProcessChild.h index 792f95adf48e..f8e1b82aeb1a 100644 --- a/netwerk/ipc/SocketProcessChild.h +++ b/netwerk/ipc/SocketProcessChild.h @@ -160,6 +160,7 @@ class SocketProcessChild final #if defined(XP_WIN) mozilla::ipc::IPCResult RecvGetUntrustedModulesData( GetUntrustedModulesDataResolver&& aResolver); + mozilla::ipc::IPCResult RecvUnblockUntrustedModulesThread(); #endif // defined(XP_WIN) protected: diff --git a/netwerk/ipc/SocketProcessHost.cpp b/netwerk/ipc/SocketProcessHost.cpp index 9680d292dd35..0c551a43551d 100644 --- a/netwerk/ipc/SocketProcessHost.cpp +++ b/netwerk/ipc/SocketProcessHost.cpp @@ -176,6 +176,12 @@ void SocketProcessHost::InitAfterConnect(bool aSucceeded) { attributes.mInitSandbox() = false; +#if defined(XP_WIN) + RefPtr dllSvc(DllServices::Get()); + attributes.mIsReadyForBackgroundProcessing() = + dllSvc->IsReadyForBackgroundProcessing(); +#endif + #if defined(XP_LINUX) && defined(MOZ_SANDBOX) if (GetEffectiveSocketProcessSandboxLevel() > 0) { auto policy = SandboxBrokerPolicyFactory::GetSocketProcessPolicy( diff --git a/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp b/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp index ee34a5f124cc..e2b7403c5893 100644 --- a/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp +++ b/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp @@ -11,9 +11,13 @@ #include "mozilla/CmdLineAndEnvUtils.h" #include "mozilla/DebugOnly.h" #include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/ContentParent.h" #include "mozilla/Likely.h" #include "mozilla/net/SocketProcessChild.h" +#include "mozilla/net/SocketProcessParent.h" +#include "mozilla/RDDChild.h" #include "mozilla/RDDParent.h" +#include "mozilla/RDDProcessManager.h" #include "mozilla/ScopeExit.h" #include "mozilla/Services.h" #include "mozilla/Telemetry.h" @@ -106,12 +110,14 @@ bool UntrustedModulesProcessor::IsSupportedProcessType() { } /* static */ -RefPtr UntrustedModulesProcessor::Create() { +RefPtr UntrustedModulesProcessor::Create( + bool aIsReadyForBackgroundProcessing) { if (!IsSupportedProcessType()) { return nullptr; } - RefPtr result(new UntrustedModulesProcessor()); + RefPtr result( + new UntrustedModulesProcessor(aIsReadyForBackgroundProcessing)); return result.forget(); } @@ -119,14 +125,16 @@ NS_IMPL_ISUPPORTS(UntrustedModulesProcessor, nsIObserver) static const uint32_t kThreadTimeoutMS = 120000; // 2 minutes -UntrustedModulesProcessor::UntrustedModulesProcessor() +UntrustedModulesProcessor::UntrustedModulesProcessor( + bool aIsReadyForBackgroundProcessing) : mThread(new LazyIdleThread(kThreadTimeoutMS, "Untrusted Modules"_ns, LazyIdleThread::ManualShutdown)), mUnprocessedMutex( "mozilla::UntrustedModulesProcessor::mUnprocessedMutex"), mModuleCacheMutex( "mozilla::UntrustedModulesProcessor::mModuleCacheMutex"), - mAllowProcessing(true) { + mStatus(aIsReadyForBackgroundProcessing ? Status::Allowed + : Status::StartingUp) { AddObservers(); } @@ -134,17 +142,22 @@ void UntrustedModulesProcessor::AddObservers() { nsCOMPtr obsServ(services::GetObserverService()); obsServ->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false); obsServ->AddObserver(this, "xpcom-shutdown-threads", false); + obsServ->AddObserver(this, "unblock-untrusted-modules-thread", false); if (XRE_IsContentProcess()) { obsServ->AddObserver(this, "content-child-will-shutdown", false); } } +bool UntrustedModulesProcessor::IsReadyForBackgroundProcessing() const { + return mStatus == Status::Allowed; +} + void UntrustedModulesProcessor::Disable() { // Ensure that mThread cannot run at low priority anymore BackgroundPriorityRegion::Clear(mThread); // No more background processing allowed beyond this point - if (!mAllowProcessing.exchange(false)) { + if (mStatus.exchange(Status::ShuttingDown) != Status::Allowed) { return; } @@ -171,6 +184,37 @@ NS_IMETHODIMP UntrustedModulesProcessor::Observe(nsISupports* aSubject, return NS_OK; } + if (!strcmp(aTopic, "unblock-untrusted-modules-thread")) { + nsCOMPtr obs(services::GetObserverService()); + obs->RemoveObserver(this, "unblock-untrusted-modules-thread"); + + mStatus.compareExchange(Status::StartingUp, Status::Allowed); + + if (!IsReadyForBackgroundProcessing()) { + // If we're shutting down, stop here. + return NS_OK; + } + + if (XRE_IsParentProcess()) { + // Propagate notification to child processes + nsTArray contentProcesses; + dom::ContentParent::GetAll(contentProcesses); + for (auto* proc : contentProcesses) { + Unused << proc->SendUnblockUntrustedModulesThread(); + } + if (auto* proc = net::SocketProcessParent::GetSingleton()) { + Unused << proc->SendUnblockUntrustedModulesThread(); + } + if (auto* rddMgr = RDDProcessManager::Get()) { + if (auto* proc = rddMgr->GetRDDChild()) { + Unused << proc->SendUnblockUntrustedModulesThread(); + } + } + } + + return NS_OK; + } + MOZ_ASSERT_UNREACHABLE("Not reachable"); return NS_OK; @@ -180,6 +224,7 @@ void UntrustedModulesProcessor::RemoveObservers() { nsCOMPtr obsServ(services::GetObserverService()); obsServ->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID); obsServ->RemoveObserver(this, "xpcom-shutdown-threads"); + obsServ->RemoveObserver(this, "unblock-untrusted-modules-thread"); if (XRE_IsContentProcess()) { obsServ->RemoveObserver(this, "content-child-will-shutdown"); } @@ -204,7 +249,7 @@ void UntrustedModulesProcessor::ScheduleNonEmptyQueueProcessing( return; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -241,7 +286,7 @@ void UntrustedModulesProcessor::CancelScheduledProcessing( void UntrustedModulesProcessor::DispatchBackgroundProcessing() { MOZ_ASSERT(NS_IsMainThread()); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -254,7 +299,7 @@ void UntrustedModulesProcessor::DispatchBackgroundProcessing() { void UntrustedModulesProcessor::Enqueue( glue::EnhancedModuleLoadInfo&& aModLoadInfo) { - if (!mAllowProcessing) { + if (mStatus == Status::ShuttingDown) { return; } @@ -272,7 +317,7 @@ void UntrustedModulesProcessor::Enqueue( } void UntrustedModulesProcessor::Enqueue(ModuleLoadInfoVec&& aEvents) { - if (!mAllowProcessing) { + if (mStatus == Status::ShuttingDown) { return; } @@ -315,7 +360,7 @@ RefPtr UntrustedModulesProcessor::GetModulesTrust( ModulePaths&& aModPaths, bool aRunAtNormalPriority) { MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread()); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } @@ -403,7 +448,7 @@ UntrustedModulesProcessor::GetProcessedDataInternalChildProcess() { self = std::move(self), source, whenProcessed = std::move(whenProcessed)]() { MOZ_ASSERT(NS_IsMainThread()); - if (!self->mAllowProcessing) { + if (!self->IsReadyForBackgroundProcessing()) { // We can't do any more work, just reject all the things whenProcessed->Then( GetMainThreadSerialEventTarget(), source, @@ -442,13 +487,13 @@ UntrustedModulesProcessor::GetProcessedDataInternalChildProcess() { } void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueue() { - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } BackgroundPriorityRegion bgRgn; - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -502,7 +547,7 @@ void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueueChildProcess() { self = std::move(self), source, whenProcessed = std::move(whenProcessed)]() { MOZ_ASSERT(NS_IsMainThread()); - if (!self->mAllowProcessing) { + if (!self->IsReadyForBackgroundProcessing()) { // We can't do any more work, just no-op whenProcessed->Then( GetMainThreadSerialEventTarget(), source, @@ -514,7 +559,7 @@ void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueueChildProcess() { whenProcessed->Then( evtTarget, source, [self = std::move(self)](Maybe&& aResult) { - if (aResult.isNothing() || !self->mAllowProcessing) { + if (aResult.isNothing() || !self->IsReadyForBackgroundProcessing()) { // Nothing to do return; } @@ -565,9 +610,9 @@ UntrustedModulesProcessor::ExtractLoadingEventsToProcess(size_t aMaxLength) { return loadsToProcess; } -// This function contains multiple |mAllowProcessing| checks so that we can -// quickly bail out at the first sign of shutdown. This may be important when -// the current thread is running under background priority. +// This function contains multiple IsReadyForBackgroundProcessing() checks so +// that we can quickly bail out at the first sign of shutdown. This may be +// important when the current thread is running under background priority. void UntrustedModulesProcessor::ProcessModuleLoadQueue() { AssertRunningOnLazyIdleThread(); if (!XRE_IsParentProcess()) { @@ -577,7 +622,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() { LoadsVec loadsToProcess = ExtractLoadingEventsToProcess(UntrustedModulesData::kMaxEvents); - if (!mAllowProcessing || loadsToProcess.empty()) { + if (!IsReadyForBackgroundProcessing() || loadsToProcess.empty()) { return; } @@ -595,7 +640,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() { uint32_t trustTestFailures = 0; for (glue::EnhancedModuleLoadInfo& entry : loadsToProcess) { - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -608,7 +653,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() { continue; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -623,7 +668,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() { continue; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -639,14 +684,14 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() { mProcessedModuleLoads.mModules.LookupOrInsert( event.mModule->mResolvedNtName, event.mModule); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } Telemetry::ProcessedStack processedStack = stackProcessor.GetStackAndModules(backtrace); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -661,7 +706,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() { return; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -741,7 +786,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess( return GetModulesTrustPromise::CreateAndResolve(Nothing(), __func__); } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return GetModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } @@ -750,7 +795,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess( // Build a set of modules to be processed by the parent for (glue::EnhancedModuleLoadInfo& entry : loadsToProcess) { - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return GetModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } @@ -758,7 +803,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess( moduleNtPathSet.PutEntry(entry.mNtLoadInfo.mSectionName.AsString()); } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return GetModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } @@ -771,7 +816,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess( ModulePaths moduleNtPaths(std::move(moduleNtPathSet)); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return GetModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } @@ -787,7 +832,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess( RefPtr p( new GetModulesTrustPromise::Private(__func__)); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { p->Reject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); return p; } @@ -815,7 +860,7 @@ void UntrustedModulesProcessor::CompleteProcessing( MOZ_ASSERT(!XRE_IsParentProcess()); AssertRunningOnLazyIdleThread(); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -837,7 +882,7 @@ void UntrustedModulesProcessor::CompleteProcessing( return; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -850,7 +895,7 @@ void UntrustedModulesProcessor::CompleteProcessing( if (!modules.IsEmpty()) { for (auto&& item : loads) { - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -860,7 +905,7 @@ void UntrustedModulesProcessor::CompleteProcessing( continue; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -868,7 +913,7 @@ void UntrustedModulesProcessor::CompleteProcessing( std::move(item.mNtLoadInfo.mBacktrace); ProcessedModuleLoadEvent event(std::move(item), std::move(module)); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -879,7 +924,7 @@ void UntrustedModulesProcessor::CompleteProcessing( continue; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -890,7 +935,7 @@ void UntrustedModulesProcessor::CompleteProcessing( continue; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -909,7 +954,7 @@ void UntrustedModulesProcessor::CompleteProcessing( return; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return; } @@ -931,7 +976,7 @@ RefPtr UntrustedModulesProcessor::GetModulesTrustInternal( MOZ_ASSERT(XRE_IsParentProcess()); AssertRunningOnLazyIdleThread(); - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } @@ -965,7 +1010,7 @@ RefPtr UntrustedModulesProcessor::GetModulesTrustInternal( for (auto& resolvedNtPath : aModPaths.mModuleNtPaths.as()) { - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } @@ -982,7 +1027,7 @@ RefPtr UntrustedModulesProcessor::GetModulesTrustInternal( continue; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } @@ -993,7 +1038,7 @@ RefPtr UntrustedModulesProcessor::GetModulesTrustInternal( continue; } - if (!mAllowProcessing) { + if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject( NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); } diff --git a/toolkit/xre/dllservices/UntrustedModulesProcessor.h b/toolkit/xre/dllservices/UntrustedModulesProcessor.h index 427aacf8657a..a00d124194df 100644 --- a/toolkit/xre/dllservices/UntrustedModulesProcessor.h +++ b/toolkit/xre/dllservices/UntrustedModulesProcessor.h @@ -37,11 +37,16 @@ using GetModulesTrustIpcPromise = class UntrustedModulesProcessor final : public nsIObserver { public: - static RefPtr Create(); + static RefPtr Create( + bool aIsReadyForBackgroundProcessing); NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIOBSERVER + // Called to check if the parent process is ready when a child process + // is spanwed + bool IsReadyForBackgroundProcessing() const; + // Called by DLL Services to explicitly begin shutting down void Disable(); @@ -65,7 +70,7 @@ class UntrustedModulesProcessor final : public nsIObserver { private: ~UntrustedModulesProcessor() = default; - UntrustedModulesProcessor(); + explicit UntrustedModulesProcessor(bool aIsReadyForBackgroundProcessing); static bool IsSupportedProcessType(); @@ -141,8 +146,10 @@ class UntrustedModulesProcessor final : public nsIObserver { // This member must only be touched on mThread UntrustedModulesData mProcessedModuleLoads; + enum class Status { StartingUp, Allowed, ShuttingDown }; + // This member may be touched by any thread - Atomic mAllowProcessing; + Atomic mStatus; // Cache all module records, including ones trusted and ones loaded in // child processes, in the browser process to avoid evaluating the same diff --git a/toolkit/xre/dllservices/WinDllServices.cpp b/toolkit/xre/dllservices/WinDllServices.cpp index cc00227be351..b98a15252b55 100644 --- a/toolkit/xre/dllservices/WinDllServices.cpp +++ b/toolkit/xre/dllservices/WinDllServices.cpp @@ -59,10 +59,15 @@ DllServices* DllServices::Get() { DllServices::~DllServices() { DisableFull(); } -void DllServices::StartUntrustedModulesProcessor() { +void DllServices::StartUntrustedModulesProcessor(bool aIsStartingUp) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!mUntrustedModulesProcessor); - mUntrustedModulesProcessor = UntrustedModulesProcessor::Create(); + mUntrustedModulesProcessor = UntrustedModulesProcessor::Create(aIsStartingUp); +} + +bool DllServices::IsReadyForBackgroundProcessing() const { + return mUntrustedModulesProcessor && + mUntrustedModulesProcessor->IsReadyForBackgroundProcessing(); } RefPtr DllServices::GetUntrustedModulesData() { diff --git a/toolkit/xre/dllservices/WinDllServices.h b/toolkit/xre/dllservices/WinDllServices.h index e484be4151d8..a5d4f9b36337 100644 --- a/toolkit/xre/dllservices/WinDllServices.h +++ b/toolkit/xre/dllservices/WinDllServices.h @@ -34,7 +34,8 @@ class DllServices final : public glue::DllServices { static const char* kTopicDllLoadedMainThread; static const char* kTopicDllLoadedNonMainThread; - void StartUntrustedModulesProcessor(); + void StartUntrustedModulesProcessor(bool aIsReadyForBackgroundProcessing); + bool IsReadyForBackgroundProcessing() const; RefPtr GetUntrustedModulesData(); diff --git a/toolkit/xre/dllservices/tests/gtest/TestUntrustedModules.cpp b/toolkit/xre/dllservices/tests/gtest/TestUntrustedModules.cpp index f874c753cf64..f308270f80c4 100644 --- a/toolkit/xre/dllservices/tests/gtest/TestUntrustedModules.cpp +++ b/toolkit/xre/dllservices/tests/gtest/TestUntrustedModules.cpp @@ -353,7 +353,7 @@ BOOL CALLBACK UntrustedModulesFixture::InitialModuleLoadOnce(PINIT_ONCE, void*, } RefPtr dllSvc(DllServices::Get()); - dllSvc->StartUntrustedModulesProcessor(); + dllSvc->StartUntrustedModulesProcessor(true); for (int i = 0; i < kLoadCountAfterDllServices; ++i) { for (const auto& mod : kTestModules) { diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index b65ffa1133ff..a7eb8622507d 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -5277,7 +5277,7 @@ nsresult XREMain::XRE_mainRun() { #if defined(XP_WIN) RefPtr dllServices(mozilla::DllServices::Get()); - dllServices->StartUntrustedModulesProcessor(); + dllServices->StartUntrustedModulesProcessor(false); auto dllServicesDisable = MakeScopeExit([&dllServices]() { dllServices->DisableFull(); });