-
Notifications
You must be signed in to change notification settings - Fork 226
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
GC sensing possible with custom WeakMap/Set #5000
Comments
Even though it is an information leak, I labeled it with security-availability rather than security-confidentiality because the threat here is breaking consensus by acting differently on different validators, based only on changes in spontaneous GC schedule. This could be caused, for example, by different memory budgets. Breaking consensus prevents progress, i.e., availability. Although no state was directly corrupted, I am also labeling it security-integrity, because correct code may operate incorrectly when it uses return override to add private fields to VDOs (virtual/durable objects). |
The coupling here is interesting. Naively this should not have been possible because
It is only this last step which falls into this trap, where the consequences of liveSlots observing GC inadvertently bled through into observability by the code running under supervision by that liveSlots instance. I don’t see any way to repair this without either
Fortunately, this is not relevant to MN1. It is relevant to MN3. |
Regarding a possible VM change on the private fields side, I've been trying to think about what that could look like. I've also been reading discussions around similar concerns when attaching private fields to the WindowProxy. Conceptually there is no difference between attaching a private field to an object, and using that object as a WeakMap key. Any mechanism that prevents private fields attachment should similarly prevent addition to Weak collections. WeakRef / FinalizationRegistry may be sufficiently orthogonal to not participate in the same mechanism, but that seems improbable. The fact we deny the WeakMap/WeakSet intrinsics to the contract's Compartment does not negate that liveslots needs the ability to add VDO and Presence representatives to a native WeakMap, as well as WeakRef and FinalizationRegistry. Thus any mechanism we come up with must not be absolute. One approach may be to have a temporal aspect to the mechanism: you can add the object to Weak collections or WeakRef/FR until it is "flagged as unweakable". At first I imagined the "unweakable" mechanism could be a flag to It's also unclear whether the stage 1 private declarations proposal would enable adding private fields to objects after their creation without using the return override trick. I opened an issue to clarify: tc39/proposal-private-declarations#12 |
Maybe an alternative would be to somehow have the ability to flag objects so they cannot be used in a return override construction? |
For folks (like me) trying to understand the mechanics around this, I found https://hacks.mozilla.org/2021/06/implementing-private-fields-for-javascript/ to be a useful primer on private fields and the way a constructor can "override" the object being created by returning a value (instead of omitting the |
An rough idea of how to accomplish this would be:
|
Neat! The linked article on the origins of the return override is also enlightening: https://www.mgaudet.ca/technical/2020/7/24/investigating-the-return-behaviour-of-js-constructors |
There's an important piece of this story that I'm completely failing to grok from the various comments and links folks have given, namely: how does this particular combination of features or misfeatures enable the creation of a weak-keyed collection in user space? Because I'm just not seeing it. |
I think the most descriptive is the actual implementation: https://github.com/endojs/endo/blob/9600194abc53bf28ca877f9b8eeb6ef73c52b214/packages/make-hardener/src/AltWeakMapSet.js |
That is whacky. How is this not just considered a spec bug? |
Because unfortunately return override was added on purpose for backwards compatibility in the ES6 days. And its implications on private fields must have been considered since there are spec algorithms that explicitly check for privates being already present when installing them, which can only happen in the return override case. What this means is you can create |
If we wanted to tackle this by preventing specifically private fields addition, I think the following approach would work:
const facet = Object.create(
Object.prototype,
boundBehaviorPropertyDescriptors,
{
privateSealed: true,
},
); The advantage of this approach is that it doesn't create the ability for code to prevent extensions through the return override trick on 3rd party objects, only the creator can decide that. It's not clear if a similar concept could apply to classes. It feels like the conceptual equivalent would be a An options bag might also allow private declarations to be set on a regular object at construction without requiring the object literal syntax (as long as there is some kind of reification allowing expression usage) : private #x as x;
const obj = Object.create(null, {}, { privateEntries: [x, 'privateValue'] });
assert(obj.#x === 'privateValue'); And finally it would allow an "integrity level caching" creation option as well. |
This came up on the html side with people stamping the window proxy object: whatwg/html#7952 |
Describe the bug
The current approach to avoid contract code from sensing if the representative of a Virtual Object was garbage collected and transparently re-created (#2724) is to replace the
WeakMap
andWeakSet
available in the contract's compartment by a vref aware version (#2993).However nothing prevents user code from rolling out their own WeakMap/WeakSet implementation based on class private fields and a return override, akin to the
AltWeakMapSet
that was once proposed to work around the WeakMap performance issues of XS (endojs/endo#703).To Reproduce
Conceptual for now, but I can build a POC if needed
Expected behavior
Contract code unable to sense GC.
Platform Environment
N/A
Additional context
The object being frozen does not prevent private fields from being attached, so that is not a possible avenue for mitigating this.
The only options I can think of right now are:
The text was updated successfully, but these errors were encountered: