Bug 1609990 - AgentCluster comparison in MessagePort and BroadcastChannel - part 3 - CloneDataPolicy, r=smaug,sfink,lth

Differential Revision: https://phabricator.services.mozilla.com/D60485

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2020-01-24 15:25:24 +00:00
Родитель b1846b3da4
Коммит ac6024f408
19 изменённых файлов: 115 добавлений и 70 удалений

Просмотреть файл

@ -176,7 +176,7 @@ PostMessageEvent::Run() {
if (mCallerAgentClusterId.isSome() && targetWindow->GetDocGroup() &&
targetWindow->GetDocGroup()->AgentClusterId().Equals(
mCallerAgentClusterId.ref())) {
cloneDataPolicy.allowSharedMemory();
cloneDataPolicy.allowIntraClusterClonableSharedObjects();
}
StructuredCloneHolder* holder;

Просмотреть файл

@ -45,14 +45,15 @@ namespace dom {
namespace {
JSObject* StructuredCloneCallbacksRead(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag, uint32_t aIndex,
void* aClosure) {
JSObject* StructuredCloneCallbacksRead(
JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, uint32_t aIndex,
void* aClosure) {
StructuredCloneHolderBase* holder =
static_cast<StructuredCloneHolderBase*>(aClosure);
MOZ_ASSERT(holder);
return holder->CustomReadHandler(aCx, aReader, aTag, aIndex);
return holder->CustomReadHandler(aCx, aReader, aCloneDataPolicy, aTag,
aIndex);
}
bool StructuredCloneCallbacksWrite(JSContext* aCx,
@ -311,25 +312,23 @@ void StructuredCloneHolder::ReadFromBuffer(nsIGlobalObject* aGlobal,
JSContext* aCx,
JSStructuredCloneData& aBuffer,
JS::MutableHandle<JS::Value> aValue,
JS::CloneDataPolicy aCloneDataPolicy,
ErrorResult& aRv) {
ReadFromBuffer(aGlobal, aCx, aBuffer, JS_STRUCTURED_CLONE_VERSION, aValue,
aRv);
aCloneDataPolicy, aRv);
}
void StructuredCloneHolder::ReadFromBuffer(nsIGlobalObject* aGlobal,
JSContext* aCx,
JSStructuredCloneData& aBuffer,
uint32_t aAlgorithmVersion,
JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv) {
void StructuredCloneHolder::ReadFromBuffer(
nsIGlobalObject* aGlobal, JSContext* aCx, JSStructuredCloneData& aBuffer,
uint32_t aAlgorithmVersion, JS::MutableHandle<JS::Value> aValue,
JS::CloneDataPolicy aCloneDataPolicy, ErrorResult& aRv) {
MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
mozilla::AutoRestore<nsIGlobalObject*> guard(mGlobal);
mGlobal = aGlobal;
if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion, CloneScope(),
aValue, JS::CloneDataPolicy(), &sCallbacks,
this)) {
aValue, aCloneDataPolicy, &sCallbacks, this)) {
JS_ClearPendingException(aCx);
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
@ -817,7 +816,7 @@ bool WriteWasmModule(JSStructuredCloneWriter* aWriter,
StructuredCloneHolder::StructuredCloneScope::SameProcess);
// We store the position of the wasmModule in the array as index.
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM,
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM_MODULE,
aHolder->WasmModules().Length())) {
aHolder->WasmModules().AppendElement(aWasmModule);
return true;
@ -869,7 +868,8 @@ bool WriteInputStream(JSStructuredCloneWriter* aWriter,
} // anonymous namespace
JSObject* StructuredCloneHolder::CustomReadHandler(
JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
uint32_t aIndex) {
MOZ_ASSERT(mSupportsCloning);
@ -906,8 +906,9 @@ JSObject* StructuredCloneHolder::CustomReadHandler(
return StructuredCloneBlob::ReadStructuredClone(aCx, aReader, this);
}
if (aTag == SCTAG_DOM_WASM &&
CloneScope() == StructuredCloneScope::SameProcess) {
if (aTag == SCTAG_DOM_WASM_MODULE &&
CloneScope() == StructuredCloneScope::SameProcess &&
aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
return ReadWasmModule(aCx, aIndex, this);
}

Просмотреть файл

@ -51,9 +51,10 @@ class StructuredCloneHolderBase {
// These methods should be implemented in order to clone data.
// Read more documentation in js/public/StructuredClone.h.
virtual JSObject* CustomReadHandler(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag, uint32_t aIndex) = 0;
virtual JSObject* CustomReadHandler(
JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
uint32_t aIndex) = 0;
virtual bool CustomWriteHandler(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
@ -238,9 +239,10 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
// Implementations of the virtual methods to allow cloning of objects which
// JS engine itself doesn't clone.
virtual JSObject* CustomReadHandler(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag, uint32_t aIndex) override;
virtual JSObject* CustomReadHandler(
JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
uint32_t aIndex) override;
virtual bool CustomWriteHandler(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
@ -292,12 +294,14 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
// and/or the PortIdentifiers.
void ReadFromBuffer(nsIGlobalObject* aGlobal, JSContext* aCx,
JSStructuredCloneData& aBuffer,
JS::MutableHandle<JS::Value> aValue, ErrorResult& aRv);
JS::MutableHandle<JS::Value> aValue,
JS::CloneDataPolicy aCloneDataPolicy, ErrorResult& aRv);
void ReadFromBuffer(nsIGlobalObject* aGlobal, JSContext* aCx,
JSStructuredCloneData& aBuffer,
uint32_t aAlgorithmVersion,
JS::MutableHandle<JS::Value> aValue, ErrorResult& aRv);
JS::MutableHandle<JS::Value> aValue,
JS::CloneDataPolicy aCloneDataPolicy, ErrorResult& aRv);
void SameProcessScopeRequired(bool* aSameProcessScopeRequired);

Просмотреть файл

@ -39,7 +39,7 @@ enum StructuredCloneTags {
SCTAG_DOM_FILE,
// IMPORTANT: Don't change the order of these enum values. You could break
// IDB.
SCTAG_DOM_WASM,
SCTAG_DOM_WASM_MODULE,
// IMPORTANT: Don't change the order of these enum values. You could break
// IDB.

Просмотреть файл

@ -5948,7 +5948,7 @@ void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
JS::CloneDataPolicy clonePolicy;
if (GetDocGroup() && callerInnerWindow &&
callerInnerWindow->IsSharedMemoryAllowed()) {
clonePolicy.allowSharedMemory();
clonePolicy.allowIntraClusterClonableSharedObjects();
}
event->Write(aCx, aMessage, aTransfer, clonePolicy, aError);
if (NS_WARN_IF(aError.Failed())) {

Просмотреть файл

@ -284,6 +284,7 @@ class ConsoleRunnable : public StructuredCloneHolderBase {
protected:
JSObject* CustomReadHandler(JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy,
uint32_t aTag, uint32_t aIndex) override {
AssertIsOnMainThread();

Просмотреть файл

@ -555,7 +555,7 @@ bool ReadBlobOrFile(JSStructuredCloneReader* aReader, uint32_t aTag,
}
bool ReadWasmModule(JSStructuredCloneReader* aReader, WasmModuleData* aRetval) {
static_assert(SCTAG_DOM_WASM == 0xFFFF8006, "Update me!");
static_assert(SCTAG_DOM_WASM_MODULE == 0xFFFF8006, "Update me!");
MOZ_ASSERT(aReader && aRetval);
uint32_t bytecodeIndex;
@ -735,28 +735,28 @@ class ValueDeserializationHelper {
}
};
JSObject* CommonStructuredCloneReadCallback(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag, uint32_t aData,
void* aClosure) {
JSObject* CommonStructuredCloneReadCallback(
JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, uint32_t aData,
void* aClosure) {
// We need to statically assert that our tag values are what we expect
// so that if people accidentally change them they notice.
static_assert(SCTAG_DOM_BLOB == 0xffff8001 &&
SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xffff8002 &&
SCTAG_DOM_MUTABLEFILE == 0xffff8004 &&
SCTAG_DOM_FILE == 0xffff8005 &&
SCTAG_DOM_WASM == 0xffff8006,
SCTAG_DOM_WASM_MODULE == 0xffff8006,
"You changed our structured clone tag values and just ate "
"everyone's IndexedDB data. I hope you are happy.");
if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
aTag == SCTAG_DOM_BLOB || aTag == SCTAG_DOM_FILE ||
aTag == SCTAG_DOM_MUTABLEFILE || aTag == SCTAG_DOM_WASM) {
aTag == SCTAG_DOM_MUTABLEFILE || aTag == SCTAG_DOM_WASM_MODULE) {
auto* const cloneReadInfo = static_cast<StructuredCloneReadInfo*>(aClosure);
JS::Rooted<JSObject*> result(aCx);
if (aTag == SCTAG_DOM_WASM) {
if (aTag == SCTAG_DOM_WASM_MODULE) {
WasmModuleData data(aData);
if (NS_WARN_IF(!ReadWasmModule(aReader, &data))) {
return nullptr;
@ -819,10 +819,10 @@ JSObject* CommonStructuredCloneReadCallback(JSContext* aCx,
aTag);
}
JSObject* CopyingStructuredCloneReadCallback(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag, uint32_t aData,
void* aClosure) {
JSObject* CopyingStructuredCloneReadCallback(
JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, uint32_t aData,
void* aClosure) {
MOZ_ASSERT(aTag != SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE);
if (aTag == SCTAG_DOM_BLOB || aTag == SCTAG_DOM_FILE ||

Просмотреть файл

@ -58,7 +58,27 @@ void SharedMessageBody::Read(JSContext* aCx,
MOZ_ASSERT(aRefMessageBodyService);
if (mCloneData) {
return mCloneData->Read(aCx, aValue, aRv);
// Use a default cloneDataPolicy here, because SharedArrayBuffers and WASM
// are not supported.
return mCloneData->Read(aCx, aValue, JS::CloneDataPolicy(), aRv);
}
JS::CloneDataPolicy cloneDataPolicy;
// Clones within the same agent cluster are allowed to use shared array
// buffers and WASM modules.
if (mAgentClusterId.isSome()) {
nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
MOZ_ASSERT(global);
Maybe<ClientInfo> clientInfo = global->GetClientInfo();
if (clientInfo) {
Maybe<nsID> agentClusterId = clientInfo->AgentClusterId();
if (agentClusterId.isSome() &&
mAgentClusterId.value().Equals(agentClusterId.value())) {
cloneDataPolicy.allowIntraClusterClonableSharedObjects();
}
}
}
MOZ_ASSERT(!mRefData);
@ -76,7 +96,7 @@ void SharedMessageBody::Read(JSContext* aCx,
return;
}
mRefData->CloneData()->Read(aCx, aValue, aRv);
mRefData->CloneData()->Read(aCx, aValue, cloneDataPolicy, aRv);
}
bool SharedMessageBody::TakeTransferredPortsAsSequence(

Просмотреть файл

@ -102,12 +102,19 @@ bool StructuredCloneData::Copy(const StructuredCloneData& aData) {
void StructuredCloneData::Read(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv) {
Read(aCx, aValue, JS::CloneDataPolicy(), aRv);
}
void StructuredCloneData::Read(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue,
JS::CloneDataPolicy aCloneDataPolicy,
ErrorResult& aRv) {
MOZ_ASSERT(mInitialized);
nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
MOZ_ASSERT(global);
ReadFromBuffer(global, aCx, Data(), aValue, aRv);
ReadFromBuffer(global, aCx, Data(), aValue, aCloneDataPolicy, aRv);
}
void StructuredCloneData::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,

Просмотреть файл

@ -176,6 +176,9 @@ class StructuredCloneData : public StructuredCloneHolder {
void Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv);
void Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
JS::CloneDataPolicy aCloneDataPolicy, ErrorResult& aRv);
void Write(JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv);
void Write(JSContext* aCx, JS::Handle<JS::Value> aValue,

Просмотреть файл

@ -772,7 +772,8 @@ void PromiseWorkerProxy::CleanUp() {
}
JSObject* PromiseWorkerProxy::CustomReadHandler(
JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
uint32_t aIndex) {
if (NS_WARN_IF(!mCallbacks)) {
return nullptr;

Просмотреть файл

@ -157,6 +157,7 @@ class PromiseWorkerProxy : public PromiseNativeHandler,
// StructuredCloneHolderBase
JSObject* CustomReadHandler(JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy,
uint32_t aTag, uint32_t aIndex) override;
bool CustomWriteHandler(JSContext* aCx, JSStructuredCloneWriter* aWriter,

Просмотреть файл

@ -66,7 +66,7 @@ bool MessageEventRunnable::DispatchDOMEvent(JSContext* aCx,
parent->GetClientInfo()->AgentClusterId().isSome() &&
parent->GetClientInfo()->AgentClusterId()->Equals(
aWorkerPrivate->AgentClusterId())) {
cloneDataPolicy.allowSharedMemory();
cloneDataPolicy.allowIntraClusterClonableSharedObjects();
}
Read(parent, aCx, &messageData, cloneDataPolicy, rv);

Просмотреть файл

@ -106,12 +106,12 @@ void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
if (NS_IsMainThread()) {
nsGlobalWindowInner* win = nsContentUtils::CallerInnerWindow();
if (win && win->IsSharedMemoryAllowed()) {
clonePolicy.allowSharedMemory();
clonePolicy.allowIntraClusterClonableSharedObjects();
}
} else {
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
if (worker && worker->IsSharedMemoryAllowed()) {
clonePolicy.allowSharedMemory();
clonePolicy.allowIntraClusterClonableSharedObjects();
}
}

Просмотреть файл

@ -4033,7 +4033,7 @@ void WorkerPrivate::PostMessageToParent(
JS::CloneDataPolicy clonePolicy;
if (IsSharedMemoryAllowed()) {
clonePolicy.allowSharedMemory();
clonePolicy.allowIntraClusterClonableSharedObjects();
}
runnable->Write(aCx, aMessage, transferable, clonePolicy, aRv);

Просмотреть файл

@ -205,24 +205,29 @@ enum TransferableOwnership {
};
class CloneDataPolicy {
bool sharedArrayBuffer_;
bool allowIntraClusterClonableSharedObjects_;
public:
// The default is to deny all policy-controlled aspects.
CloneDataPolicy() : sharedArrayBuffer_(false) {}
CloneDataPolicy() : allowIntraClusterClonableSharedObjects_(false) {}
// In the JS engine, SharedArrayBuffers can only be cloned intra-process
// because the shared memory areas are allocated in process-private memory.
// Clients should therefore deny SharedArrayBuffers when cloning data that
// are to be transmitted inter-process.
// In the JS engine, SharedArrayBuffers and WASM modules can only be cloned
// intra-process because the shared memory areas are allocated in
// process-private memory. Clients should therefore deny SharedArrayBuffers
// when cloning data that are to be transmitted inter-process.
//
// Clients should also deny SharedArrayBuffers when cloning data that are to
// be transmitted intra-process if policy needs dictate such denial.
// Clients should also deny SharedArrayBuffers and WASM modules when cloning
// data that are to be transmitted intra-process if policy needs dictate such
// denial.
void allowSharedMemory() { sharedArrayBuffer_ = true; }
void allowIntraClusterClonableSharedObjects() {
allowIntraClusterClonableSharedObjects_ = true;
}
bool isSharedArrayBufferAllowed() const { return sharedArrayBuffer_; }
bool areIntraClusterClonableSharedObjectsAllowed() const {
return allowIntraClusterClonableSharedObjects_;
}
};
} /* namespace JS */
@ -236,10 +241,10 @@ class CloneDataPolicy {
* from the reader r. closure is any value passed to the JS_ReadStructuredClone
* function. Return the new object on success, nullptr on error/exception.
*/
typedef JSObject* (*ReadStructuredCloneOp)(JSContext* cx,
JSStructuredCloneReader* r,
uint32_t tag, uint32_t data,
void* closure);
typedef JSObject* (*ReadStructuredCloneOp)(
JSContext* cx, JSStructuredCloneReader* r,
const JS::CloneDataPolicy& cloneDataPolicy, uint32_t tag, uint32_t data,
void* closure);
/**
* Structured data serialization hook. The engine can write primitive values,

Просмотреть файл

@ -3420,7 +3420,7 @@ bool js::testingFunc_serialize(JSContext* cx, unsigned argc, Value* vp) {
}
if (StringEqualsLiteral(poli, "allow")) {
policy.allowSharedMemory();
policy.allowIntraClusterClonableSharedObjects();
} else if (StringEqualsLiteral(poli, "deny")) {
// default
} else {
@ -3500,7 +3500,7 @@ static bool Deserialize(JSContext* cx, unsigned argc, Value* vp) {
}
if (StringEqualsLiteral(poli, "allow")) {
policy.allowSharedMemory();
policy.allowIntraClusterClonableSharedObjects();
} else if (StringEqualsLiteral(poli, "deny")) {
// default
} else {

Просмотреть файл

@ -1259,7 +1259,7 @@ bool JSStructuredCloneWriter::writeArrayBuffer(HandleObject obj) {
bool JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj) {
MOZ_ASSERT(obj->canUnwrapAs<SharedArrayBufferObject>());
if (!cloneDataPolicy.isSharedArrayBufferAllowed()) {
if (!cloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
auto errorMsg =
context()->realm()->creationOptions().getCoopAndCoepEnabled()
? JSMSG_SC_NOT_CLONABLE_WITH_COOP_COEP
@ -1305,7 +1305,7 @@ bool JSStructuredCloneWriter::writeSharedWasmMemory(HandleObject obj) {
MOZ_ASSERT(obj->canUnwrapAs<WasmMemoryObject>());
// Check the policy here so that we can report a sane error.
if (!cloneDataPolicy.isSharedArrayBufferAllowed()) {
if (!cloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
auto errorMsg =
context()->realm()->creationOptions().getCoopAndCoepEnabled()
? JSMSG_SC_NOT_CLONABLE_WITH_COOP_COEP
@ -2234,7 +2234,7 @@ bool JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes,
}
bool JSStructuredCloneReader::readSharedArrayBuffer(MutableHandleValue vp) {
if (!cloneDataPolicy.isSharedArrayBufferAllowed()) {
if (!cloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
auto errorMsg =
context()->realm()->creationOptions().getCoopAndCoepEnabled()
? JSMSG_SC_NOT_CLONABLE_WITH_COOP_COEP
@ -2298,7 +2298,7 @@ bool JSStructuredCloneReader::readSharedWasmMemory(uint32_t nbytes,
return false;
}
if (!cloneDataPolicy.isSharedArrayBufferAllowed()) {
if (!cloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
auto errorMsg =
context()->realm()->creationOptions().getCoopAndCoepEnabled()
? JSMSG_SC_NOT_CLONABLE_WITH_COOP_COEP
@ -2643,7 +2643,8 @@ bool JSStructuredCloneReader::startRead(MutableHandleValue vp) {
if (!allObjs.append(dummy)) {
return false;
}
JSObject* obj = callbacks->read(context(), this, tag, data, closure);
JSObject* obj =
callbacks->read(context(), this, cloneDataPolicy, tag, data, closure);
if (!obj) {
return false;
}

Просмотреть файл

@ -59,6 +59,7 @@ class MOZ_STACK_CLASS StackScopedCloneData : public StructuredCloneHolderBase {
~StackScopedCloneData() { Clear(); }
JSObject* CustomReadHandler(JSContext* aCx, JSStructuredCloneReader* aReader,
const JS::CloneDataPolicy& aCloneDataPolicy,
uint32_t aTag, uint32_t aData) override {
if (aTag == SCTAG_REFLECTOR) {
MOZ_ASSERT(!aData);