Commit f510c66b authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

inspector: Add flag to Runtime.evaluate() for unsafe eval

evaluate() bypassed CSP for unsafe-eval by default. This is a useful
option for debugging clients, but is not always what we want.

e.g. in the devtools console we want to match the page's CSP settings
to make debugging CSP issues on the page easier.

Add a toggle that keeps the current behavior by default.

Bug: chromium:1084558
Change-Id: Ia01142d5be00f8ef5f65e5eeba17549efc6f9120
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2250245
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68432}
parent c6642b51
......@@ -1370,6 +1370,11 @@ domain Runtime
# Note that `let` variables can only be re-declared if they originate from
# `replMode` themselves.
experimental optional boolean replMode
# The Content Security Policy (CSP) for the target might block 'unsafe-eval'
# which includes eval(), Function(), setTimeout() and setInterval()
# when called with non-callable arguments. This flag bypasses CSP for this
# evaluation and allows unsafe-eval. Defaults to true.
experimental optional boolean allowUnsafeEvalBlockedByCSP
returns
# Evaluation result.
RemoteObject result
......
......@@ -237,6 +237,7 @@ void V8RuntimeAgentImpl::evaluate(
Maybe<bool> generatePreview, Maybe<bool> userGesture,
Maybe<bool> maybeAwaitPromise, Maybe<bool> throwOnSideEffect,
Maybe<double> timeout, Maybe<bool> disableBreaks, Maybe<bool> maybeReplMode,
Maybe<bool> allowUnsafeEvalBlockedByCSP,
std::unique_ptr<EvaluateCallback> callback) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
"EvaluateScript");
......@@ -262,8 +263,10 @@ void V8RuntimeAgentImpl::evaluate(
const bool replMode = maybeReplMode.fromMaybe(false);
// Temporarily enable allow evals for inspector.
scope.allowCodeGenerationFromStrings();
if (allowUnsafeEvalBlockedByCSP.fromMaybe(true)) {
// Temporarily enable allow evals for inspector.
scope.allowCodeGenerationFromStrings();
}
v8::MaybeLocal<v8::Value> maybeResultValue;
{
V8InspectorImpl::EvaluateScope evaluateScope(scope);
......
......@@ -68,7 +68,7 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend {
Maybe<bool> generatePreview, Maybe<bool> userGesture,
Maybe<bool> awaitPromise, Maybe<bool> throwOnSideEffect,
Maybe<double> timeout, Maybe<bool> disableBreaks,
Maybe<bool> replMode,
Maybe<bool> replMode, Maybe<bool> allowUnsafeEvalBlockedByCSP,
std::unique_ptr<EvaluateCallback>) override;
void awaitPromise(const String16& promiseObjectId, Maybe<bool> returnByValue,
Maybe<bool> generatePreview,
......
......@@ -31,6 +31,104 @@ Running test: testEvaluatePaused
}
}
Running test: testEvaluateUnsafeEval
{
id : <messageId>
result : {
result : {
description : 2
type : number
value : 2
}
}
}
{
id : <messageId>
result : {
result : {
description : 2
type : number
value : 2
}
}
}
Running test: testEvaluateUnsafeEvalDisableBypass
{
id : <messageId>
result : {
exceptionDetails : {
columnNumber : 0
exception : {
className : EvalError
description : EvalError: Code generation from strings disallowed for this context at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 0
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 0
functionName :
lineNumber : 0
scriptId : <scriptId>
url :
}
]
}
text : Uncaught
}
result : {
className : EvalError
description : EvalError: Code generation from strings disallowed for this context at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
}
}
{
id : <messageId>
result : {
exceptionDetails : {
columnNumber : 0
exception : {
className : EvalError
description : EvalError: Code generation from strings disallowed for this context at new Function (<anonymous>) at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 0
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 0
functionName :
lineNumber : 0
scriptId : <scriptId>
url :
}
]
}
text : Uncaught
}
result : {
className : EvalError
description : EvalError: Code generation from strings disallowed for this context at new Function (<anonymous>) at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
}
}
Running test: testCallFunctionOn
{
id : <messageId>
......
......@@ -36,6 +36,24 @@ InspectorTest.runAsyncTestSuite([
await Protocol.Debugger.resume();
},
async function testEvaluateUnsafeEval() {
contextGroup.addScript(`inspector.setAllowCodeGenerationFromStrings(false);`);
await Protocol.Debugger.onceScriptParsed();
InspectorTest.logMessage(
await Protocol.Runtime.evaluate({expression: 'eval("1+1")'}));
InspectorTest.logMessage(
await Protocol.Runtime.evaluate({expression: 'new Function("return 1+1")()'}));
},
async function testEvaluateUnsafeEvalDisableBypass() {
contextGroup.addScript(`inspector.setAllowCodeGenerationFromStrings(false);`);
await Protocol.Debugger.onceScriptParsed();
InspectorTest.logMessage(
await Protocol.Runtime.evaluate({expression: 'eval("1+1")', allowUnsafeEvalBlockedByCSP: false}));
InspectorTest.logMessage(
await Protocol.Runtime.evaluate({expression: 'new Function("return 1+1")()', allowUnsafeEvalBlockedByCSP: false}));
},
async function testCallFunctionOn() {
await contextGroup.addScript(`inspector.setAllowCodeGenerationFromStrings(false);`);
const globalObject = await Protocol.Runtime.evaluate({expression: 'this'});
......
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