Commit a5fd60e1 authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

Calls to {console} require an access check for the provided arguments

This CL adds an access check for the arguments to all calls to
{console} like {console.log}. This is needed since the DevTools
protocol notificiation event does not contain the context in which
the {console.log} call occurred. Only the context of the argument.
When DevTools then reads properties for the preview of the argument,
it uses arguments context, instead of the calling context, potentially
leaking objects/exceptions into the calling context.

Bug: chromium:987502, chromium:986393
Change-Id: I6f7682f7bee94a28ac61994bad259bd003511c39
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1741664
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63122}
parent c6553cde
......@@ -47,6 +47,22 @@ void ConsoleCall(
CHECK(!isolate->has_scheduled_exception());
if (!isolate->console_delegate()) return;
HandleScope scope(isolate);
// Access check. The current context has to match the context of all
// arguments, otherwise the inspector might leak objects across contexts.
Handle<Context> context = handle(isolate->context(), isolate);
for (int i = 0; i < args.length(); ++i) {
Handle<Object> argument = args.at<Object>(i);
if (!argument->IsJSObject()) continue;
Handle<JSObject> argument_obj = Handle<JSObject>::cast(argument);
if (argument->IsAccessCheckNeeded(isolate) &&
!isolate->MayAccess(context, argument_obj)) {
isolate->ReportFailedAccessCheck(argument_obj);
return;
}
}
debug::ConsoleCallArguments wrapper(args);
Handle<Object> context_id_obj = JSObject::GetDataProperty(
args.target(), isolate->factory()->console_context_id_symbol());
......
......@@ -181,4 +181,46 @@ TEST_F(AccessRegressionTest,
ASSERT_EQ(getter_c2->native_context(), *Utils::OpenHandle(*context2));
}
namespace {
bool failed_access_check_callback_called;
class AccessCheckTestConsoleDelegate : public debug::ConsoleDelegate {
public:
void Log(const debug::ConsoleCallArguments& args,
const debug::ConsoleContext& context) {
FAIL();
}
};
} // namespace
// Ensure that {console.log} does an access check for its arguments.
TEST_F(AccessCheckTest, ConsoleLog) {
isolate()->SetFailedAccessCheckCallbackFunction(
[](v8::Local<v8::Object> host, v8::AccessType type,
v8::Local<v8::Value> data) {
failed_access_check_callback_called = true;
});
AccessCheckTestConsoleDelegate console{};
debug::SetConsoleDelegate(isolate(), &console);
Local<ObjectTemplate> object_template = ObjectTemplate::New(isolate());
object_template->SetAccessCheckCallback(AccessCheck);
Local<Context> context1 = Context::New(isolate(), nullptr);
Local<Context> context2 = Context::New(isolate(), nullptr);
Local<Object> object1 =
object_template->NewInstance(context1).ToLocalChecked();
EXPECT_TRUE(context2->Global()
->Set(context2, v8_str("object_from_context1"), object1)
.IsJust());
Context::Scope context_scope(context2);
failed_access_check_callback_called = false;
CompileRun(isolate(), "console.log(object_from_context1);").ToLocalChecked();
ASSERT_TRUE(failed_access_check_callback_called);
}
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment