/* -*- 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/. */
/* static */ bool UntrustedModulesProcessor::IsSupportedProcessType() { switch (XRE_GetProcessType()) { case GeckoProcessType_Default: case GeckoProcessType_Content: case GeckoProcessType_Socket: return Telemetry::CanRecordReleaseData(); case GeckoProcessType_RDD: case GeckoProcessType_Utility: case GeckoProcessType_GMPlugin: // For GMPlugin, RDD and Utility process, we check the telemetry settings // in RDDChild::Init() / UtilityProcessChild::Init() / GMPChild::Init() // running in the browser process because CanRecordReleaseData() always // returns false here. returntrue; default: returnfalse;
}
}
void UntrustedModulesProcessor::ScheduleNonEmptyQueueProcessing( const MutexAutoLock& aProofOfLock) { // In case something tried to load a DLL during shutdown if (!mThread) { return;
}
#ifdefined(ENABLE_TESTS) // Don't bother scheduling background processing in short-lived xpcshell // processes; it makes the test suites take too long. if (MOZ_UNLIKELY(mozilla::EnvHasValue("XPCSHELL_TEST_PROFILE_DIR"))) { return;
} #endif// defined(ENABLE_TESTS)
if (mIdleRunnable) { return;
}
if (!IsReadyForBackgroundProcessing()) { return;
}
// Schedule a runnable to trigger background processing once the main thread // has gone idle. We do it this way to ensure that we don't start doing a // bunch of processing during periods of heavy main thread activity.
nsCOMPtr<nsIRunnable> idleRunnable(NewCancelableRunnableMethod( "UntrustedModulesProcessor::DispatchBackgroundProcessing", this,
&UntrustedModulesProcessor::DispatchBackgroundProcessing));
if (NS_FAILED(NS_DispatchToMainThreadQueue(do_AddRef(idleRunnable),
EventQueuePriority::Idle))) { return;
}
// Clear any background priority in case background processing is running.
{
MutexAutoLock lock(mThreadHandleMutex);
BackgroundPriorityRegion::Clear(mThreadHandle);
}
if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
}
RefPtr<UntrustedModulesProcessor> self(this); auto run = [self = std::move(self), modPaths = std::move(aModPaths),
runNormal = aRunAtNormalPriority]() mutable { return self->GetModulesTrustInternal(std::move(modPaths), runNormal);
};
if (aRunAtNormalPriority) { // Clear any background priority in case background processing is running.
{
MutexAutoLock lock(mThreadHandleMutex);
BackgroundPriorityRegion::Clear(mThreadHandle);
}
// We always send |completionRoutine| on a trip through the main thread // due to some subtlety with |mThread| being a LazyIdleThread: we can only // Dispatch or Then to |mThread| from its creating thread, which is the // main thread. Hopefully we can get rid of this in the future and just // invoke whenProcessed->Then() directly.
nsresult rv = NS_DispatchToMainThread(
NS_NewRunnableFunction(__func__, std::move(completionRoutine)));
MOZ_ASSERT(NS_SUCCEEDED(rv)); if (NS_FAILED(rv)) {
p->Reject(rv, __func__);
}
return p;
}
void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueue() { if (!IsReadyForBackgroundProcessing()) { return;
}
BackgroundPriorityRegion bgRgn;
if (!IsReadyForBackgroundProcessing()) { return;
}
// We always send |completionRoutine| on a trip through the main thread // due to some subtlety with |mThread| being a LazyIdleThread: we can only // Dispatch or Then to |mThread| from its creating thread, which is the // main thread. Hopefully we can get rid of this in the future and just // invoke whenProcessed->Then() directly.
DebugOnly<nsresult> rv = NS_DispatchToMainThread(
NS_NewRunnableFunction(__func__, std::move(completionRoutine)));
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
// 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()) {
BackgroundProcessModuleLoadQueueChildProcess(); return;
}
for (UnprocessedModuleLoadInfoContainer* container : loadsToProcess) {
glue::EnhancedModuleLoadInfo& entry = container->mInfo;
if (!IsReadyForBackgroundProcessing()) { return;
}
RefPtr<ModuleRecord> module(GetOrAddModuleRecord(
modEval, entry.mNtLoadInfo.mSectionName.AsString())); if (!module) { // We failed to obtain trust information about the module. // Don't include test failures in the ping to avoid flooding it.
++trustTestFailures; continue;
}
if (!IsReadyForBackgroundProcessing()) { return;
}
if (!IsReadyForBackgroundProcessing()) { return;
}
Unused << processedStacks.emplaceBack(std::move(processedStack));
processedEvents.insertBack( new ProcessedModuleLoadEventContainer(std::move(event)));
}
if (processedStacks.empty() && processedEvents.isEmpty() &&
!sanitizationFailures && !trustTestFailures) { // Nothing to save return;
}
if (!IsReadyForBackgroundProcessing()) { return;
}
// Modules have been added to mProcessedModuleLoads.mModules // in the loop above. Passing an empty ModulesMap to AddNewLoads.
mProcessedModuleLoads.AddNewLoads(ModulesMap{}, std::move(processedEvents),
std::move(processedStacks)); if (maybeXulLoadDuration) {
MOZ_ASSERT(!mProcessedModuleLoads.mXULLoadDurationMS);
mProcessedModuleLoads.mXULLoadDurationMS = maybeXulLoadDuration;
}
switch (XRE_GetProcessType()) { case GeckoProcessType_Content: { return ::mozilla::SendGetModulesTrust(dom::ContentChild::GetSingleton(),
std::move(aModules), runNormal);
} case GeckoProcessType_RDD: { return ::mozilla::SendGetModulesTrust(RDDParent::GetSingleton(),
std::move(aModules), runNormal);
} case GeckoProcessType_Socket: { return ::mozilla::SendGetModulesTrust(
net::SocketProcessChild::GetSingleton(), std::move(aModules),
runNormal);
} case GeckoProcessType_Utility: { return ::mozilla::SendGetModulesTrust(
ipc::UtilityProcessChild::GetSingleton().get(), std::move(aModules),
runNormal);
} case GeckoProcessType_GMPlugin: { return ::mozilla::gmp::SendGetModulesTrust(std::move(aModules),
runNormal);
} default: {
MOZ_ASSERT_UNREACHABLE("Unsupported process type"); return GetModulesTrustIpcPromise::CreateAndReject(
ipc::ResponseRejectReason::SendError, __func__);
}
}
}
/** * This method works very similarly to ProcessModuleLoadQueue, with the * exception that a sandboxed child process does not have sufficient rights to * be able to evaluate a module's trustworthiness. Instead, we accumulate the * resolved paths for all of the modules in this batch and send them to the * parent to determine trustworthiness. * * The parent process returns a list of untrusted modules and invokes * CompleteProcessing to handle the remainder of the process. * * By doing it this way, we minimize the amount of data that needs to be sent * over IPC and avoid the need to process every load's metadata only * to throw most of it away (since most modules will be trusted).
*/
RefPtr<UntrustedModulesProcessor::GetModulesTrustPromise>
UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess(
UntrustedModulesProcessor::Priority aPriority) {
AssertRunningOnLazyIdleThread();
MOZ_ASSERT(!XRE_IsParentProcess());
UnprocessedModuleLoads loadsToProcess =
ExtractLoadingEventsToProcess(UntrustedModulesData::kMaxEvents); if (loadsToProcess.isEmpty()) { // Nothing to process return GetModulesTrustPromise::CreateAndResolve(Nothing(), __func__);
}
if (!IsReadyForBackgroundProcessing()) { return GetModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
}
// Build a set of modules to be processed by the parent for (UnprocessedModuleLoadInfoContainer* container : loadsToProcess) {
glue::EnhancedModuleLoadInfo& entry = container->mInfo;
if (!IsReadyForBackgroundProcessing()) { return GetModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
}
if (!IsReadyForBackgroundProcessing()) { return GetModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
}
MOZ_ASSERT(!moduleNtPathSet.IsEmpty()); if (moduleNtPathSet.IsEmpty()) { // Nothing to process return GetModulesTrustPromise::CreateAndResolve(Nothing(), __func__);
}
if (!IsReadyForBackgroundProcessing()) { return;
}
if (aModulesAndLoads.mModMapResult.isNothing()) { // No untrusted modules in this batch, nothing to save. return;
}
// This map only contains information about modules deemed to be untrusted, // plus xul.dll. Any module referenced by load requests that is *not* in the // map is deemed to be trusted.
ModulesMap& modules = aModulesAndLoads.mModMapResult.ref().mModules; const uint32_t& trustTestFailures =
aModulesAndLoads.mModMapResult.ref().mTrustTestFailures;
UnprocessedModuleLoads& loads = aModulesAndLoads.mLoads;
if (modules.IsEmpty() && !trustTestFailures) { // No data, nothing to save. return;
}
if (!IsReadyForBackgroundProcessing()) { return;
}
if (!IsReadyForBackgroundProcessing()) { return;
}
if (!event) { // We don't have a sanitized DLL path, so we cannot include this event // for privacy reasons.
++sanitizationFailures; continue;
}
if (!IsReadyForBackgroundProcessing()) { return;
}
if (event.IsXULLoad()) {
maybeXulLoadDuration = event.mLoadDurationMS; // We saved the XUL load duration, but it is still trusted, so we // continue. continue;
}
if (!IsReadyForBackgroundProcessing()) { return;
}
// The thread priority of this job should match the priority that the child // process is running with, as specified by |aRunAtNormalPriority|.
RefPtr<ModulesTrustPromise> UntrustedModulesProcessor::GetModulesTrustInternal(
ModulePaths&& aModPaths, bool aRunAtNormalPriority) {
MOZ_ASSERT(XRE_IsParentProcess());
AssertRunningOnLazyIdleThread();
if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
}
if (aRunAtNormalPriority) { return GetModulesTrustInternal(std::move(aModPaths));
}
// For each module in |aModPaths|, evaluate its trustworthiness and only send // ModuleRecords for untrusted modules back to the child process. We also save // XUL's ModuleRecord so that the child process may report XUL's load time.
RefPtr<ModulesTrustPromise> UntrustedModulesProcessor::GetModulesTrustInternal(
ModulePaths&& aModPaths) {
MOZ_ASSERT(XRE_IsParentProcess());
AssertRunningOnLazyIdleThread();
ModuleEvaluator modEval;
MOZ_ASSERT(!!modEval); if (!modEval) { return ModulesTrustPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
for (auto& resolvedNtPath :
aModPaths.mModuleNtPaths.as<ModulePaths::VecType>()) { if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
}
MOZ_ASSERT(!resolvedNtPath.IsEmpty()); if (resolvedNtPath.IsEmpty()) { continue;
}
RefPtr<ModuleRecord> module(GetOrAddModuleRecord(modEval, resolvedNtPath)); if (!module) { // We failed to obtain trust information.
++trustTestFailures; continue;
}
if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
}
if (module->IsTrusted() && !module->IsXUL()) { // If the module is trusted we exclude it from results, unless it's XUL. // (We save XUL so that the child process may report XUL's load time) continue;
}
if (!IsReadyForBackgroundProcessing()) { return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.