1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/bindings/callback_interface_base.h"
#include "third_party/blink/renderer/platform/bindings/binding_security_for_platform.h"
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h"
namespace blink {
CallbackInterfaceBase::CallbackInterfaceBase(
v8::Local<v8::Object> callback_object,
SingleOperationOrNot single_op_or_not) {
DCHECK(!callback_object.IsEmpty());
v8::Isolate* isolate = callback_object->GetIsolate();
callback_object_.Reset(isolate, callback_object);
incumbent_script_state_ =
ScriptState::From(isolate, isolate->GetIncumbentContext());
is_callback_object_callable_ =
(single_op_or_not == kSingleOperation) && callback_object->IsCallable();
// Set |callback_relevant_script_state_| iff the creation context and the
// incumbent context are the same origin-domain. Otherwise, leave it as
// nullptr.
if (is_callback_object_callable_) {
// If the callback object is a function, it's guaranteed to be the same
// origin at least, and very likely to be the same origin-domain. Even if
// it's not the same origin-domain, it's already been possible for the
// callsite to run arbitrary script in the context. No need to protect it.
// This is an optimization faster than ShouldAllowAccessToV8Context below.
callback_relevant_script_state_ =
ScriptState::ForRelevantRealm(isolate, callback_object);
} else {
v8::MaybeLocal<v8::Context> creation_context =
callback_object->GetCreationContext();
if (BindingSecurityForPlatform::ShouldAllowAccessToV8Context(
incumbent_script_state_->GetContext(), creation_context)) {
callback_relevant_script_state_ =
ScriptState::From(isolate, creation_context.ToLocalChecked());
}
}
}
void CallbackInterfaceBase::Trace(Visitor* visitor) const {
visitor->Trace(callback_object_);
visitor->Trace(callback_relevant_script_state_);
visitor->Trace(incumbent_script_state_);
}
ScriptState* CallbackInterfaceBase::CallbackRelevantScriptStateOrReportError(
const char* interface_name,
const char* operation_name) {
if (callback_relevant_script_state_)
return callback_relevant_script_state_.Get();
// Report a SecurityError due to a cross origin callback object.
ScriptState::Scope incumbent_scope(incumbent_script_state_);
v8::TryCatch try_catch(GetIsolate());
try_catch.SetVerbose(true);
ExceptionState exception_state(GetIsolate());
exception_state.ThrowSecurityError(ExceptionMessages::FailedToExecute(
operation_name, interface_name,
"An invocation of the provided callback failed due to cross origin "
"access."));
return nullptr;
}
ScriptState* CallbackInterfaceBase::CallbackRelevantScriptStateOrThrowException(
const char* interface_name,
const char* operation_name) {
if (callback_relevant_script_state_)
return callback_relevant_script_state_.Get();
// Throw a SecurityError due to a cross origin callback object.
ScriptState::Scope incumbent_scope(incumbent_script_state_);
ExceptionState exception_state(GetIsolate());
exception_state.ThrowSecurityError(ExceptionMessages::FailedToExecute(
operation_name, interface_name,
"An invocation of the provided callback failed due to cross origin "
"access."));
return nullptr;
}
} // namespace blink
|