-
Notifications
You must be signed in to change notification settings - Fork 74
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
Alternative harden
implementation approach
#705
Comments
I searched the spec for the various terms that could Searching the spec for the various ways something could become non-extensible (recursively following up the "abstract operations"):
In 12.2.9.4, the arrays provide by template literals are frozen via In 9.4.6, Module Namespace Exotic Objects are specified to simply override 9.2.4.1 Note: @erights pointed out these places where extensibility is relevant in the spec, so the search terms kept expanding until they covered these issues. Edits to update for comments below. |
This is not why they cannot be made readonly. Normal non-configurable writable properties can be made readonly. Only exotic behavior can refuse to be made readonly. Proxies can implement such exotic behavior. IIRC module namespace objects do too, but I have not looked. |
Unless they're empty, in which case, like the templates array, they're transitively immutable anyway, and so not a threat. |
Also, Dean found a third case that I forgot: The ThrowTypeError object. But it is already included in our primordials and hardened on |
Still need a |
In progress at #706 . Many things pass but many things fail. Does a lot of self-testing, some of which also fails. Handed back to @kriskowal until further notice. |
Does not workMy interim conclusion from the #706 experiment: This technique is too dangerous when (It looks like If we did a complete Finally, any of the existing host means of creating a new realm (vm on Node, iframe on the browser) create a non-isolated realm, it will come with its own fresh copies of these methods, which might innocently cause more violations of the crucial invariant. I emphasize "innocently" because we assume that none of the platform code is purposely malicious. But we only get to assume it upholds invariants we rely on when we assume reasonable invariants. ButThe immediate temporary situation Agoric is in:
Use only where we must. Kill it soon.Best would be if we can get the underlying scaling problem fixed before we need to deploy this. But if we must deploy it on XS only on-chain, and kill it before any potentially malicious code is to run on chain, we can cope. |
The other hazard is that some of our own code accidentally either freezes something early, or samples the freezing functions early, merely because of the order of module initialization. That's why I had to change the import order at https://github.com/endojs/endo/pull/706/files#diff-49d41d34c5a4387e587918e9e0d6de6ee8431bea720f90e81954fca5e953b88c in packages/ses/index.js . This is not a fatal hazard, but it is a PITA. We don't currently have any good way to prevent this accident under maintenance. The tooling needed to ensure this is upheld would be weird, but certainly possible. |
If we were to place a complete membrane between SES and all the non-SES host-provided objects on the start compartment's global, that could preserve the crucial invariant on all objects reachable from SES. The key is that the SES-side of the membrane should only present non-extensible objects to SES that are also registered on the |
Assigning me to Agoric/agoric-sdk#3118 makes sense to me, but not this one. As a poor-man's notation for blocking dependency, this depends on addressing: |
Closing since we are not pursuing this |
What is the Problem Being Solved?
The current implementation of
harden
uses membership in aWeakSet
to determine whether various objects, functions, etc. have already been hardened. This prevents infinite recursion and improves performance by preventing walking already-frozen object graphs. The algorithm cannot just useisFrozen
for the test because a user could manuallyfreeze
objects that reference still-mutable state.That
hardened
WeakSet
can get very large, whereas in both typical JavaScript programs and in Agoric's model usingharden
,Object.freeze
is rarely used. Can we eliminate the need for the largehardened
set?Description of the Design
This alternative implementation approach is inspired by the assumption that we harden many more objects than we just freeze. So we record the usages of
freeze
instead.hardened
WeakSet to aonlyFrozen
WeakSet.Object.freeze
to both freeze the object and add it to theonlyFrozen
setisFrozen
is unchangedharden
just recursively freezes. If it finds a frozen object, it checks whether it's in theonlyFrozen
set. If so, it removes it from the set and recurs on itfreeze
cannot be shimmed early enough, thenlockdown
may use ahardened
set to recur into frozen things it has not seen before.As a result,
isHardened(o)
isisFrozen(o) && !onlyFrozen.has(o)
Security Considerations
3 potential concerns:
lockdown
is calledObject.freeze
Re #2, @erights had some insight:
The text was updated successfully, but these errors were encountered: