Skip to content

Commit

Permalink
Normative: Provide source text to HostEnsureCanCompileStrings
Browse files Browse the repository at this point in the history
This is a continuation of Mike Samuel's work in #1498. Due to #2670, this
change can be made simpler than it previously was.

This change provides the source text to be evaluated, and the grammar
symbol that should be used to parse it, to the host hook
HostEnsureCanCompileStrings.

One example of where this is needed is for allowing a Content Security
Policy to provide hashes for code executed via `eval()` or
`new Function()`:
w3c/webappsec-csp#623
This is useful on its own, but has come up again in the topic of
ShadowRealm-HTML integration. In a ShadowRealm you can either execute code
asynchronously, with ShadowRealm.p.importValue, or synchronously, with
ShadowRealm.p.evaluate. Because the latter uses `eval()` inside the
ShadowRealm, it's subject to CSP rules, so the only CSP policy that will
let you execute synchronously in the realm is `unsafe-eval`.

The original purpose of #1498 was to support Trusted Types, which is still
a goal of this PR.

This is a separate needs-consensus PR, rather than being part of the
ShadowRealm proposal, because it's useful independently of ShadowRealm,
and also ShadowRealm would go forward regardless of whether this goes
forward.

Prior art: https://github.com/tc39/proposal-dynamic-code-brand-checks
  • Loading branch information
mikesamuel authored and ptomato committed Nov 16, 2023
1 parent 82c99bb commit d07cd69
Showing 1 changed file with 20 additions and 5 deletions.
25 changes: 20 additions & 5 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -19219,7 +19219,7 @@ <h1>Runtime Semantics: Evaluation</h1>
1. If _argList_ has no elements, return *undefined*.
1. Let _evalArg_ be the first element of _argList_.
1. If the source text matched by this |CallExpression| is strict mode code, let _strictCaller_ be *true*. Otherwise let _strictCaller_ be *false*.
1. [id="step-callexpression-evaluation-direct-eval"] Return ? PerformEval(_evalArg_, _strictCaller_, *true*).
1. [id="step-callexpression-evaluation-direct-eval"] Return ? PerformEval(_evalArg_, |Script|, _strictCaller_, *true*).
1. Let _thisCall_ be this |CallExpression|.
1. Let _tailCall_ be IsInTailPosition(_thisCall_).
1. Return ? EvaluateCall(_func_, _ref_, _arguments_, _tailCall_).
Expand Down Expand Up @@ -28884,13 +28884,14 @@ <h1>eval ( _x_ )</h1>
<p>This function is the <dfn>%eval%</dfn> intrinsic object.</p>
<p>It performs the following steps when called:</p>
<emu-alg>
1. Return ? PerformEval(_x_, *false*, *false*).
1. Return ? PerformEval(_x_, |Script|, *false*, *false*).
</emu-alg>

<emu-clause id="sec-performeval" type="abstract operation" oldids="sec-performeval-rules-outside-functions,sec-performeval-rules-outside-methods,sec-performeval-rules-outside-constructors">
<h1>
PerformEval (
_x_: an ECMAScript language value,
_goal_: a grammar symbol,
_strictCaller_: a Boolean,
_direct_: a Boolean,
): either a normal completion containing an ECMAScript language value or a throw completion
Expand All @@ -28902,7 +28903,7 @@ <h1>
1. If _x_ is not a String, return _x_.
1. Let _evalRealm_ be the current Realm Record.
1. NOTE: In the case of a direct eval, _evalRealm_ is the realm of both the caller of `eval` and of the `eval` function itself.
1. Perform ? HostEnsureCanCompileStrings(_evalRealm_).
1. Perform ? HostEnsureCanCompileStrings(_evalRealm_, _goal_, _x_).
1. Let _inFunction_ be *false*.
1. Let _inMethod_ be *false*.
1. Let _inDerivedConstructor_ be *false*.
Expand Down Expand Up @@ -28965,13 +28966,27 @@ <h1>
<h1>
HostEnsureCanCompileStrings (
_calleeRealm_: a Realm Record,
_goal_: a grammar symbol,
_bodyText_: a String,
): either a normal completion containing ~unused~ or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It allows host environments to block certain ECMAScript functions which allow developers to interpret and evaluate strings as ECMAScript code.</dd>
</dl>
<p>The default implementation of HostEnsureCanCompileStrings is to return NormalCompletion(~unused~).</p>

<emu-note>
<p>
_goal_ is the production which will be used to parse _bodyText_.
For example, if called via %Function% it might be the grammar symbol |FunctionBody[~Yield, ~Await]| and from %eval% it might be the grammar symbol |Script|.
</p>
</emu-note>

<p>
Implementations of HostEnsureCanCompileStrings should not coerce _bodyText_ to a string since callers will later do that and HostEnsureCanCompileStrings must not base security decisions on both coercions producing the same string.
Clients may base security decisions on internal slots.
</p>
</emu-clause>

<emu-clause id="sec-evaldeclarationinstantiation" type="abstract operation">
Expand Down Expand Up @@ -30157,8 +30172,6 @@ <h1>
<dd>_constructor_ is the constructor function that is performing this action. _newTarget_ is the constructor that `new` was initially applied to. _parameterArgs_ and _bodyArg_ reflect the argument values that were passed to _constructor_.</dd>
</dl>
<emu-alg>
1. Let _currentRealm_ be the current Realm Record.
1. Perform ? HostEnsureCanCompileStrings(_currentRealm_).
1. If _newTarget_ is *undefined*, set _newTarget_ to _constructor_.
1. If _kind_ is ~normal~, then
1. Let _prefix_ be *"function"*.
Expand All @@ -30185,6 +30198,8 @@ <h1>
1. Let _bodySym_ be the grammar symbol |AsyncGeneratorBody|.
1. Let _parameterSym_ be the grammar symbol |FormalParameters[+Yield, +Await]|.
1. Let _fallbackProto_ be *"%AsyncGeneratorFunction.prototype%"*.
1. Let _currentRealm_ be the current Realm Record.
1. Perform ? HostEnsureCanCompileStrings(_currentRealm_, _bodySym_, _bodyArg_).
1. Let _argCount_ be the number of elements in _parameterArgs_.
1. Let _P_ be the empty String.
1. If _argCount_ > 0, then
Expand Down

0 comments on commit d07cd69

Please sign in to comment.