-
Notifications
You must be signed in to change notification settings - Fork 215
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
Promise.resolve(p).then(t => {...})` not actually safe from reentrancy attack. #9
Comments
@dtribble suggested two safe alternatives:
I'll add:
// at module init time:
const { resolve } = Promise;
const { thenFunc } = Promise.prototype.then;
const { apply } = Reflect;
...
// static method context
when(p, onSuccess, onFailure) {
return apply(thenFunc, resolve(p), [onSuccess, onFailure]);
}
```js |
The reason the new static method on |
On @dtribble 's suggested patch to
|
I would like to implement assimilation for Something like: const { hasOwnProperty } = Object.prototype;
const { apply } = Reflect;
[...]
static resolve(value) {
ensureMaps();
// Resolving a Presence returns the pre-registered handled promise.
let resolvedPromise = presenceToPromise.get(value);
if (!resolvedPromise) {
resolvedPromise = baseResolve(value);
}
if (apply(hasOwnProperty, resolvedPromise, ['then'])) {
// Make sure thenables are assimilated, not directly returned.
// This prevents reentrancy attacks even in case resolvedPromise is
// a genuine promise, but has a 'then' own property.
return new HandledPromise(resolve => resolve(resolvedPromise));
}
return resolvedPromise;
} |
The line return new HandledPromise(resolve => resolve(resolvedPromise)); does successfully hide the However, it does not assimilate |
Is there a reference or sample code that could assimilate as a thenable? That's my intention, of which I fell short. |
I'm about to take off, so briefly. But you should google for a test262-passing Promise implementation to get something accurate. if (value && typeof value.then === 'function') {
p = Promise.resolve().then(_ => new HandledPromise((resolve, reject) => value.then(resolve, reject)));
} The initial part is just to postpone the rest of it to a later turn. |
The key idea is to use the thenable's |
Thanks, I looked at Bluebird's implementation, and it appears the only significant difference is some defensiveness around looking up the |
* fix path and move file * check in agoric-evaluate tarball
@erights This is harder for me than it first seemed. How do I preserve the functionality of: HandledPromise.resolve(p) === p // when p is a Promise as well as assimilation for arbitrary |
Can you attack the following? const {
isFrozen,
getOwnPropertyDescriptor: gopd,
getPrototypeOf,
} = Object;
const { resolve: promiseResolve, prototype: promiseProto } = Promise;
const { then: originalThen } = promiseProto;
function isNormalPromiseThen(p) {
return isFrozen(p) &&
isFrozen(promiseProto) && // unnecessary under SES
getPrototypeOf(p) === promiseProto &&
promiseResolve(p) === p &&
gopd(p, 'then') === undefined &&
gopd(promiseProto, 'then').value === originalThen; // unnecessary under SES
} |
Ahh, yes, that gets me going! I had forgotten about isFrozen, which is key to defending without calling harden in the test. |
* fix(resolve): protect against reentrancy attack Closes #9 * fix(resolve): harden argument to HandledPromise.resolve The harden calls in eventual-send already need an SES-like environment for proper security. Make HandledPromise.resolve simpler and prevent proxy trickery. * fix(HandledPromise): set prototype to Promise * fix(test-thenable): proper workaround of override mistake
This issue was closed when we introduced |
@erights Is this still an issue, and if so, does it need to be done for Mainnet 1? |
It is still an issue. A search just now shows that we still have a massive overuse of |
As implied in endojs/endo#1126, |
If we have proxy brand/stamping checks (#3905), it should be possible to implement a safe |
See also endojs/endo#1250 , which would benefit from this. |
Hi @mhofman I just assigned the two of us. Do we have a separate issue where we document the constructor attack? |
is not actually safe from reentrancy attack.
This vulnerability is suggested by https://github.com/Agoric/eventual-send/issues/32 but not actually stated there. We carefully designed the semantics of
Promise.resolve
so that it was safe from reentrancy attacks, even when its argument was a thenable that triggers absorption. We had in mind that patterns like that above would likewise bePromise.prototype.then
would be frozen (good assumption)The attacker could make a genuine promise with an own
then
property that executes immediately, attacking any reentrancy available to it. Thus, we must find some alternative to the above code pattern.The text was updated successfully, but these errors were encountered: