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
102 lines
3.0 KiB
C++
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
|