Open leotm opened 6 months ago
My understanding of this issue is that we’re tracking integration problems with Hermes and some of these may motivate recommendations to change the SES shim to broaden its portability. (I’m driving similar work with XS.) You also are getting by with some transformations and manual edits of the SES shim that might upstream.
@leotm Do you plan to propose changes?
One of the things I am thinking of doing for XS is elaborate the "exports"
in package.json
to use a custom variant of SES for that platform. That amounts to including only certain layers, and having some XS-specific layers. I imagine something similar will be in order for Hermes.
{
"exports": {
"hermes": {},
"xsnap": {},
"default": {},
}
}
My understanding of this issue is that we’re tracking integration problems with Hermes and some of these may motivate recommendations to change the SES shim to broaden its portability. (I’m driving similar work with XS.) You also are getting by with some transformations and manual edits of the SES shim that might upstream.
@leotm Do you plan to propose changes?
One of the things I am thinking of doing for XS is elaborate the
"exports"
inpackage.json
to use a custom variant of SES for that platform. That amounts to including only certain layers, and having some XS
Exactly ^ renamed to tracking issue, was initially only planning on running a local codemod once functional, but a new separate export (non-async SES shim) for Hermes makes sense 👍 like you're thinking for XS
Updated description with deeper dive on tameSymbolConstructor
with couple solutions ^ security considerations pending further thought
Briefly demo'd https://github.com/MetaMask/metamask-mobile/pull/8009, a minimally transformed ses@0.18.8 wip that runs on Hermes (latest React Native default JS engine)
here's the omnibus of issues/mods below, while figuring which parts we definitely need (vs can skip/remove in a codemod) cc @erights would appreciate any thoughts
Bundling (Metro, release)
[x]
error: async functions are unsupported
loadWithoutErrorAnnotation
fixed since ses@1.5.0memoizedLoadWithErrorAnnotation
fixed since ses@1.5.0load
drainQueue
(introduced in ses@1.5.0)[x]
error: async generators are unsupported
async function* AsyncGeneratorFunctionInstance() {}
[ ] SES shim variant for Hermes and Static Hermes
Runtime
// assertDirectEvalAvailable(); // SES TypeError
// addIntrinsics(tameRegExpConstructor(regExpTaming)); // SES TypeError
// addIntrinsics(tameSymbolConstructor()); // Metro exception, RN polyfill error guard Fatal Error
// addIntrinsics(getAnonymousIntrinsics()); // SES TypeError
// completePrototypes(); // SES TypeError
// whitelistIntrinsics(intrinsics, markVirtualizedNativeFunction); // SES TypeError
// hardenIntrinsics(); // no error, app hangs loading
__hardenTaming__: 'unsafe'
isn't sufficient for the protection we requireTested across bundled Hermes for RN
Nb: latest minor version tags above, side-by-side with Hermes tarballs downloaded during build
async functionsnb: interestingly, Hermes seems to bundle fine and not complain about
async function AsyncFunctionInstance() { }
encountered bundling the app with Metro (considering testing Re.Pack)
Since Hermes
async
andawait
support is In Progress (let alone async generators)so Hermes doesn't support async arrow functions directly
but we're getting indirect support later via @babel/preset-env
nb: metro-react-native-babel-preset includes these 37 babel plugins too
In order to call lockdown only, do we still need
loadWithoutErrorAnnotation
?memoizedLoadWithErrorAnnotation
?load
?AsyncGeneratorFunctionInstance
?If so, re-write to Promises, otherwise skip parts or remove and refactor, or is there a better solution?
TODO: check refactor from async arrow fns to async fns; check latest bundled Hermes versions of RNNo longer an issue on bundled Hermes for RN 0.71.17+ (i.e. not a custom build from source)
assertDirectEvalAvailable
Since
eval
is Excluded From SupporttameRegExpConstructorno RegExp[Symbol.species] descriptor
,no stack
ses.cjs#4472:
TypeError('no RegExp[Symbol.species] descriptor');
This is because it is Excluded From Support on Hermes
For a good reason it seems, noting both warnings
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/species
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@species
So we likely want this part skipped or tameRegExpConstructor option to skip (plus remaining changes, then upstream)
fixed in
tameSymbolConstructor
property is not configurable
,no stack
/at [object CallSite]
ses.cjs#9481:
defineProperties(SharedSymbol, descs);
We can fix this simply by omitting
configurable: true
on Hermesin order to tame the Symbol constructor (used on constructed compartments), we attempt to temporarily make all props
configurable: true
so that we can whitelist (remove non-standard) props, then harden them (back to non-configurable)Hermes has 15
Symbol
props on all versions (contrasted to e.g. Node with 18)on metamask-mobile (Android) when we observe
Object.getOwnPropertyDescriptor(originalDescsEntries, name)?.configurable
we get 15 non-true props: 1false
prop (length
), 14undefined
nb: on Hermes v0.12.0 built from scratch
(i built/ran Hermes from scratch to observe above, since Hermes via eshost-cli on m2 is unsupported via jsvu(mac64arm) and doesn't fetch via esvu(darwin-arm64) and built Hermes via eshost complains
hermes: Unknown command line argument '-fenable-tdz'
and Hermes playground only prints[object Object]
- but thx for demo'ing @gibson042, jealous how it worked so eloquently on your machine :p)nb: some Hermes Language Features
Symbol.species
and its interactions with JS library functionsSymbol.unscopables
(Hermes does not supportwith
)Symbol.prototype.description
(it's not fully spec-conformant yet.Symbol().description
should beundefined
but it's currently''
)[Symbol.iterator]
)nb: our
tameSymbolConstructor
fnnb: a
SymbolTaming
lockdown option doesn't exist yet (same with FunctionTaming ontameFunctionConstructors
)solutions
packages/ses/src/tame-symbol-constructor.js
)packages/ses/src/lockdown.js#L276
)safe
(current implementation)unsafe
(skip taming, none at all)extra
The ses shim is constructed to _eventually_ enable vetted shims...
10mo ago now we have vetted shimssecurity considerations pending further thought
getAnonymousIntrinsicsConflicting definitions of %InertAsyncFunction%
,no stack
ses.cjs#3688:
TypeError( `Conflicting definitions of ${name}`);
No longer an issue (was only occurring in initial ses.cjs iteration)
completePrototypes
lockdown.prototype property not whitelisted
,no stack
ses.cjs#3730:
TypeError( `${name}.prototype property not whitelisted`)
whitelistIntrinsics
Unexpected intrinsic intrinsics.isFinite.__proto__ at %FunctionPrototype%
,no stack
ses.cjs#3953:
TypeError( `Unexpected intrinsic ${path}.__proto__ at ${protoName}`)
isFinite
appears to be the first of many intrinsicsNo more SES TypeErrors thrown after whitelisting intrinsics
hardenIntrinsics
No errors visible, but app hangs loading (under investigation)
Solution:
__hardenTaming__: 'unsafe'
(default safe)https://github.com/endojs/endo/blob/master/packages/ses/docs/lockdown.md#__hardentaming__-options