Skip to content
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

layer 0: HostEnsureCanCompileStrings integration #76

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

caridy
Copy link
Collaborator

@caridy caridy commented Aug 18, 2022

This PR introduces the host integration to prevent code from being evaluated when needed.

@@ -548,8 +550,11 @@ location: https://tc39.es/proposal-compartments/
1. Else, if Type(_importMeta_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RequireInternalSlot(_moduleSource_, [[ModuleSource]]).
1. Let _evalRealm_ be the current Realm Record.
1. NOTE: Module Instances created from this constructor must use a valid source.
1. Perform ? HostEnsureCanCompileStrings(_evalRealm_).
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a ModuleSource is not problematic, but creating a Module Instance from that source is, in which case we call the host.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolo-ribaudo this is important so we can serialize and share a ModuleSource instance with another realm, and evaluate it there if possible without requiring string evaluation privileges on the realm creating the source.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I believe the Host operation has the wrong (or misleading) name since the problem is not really compilation IMO, but evaluation. We should get some clarifications from implementers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is somehow like you create a new Function via eval and call it in a CSP-enabled Realm. It's OK. You should put the check in the ModuleSource constructor.

Copy link
Member

@nicolo-ribaudo nicolo-ribaudo Sep 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a ModuleSource is not problematic

I just realized that this is problematic: for layer 1, hosts must parse the string passed to ModuleSource to provide the static analysis info, and thus it requires them to ship a complete parser.

This host hook is not just about security, it's about avoiding shipping big chunks of code (parser, interpreter) that are almost never used on resource-constrained engines.

1. Let _O_ be ? OrdinaryCreateFromConstructor(NewTarget, *"%Module.prototype%"*, « [[Module]], [[ModuleSourceInstance]], [[ImportHook]] »).
1. Let _moduleRecord_ to ! CreateModuleRecord(_moduleSource_.[[ModuleSource]]).
1. Let _moduleRecord_ to ! CreateModuleRecord(_evalRealm_, _moduleSource_.[[ModuleSource]]).
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reusing the _evalRealm_ here, but also it makes sense that when a module record is created, it can be associated to a realm, and the caller of the abstract operation to be responsible for providing such realm. This opens the door for more advanced use-cases like transferring instances across realms.

@@ -548,8 +550,11 @@ location: https://tc39.es/proposal-compartments/
1. Else, if Type(_importMeta_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RequireInternalSlot(_moduleSource_, [[ModuleSource]]).
1. Let _evalRealm_ be the current Realm Record.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean the [[Realm]] from the current Execution Context?

My feeling is that we should be getting [[Realm]] from an internal slot of the %Module% constructor, patterned after %Function%.

Copy link
Collaborator Author

@caridy caridy Aug 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the pattern used by Function constructor (https://tc39.es/ecma262/#sec-function-p1-p2-pn-body), which just calls https://tc39.es/ecma262/#sec-createdynamicfunction, and this abstract operation gets the current realm.

@@ -548,8 +550,11 @@ location: https://tc39.es/proposal-compartments/
1. Else, if Type(_importMeta_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RequireInternalSlot(_moduleSource_, [[ModuleSource]]).
1. Let _evalRealm_ be the current Realm Record.
1. NOTE: Module Instances created from this constructor must use a valid source.
1. Perform ? HostEnsureCanCompileStrings(_evalRealm_).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be called in ModuleSource constructor, because create a new module instance from a compiled source is safe, but convert a string to a ModuleSource is unsafe.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point... but the problem that I see here is that csp can completely block the parsing of a source... let's chat more about it. Ideally, we can decorate the source record to conditionally call this host hook. cc @nicolo-ribaudo

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

csp can completely block the parsing of a source

Yes, that's how CSP works.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I understand that's how it works today, but if we are going to extend the ModuleSource API to expose the metadata of the parsed source, you will not be able to parse it in the first place even though you don't plan to evaluate it. E.g.: a bundler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants