-
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
Node.js adds a property called domain
to promises
#126
Comments
See https://github.com/Agoric/ERTP/blob/master/util/makePromise.js We should instead monkey patch the Promise constructor, and other elements of the std Promise API to remove these as much as possible. That will subsume the safety of anything like a naive |
From what i can read, domains are expected to go eventually This eventually seems to be far away, though In the short term, it might be possible to ask the Node project if one of these solutions is possible:
|
@bmeck , could Node do one of @DavidBruant 's suggestions? Or could Node plug this leak by any other means? @DavidBruant , where else is it attached besides promises? |
@erights it is certainly possible to attempt both, though getter/setter is easier to land most likely. |
it looks like we do this to a variety of objects https://github.com/nodejs/node/blob/fce1a5198a89e8f62ea2d093e01971db46da9bf5/lib/domain.js#L62 , I need to think about this, but a flag might be simpler since some of those could be from userland |
Would making |
I am not oriented enough. How would this work? How might this make things safe? How might this fail to make things safe? |
@erights currently:
By making a new accessor pair or replacing it with a data property, it could be forced to always be Object.defineProperty(process, 'domain', {
get() {return null},
set(v) {},
enumerable: true,
configurable: false
}) Would then result in Completely disabling domains would be a large effort and the assignment is not on Promise exclusively so this seems somewhat reasonable to me to put the censoring at the source of the value. |
Is there any reason to prefer this accessor approach to Object.defineProperty(process, 'domain', {
value: null,
writable: false,
enumerable: true, // or false. I don't care
configurable: false
}); Either seems fine to me. Other things being equal, I prefer the data property approach. |
@erights it wouldn't matter for the most part. i would think slightly diff assignment errors if the whole non-writable prototype thing hints is the only diff. |
One reason to prefer the accessor might be to minimize difference — it’d normally be an enumerable accessor, so keeping it one reduces the change in this mode to just what’s really needed (that it return |
I opened a PR against node, though I'm sure something is likely to break if it expected the domain to be set and it suddenly was censored it should allow censoring at least. |
Thanks! |
We have some feedback trying to get together a test suite and concerns about breakage of the REPL itself since it uses this feature for error checking. Is there an example codebase that we can take a small look at that is trying to avoid this feature leaking info to complete the test suite against |
Hi @bmeck , well, SES. The existence of this feature causes leakage of stuff that should not be available. The uncontrolled, implicit, and syntactic creation of promises means SES cannot reliably intercept and remove these before user code can observe them. In addition to security leakage, observing them breaks host virtualizability, as these properties would not have been present on other hosts. Whatever is currently doing this, can't it get the same effect with a private weakmap instead? |
This doesn't seem like a codebase we can use to check that disabling the feature allows code to work properly though. I was looking for some example code that had the problems being able to run tests against to show that allowing it to be disabled does indeed allow the node runtime and the SES code to work properly still. |
I don't think I yet understand what you're asking for. For any closed test of only functionality, the addition of an unexpected exploitable property won't cause the closed test to fail. However, it will cause security to fail because an attacker can know to exploit it. So what kind of test are you looking for? What if we had a test that created a promise, checked the names of all its own properties, and fails if it has any own properties it doesn't expect, like |
this issue arose from
I'm looking for a reproduction of the REPL and/or environment we are trying to ensure works. We cannot simply use a WeakMap as ecosystem APIs and the deprecated Node API are using that for public accessible interactions. Any change we make to the API needs to ensure things like the REPL in question continue to work. Node's |
I am still not understanding. Are you saying that you cannot avoid adding the At this point I think I remain totally confused. My suspicion is that the only way forward is indeed to write a test that would fail if it sees a |
@erights we can avoid it, but we cannot do so without someone censoring the API. you have to opt-in to us not adding that property. We would have to make any WeakMap publicly accessible and for backwards compat would need to keep the original behavior unless you opt-in to the breaking change somehow. |
Good, thanks. That we can do. As we discussed, were it just on promises, we could refactor to make it an accessor on |
What old code would break that
? |
This is largely irrelevant to our being able to state it is safe to fix/demeans existing codebases. The node default REPL depends on
This is part of the question, |
we can talk about this tomorrow, @misterdjules would it be possible for you to attend? |
Mark won't be at the meeting tomorrow due to a prior engagement.
…--
Michael FIG
Software Engineer, Agoric
On Wed., Dec. 11, 2019, 8:55 p.m. Bradley Farias, ***@***.***> wrote:
we can talk about this tomorrow, @misterdjules
<https://github.com/misterdjules> would it be possible for you to attend?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<https://github.com/Agoric/SES/issues/113?email_source=notifications&email_token=AADPUHDW37HDDXEHN7IBB2TQYGRYTA5CNFSM4HFW2POKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEGVJKJA#issuecomment-564827428>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AADPUHGQ5DJYG2SE722C7VTQYGRYTANCNFSM4HFW2POA>
.
|
@bmeck What date and time is the meeting? |
@misterdjules Weekly Thursday at 1PM Pacific, but it appears that this week might not be ideal. |
@bmeck I would be available today, but not next week. |
A tip from @dominictarr suggests it is possible to disable domains by defining if (typeof process === 'object' && process !== null) {
// Prevents domains from initializing:
Object.defineProperty(process, 'domain', {value: null, configurable: false, writable: false, enumerable: false});
if (typeof require === 'function') {
let domainsInitializedAlready = false;
try {
require('domain')
domainsInitializedAlready = true;
} catch {
// We expect an initialization error.
}
if (domainsInitializedAlready) {
throw new Error(`SES cannot guarantee containment if Node.js domains have already been initialized`);
}
}
} This covers CommonJS only. We might be able to do the same with dynamic import, but only asynchronously, and we can’t feature-detect ESM with |
Now without caveats: if (typeof process === 'object' && process !== null) {
// Check whether domains were initialized:
const domainDescriptor = Object.getOwnPropertyDescriptor(process, 'domain');
if (domainDescriptor !== undefined && domainDescriptor.get !== undefined) {
throw new Error(`SES cannot guarantee containment if Node.js domains have been installed`);
}
// Prevents domains from initializing:
Object.defineProperty(process, 'domain', {value: null, configurable: false, writable: false, enumerable: false});
} |
An alternative in case we want t allow
|
One of the implicit albeit soft requirements is to avoid coupling SES to any particular module system. Currently, the same source works in a browser script, CJS, and ESM, since it’s just presenting its API as mutations to the global scope. This keeps the build system small and avoids initializing anything it doesn’t need. I’m going to present a PR with the snippet above. |
Fixes #126 *BREAKING CHANGE*: Removes support for [RESM](https://github.com/standard-things/esm).
* chore: update outdated * chore: lint-fix with new versions of eslint configs
Mark and I noticed that Node.js adds a property called
domain
to promises while running something from a REPL in SwingSet.Mark says that
domain
leads to all sorts of objects whose semantics we haven't inspected for safety. This is an authority leak. If SES can't remove the domain property from all promises before the promise is exposed to user code, then this is a severe authority leak for SES as run on Node.js. Fortunately it seems to only be a problem when code is run from a REPL.[edit 2020-09-15 @kriskowal]
SES will not be secure on Node.js until we have the means to disable
domains
. We must work with the Node.js project to reveal a command-line flag or the moral equivalent.The text was updated successfully, but these errors were encountered: