Files
sousa-gecko/js/xpconnect/loader/ScriptCacheActors.cpp
T
Nika Layzell ec9837a9f1 Bug 2049046 - Add a unified mechanism for determining when a content process becomes untrusted, r=dom-core-reviewers,necko-reviewers,dom-worker-reviewers,valentin,edenchuang,mccr8
The ScriptCache has a simple system for determining when the process is
untrusted to ensure that script cache writes are finished before
untrusted content is loaded in the content process.

This expands this system to more explicitly cover multiple potential
causes of becoming untrusted, and exposes a threadsafe flag which can be
checked to see if the process could have started loading untrusted
content.

Much like the existing ScriptCache threshold, this is defined very
conservatively, such that we cannot have loaded untrusted content before
the threshold.

Differential Revision: https://phabricator.services.mozilla.com/D307885
2026-06-25 16:21:57 +00:00

102 lines
3.0 KiB
C++

/* 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 "mozilla/ScriptPreloader.h"
#include "ScriptPreloader-inl.h"
#include "mozilla/loader/ScriptCacheActors.h"
#include "mozilla/dom/ContentParent.h"
namespace mozilla {
namespace loader {
void ScriptCacheChild::Init(const Maybe<FileDescriptor>& cacheFile,
bool wantCacheData) {
AssertIsOnMainThread();
mWantCacheData = wantCacheData;
auto& cache = ScriptPreloader::GetChildSingleton();
(void)cache.InitCache(cacheFile, this);
if (!wantCacheData) {
// If the parent process isn't expecting any cache data from us, we're
// done.
Send__delete__(this, AutoTArray<ScriptData, 0>());
}
}
// Finalize the script cache for the content process, and send back data about
// any scripts executed up to this point.
void ScriptCacheChild::SendScriptsAndFinalize(
ScriptPreloader::ScriptHash& scripts) {
MOZ_ASSERT(mWantCacheData);
auto matcher = ScriptPreloader::Match<ScriptPreloader::ScriptStatus::Saved>();
JS::FrontendContext* fc = JS::NewFrontendContext();
if (!fc) {
return;
}
nsTArray<ScriptData> dataArray;
for (auto& script : IterHash(scripts, matcher)) {
if (!script->mSize && !script->XDREncode(fc)) {
continue;
}
auto data = dataArray.AppendElement();
data->url() = script->mURL;
data->cachePath() = script->mCachePath;
data->loadTime() = script->mLoadTime;
if (script->HasBuffer()) {
auto& xdrData = script->Buffer();
data->xdrData().AppendElements(xdrData.begin(), xdrData.length());
script->FreeData();
}
}
JS::DestroyFrontendContext(fc);
Send__delete__(this, dataArray);
}
void ScriptCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
auto& cache = ScriptPreloader::GetChildSingleton();
cache.mChildActor = nullptr;
}
IPCResult ScriptCacheParent::Recv__delete__(nsTArray<ScriptData>&& scripts) {
if (!mWantCacheData && scripts.Length()) {
return IPC_FAIL(this, "UnexpectedScriptData");
}
// We don't want any more data from the process at this point.
mWantCacheData = false;
// Merge the child's script data with the parent's.
auto parent = static_cast<dom::ContentParent*>(Manager());
auto processType =
ScriptPreloader::GetChildProcessType(parent->GetRemoteType());
if (parent->IsUntrusted()) {
return IPC_FAIL(this,
"Expected script data before process became untrusted");
}
auto& cache = ScriptPreloader::GetChildSingleton();
for (auto& script : scripts) {
cache.NoteStencil(script.url(), script.cachePath(), processType,
std::move(script.xdrData()), script.loadTime());
}
cache.NoteReceivedAllChildStencilsForProcess(processType);
return IPC_OK();
}
void ScriptCacheParent::ActorDestroy(ActorDestroyReason aWhy) {}
} // namespace loader
} // namespace mozilla