-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
with (scopeProxy) { foo() }
leaks scopeProxy if foo mentions this
.
#31
Comments
Due to https://github.com/google/caja/wiki/SES#this-binding-of-global-function-calls The scopeProxy was never supposed to leak. The problem is only caused by At an unmodified normal JS prompt, const obj = { foo() {'use strict'; return this;} };
with (obj) { foo() === obj; } // true
with (obj) { (1,foo)() === undefined; } // true This leakage of What this means under the evaluator-shim and the realms-shim, and therefore under SES: const e = new Evaluator();
function foo() { return this; }
e.evaluate('foo()', { foo }); // evaluates to the scopeProxy. Amusingly, once #18 is fixed by Agoric/evaluator-shim#3 the following works const e = new Evaluator();
function foo() { return this; }
e.evaluate('foo()', Object.freeze({ foo })); // undefined because If we cannot practically prevent the scopeProxy from leaking, we need to ensure that no vulnerability follows from leaking the scopeProxy. We could probably make the scopeProxy no more powerful than the safeGlobal plus the values of the endowments. That should be both possible and adequate. |
valueOf()
causes surprising scopeProxy trapwith (scopeProxy) { foo() }
leaks scopeProxy if foo mentions this
.
(grr...it's too easy to accidentally loose/close a github tab with an unsaved text entry field...trying again) This should be easy (at least at the ECMA-262 spec. level) to fix. Object Environment Records already have a specification mechanism that controls whether or not they make their backing object available for inclusion in resolved References. This is controlled by the setting their withValue to true. With statements normally do that for all with objects. What we need to do is not set withValue to true when the with object is a ScopeProxy. There are various ways this might be done in the spec, but I suggest doing all the work in with statement evaluation. Specifically we need to put a "not a ScopeProxy" guard on step 5 which currently unconditionally sets withValue. What does the guard look like? We really don't want to build knowledge of a specific ScopeProxy definition into this level of ECMA-262. Instead, I suggest we define a new well-known symbol named @@hiddenWith. The guard would be: HasOwnProperty(obj, @@hiddenWith) is false. The definition of ScopeProxy (its proxy handler) would ensure that they always report that they have a @@hiddenWith own property. That's it! Actually updating implementations to do this is probably not quite so simple, I assume that they don't have anything that exactly corresponds to an Object environment record with a withValue flag. But I suspect that adapting an implementation to conform to this updated specification would be a modest effort—and well worth it. |
I left out of my redo: this ECMA-262 specification change appears be backwards compatible with all existing ES code. |
This is a use of
|
Well, it is also a mention of |
Ah. I see. Thanks. |
We've noticed that some Web APIs such as This fidelity bug of the shim causes code that would otherwise work to break if these functions are endowed to a compartment's global. |
How has multi-backflip affected this? |
It still leaks, but only the Main problem left is for module lexical created by the shim, as detailed in #912. Should we rename the title of this issue? It might be good to keep tracking an engine level change allowing to disable the current with context behavior. |
Please do! |
Narrowed scope and posted for follow-up: #1954 |
## Description This PR changes the `HIDDEN_PREFIX` of `ModuleSource` from the non-conforming `$h\u200D_` zero-width joiner (`ZWJ`) notation to the conforming `$h\u034F_` combining grapheme joiner (`CGJ`) notation. A future PR may address further changes to a `$\u034F`-prefixed and `\u034F$`-suffixed format as was suggested by @michaelfig in discussions. ### Motivation This change is motivated after encountering a parsing error when using `rollup` which was traced back to the `$h\u200D_`-prefixed identifier in an `endoScript` bundle. More importantly, this is also motivated by the subsequent discovery that `rollup`'s implementation was actually conforming to the ECMAScript Specification when it was throwing this error. To elaborate, while runtimes today will accept the special identifier notation that is currently being introduced by the `ModuleSource` rewrites, the current `$h\u200D_` zero-width joiner (`ZWJ`) notation does not conform to the specifications defined in the [ECMAScript Lexical Grammar](https://tc39.es/ecma262/#sec-names-and-keywords). In essence, what the specifications entail is that the character sequence for [Identifier Names](https://tc39.es/ecma262/#sec-identifier-names) once unescaped would be expected to match the `/^[$_\p{ID_Start}][$_\p{ID_Continue}]*$/u` pattern, aside from the additional `#` character prefix required in the case of private fields. As such, one can test this in the console by evaluating the following: ```js Object.fromEntries([String.raw`$h\u200D_`, String.raw`$h\u034F_`].map(id => [id, /^[$_\p{ID_Start}][$_\p{ID_Continue}]*$/u.test(JSON.parse(`"${id}"`))])) ``` The above would yield the following object in a runtime where the unicode escape sequences are retained: ```js {$h\u200D_: false, $h\u034F_: true} ``` Digging closer in the Unicode Standard, it seems that the zero-width joiner (`ZWJ`) may indeed be used in a conforming notation per [Emoji Profile in Annex #31 of the Unicode Standard](http://www.unicode.org/reports/tr31/#Emoji_Profile), however this is not applicable for this purpose as it would require the use of emojis. At this point, my suggestion to instead use the combining grapheme joiner (`CGJ`) is best articulated with this excerpt that I am borrowing from its canonical Wikipedia entry: > However, in contrast to the zero-width joiner and similar characters, the `CGJ` does not affect whether the two letters are rendered separately or as a ligature or cursively joined—the default behavior for this is determined by the font.[^1] > > > [^1]: https://en.wikipedia.org/wiki/Combining_grapheme_joiner The Wikipedia article offers additional nuances about the differences, while the [Proposal for addition of COMBINING GRAPHEME JOINER](https://www.unicode.org/L2/L2000/00274-N2236-grapheme-joiner.htm) offers the necessary context about its intent. It is fair to note that there are many uses of the zero-width joiner (`ZWJ`) already in the wild, and in fact there are currently `test262` tests for its occurrence. That said, unless those uses are conforming to the ECMAScript Specification and the Unicode Standard, they will limit code portability and adoption by users who may end up confused by failures similar to the one encountered with `rollup`. Ultimately, with the reasonable recommendations to exercise caution when it comes to bundling `ses` and related sources that are best bundled with `bundleSource` instead, those sources may still need to be parsed with tools like `rollup` for different purposes that would be aligned with the expectations that they are being handled safely. ### Approach #### Substituting the invisible joiner character A search across the monorepo for `(?:\u200d|\\u200d)_` yields only 3 files of interest: - `packages/module-source/TESTS.md` - `packages/module-source/src/hidden.js` - `packages/module-source/test/module-source.test.js` While making changes to the 3 files of interest, a distinction is made between matching `\$h\\u200d_` and `\$h\u200d_` where the replacements are respectively `$h\\u034f_` and `$h\u034f_`, along with their `$c` equivalents. The search across the monorepo for `(?:\u200d|\\u200d)_` yields another 978 files that are not of interest found in: - `packages/test262-runner/test262/test/language/expressions/class/elements` - `packages/test262-runner/test262/test/language/statements/class/elements` All those files remain unchanged. #### Ensuring generic wording is used For testing and other purposes where descriptive phrases are used to refer to the use of `ZWJ`, `CGJ` or other characters for this same intent, the phrase *"invisible joiner character"* is suggested. ### Security Considerations **Does not apply to my knowledge** ### Scaling Considerations **Does not apply to my knowledge** ### Documentation Considerations **Does not apply to my knowledge** ### Testing Considerations **See**: #2436 (comment) ### Compatibility Considerations While the changes do not affect compatibility when the generated code is evaluated at runtime, there can potentially be compatibility concerns with tools that have been specifically designed to work with the current notation. ### Upgrade Considerations **Does not apply to my knowledge**
) closes: #XXXX refs: endojs/endo#31 (comment) ## Description Testing on Brave, the browser's global `fetch` function works when called with its `this` bound to either `undefined` or the browser global object, but does not work if its `this` is bound to something else. The code this PR fixes was misbehaving because it was calling `powers.fetch(...)`, i.e., happening to call it as a method with its `this` bound to the irrelevant `powers` object. This refactor just expresses the intention of this code, which is just to call the `fetch` function without passing it some object as its `this` binding. This seems to fix the problem. Not at all addressed by this PR: The fact that this problem happened from a programming patterns that seems correct and would have passed review indicates a deeper hazard. This PR does nothing to mitigate this deeper hazard. It only fixes this case where we fell into the hazard. ### Security Considerations none ### Scaling Considerations none ### Documentation Considerations none, except as needed to address the more general hazard. ### Testing Considerations Only tested `fetch` behavior on Brave. Based on that, proceeding under untested assumption that this refactor will work on all supported browsers. ### Upgrade Considerations none
Typing
valueOf()
into the evaluator shim playground (demo/index.html) and hitting the Evaluate button causes the errorUnlike other surprising scopeProxy traps, this does not look like an engine bug. We see identical symptoms on Brave, FF, and Safari.
[edit by @kriskowal 2020-08-12:]
Actions needed (to be independently tracked, and this issue closed)
Create a specification proposal that introduces ahiddenWith
symbol thatwith
would respect.barring eventual engine support for ahiddenWith
symbol.absentrevealing thehiddenWith
,ScopeProxy
does not break containment.The text was updated successfully, but these errors were encountered: