Skip to content

feat(ses): update lockdown init and enable Hermes VM #2723

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

Merged
merged 6 commits into from
Apr 7, 2025

Conversation

leotm
Copy link
Contributor

@leotm leotm commented Feb 14, 2025

Closes: #1891 (tracker), tested on #2334, Endo Sync: 2025-01-29

Previous iterations: #2723 (comment)

TODO

  • add new lockdown option
    • legacyHermesTaming: safe (default), unsafe
    • hostEvaluators: '_legacy' (default), 'all' (regular), 'none' (strict csp), 'no-direct' (hermes)
    • fail on safe-eval (default) and no-direct (hermes) early
      • i.e. require unsafe-eval and no-direct on hermes (since with not supported)
    • add assertions (on non _legacy options) and types
    • update ses/error-codes/SES_DIRECT_EVAL.md
    • update lockdown.md
    • refactor assertDirectEvalAvailable to probeHostEvaluators
      • return results, now used for further assertions
      • test Function() constructor and eval() separately then together
    • ensure backwards compatibility (lockdown({}) - no option provided)
      • before: worked with a strict CSP (assertDirectEvalAvailable swallows strict CSP error then skips SES_DIRECT_EVAL error)
      • after: 'all' as default (breaking change) with a strict CSP will error, 'none' is now required
      • endo sync: 4th option undefined, warn (with new error reporter) to use the new lockdown option
      • since getEnvironmentOption default must be a string ('all'), warn instead of SES_DIRECT_EVAL error with a strict CSP
      • default to '_legacy' under-the-hood if lockdown({}), warn to use new option; SES_DIRECT_EVAL error with a normal CSP, also when set to 'all'
      • document TODOs to replace '_legacy' with 'all' as default in future (the breaking change)
    • disable compartment-shim when bundling ses for hermes
    • disable: globalThis Compartment and testCompartmentHooks
    • disable compartmentInstance.evaluate instead of deleting compartment
      • makeCompartmentConstructor setGlobalObjectEvaluators safeEvaluate is the default (no evalTaming yet)
      • CompartmentPrototype.evaluate returns compartmentEvaluate safeEvaluate is the default (no evalTaming)
      • endo sync: throw error on usage, if env lacks direct eval support
  • test on hermes
    • evalTaming: no-eval/safe-eval/unsafe-eval
    • hostEvaluators: all/none/no-direct
    • post-lockdown: eval(42), eval('42'), Function('return 42')()
  • check prev test branch (below)
  • fix typos
  • update smoke test with Hermes eval assertions
  • enable Hermes VM in CI
  • fix(ses): lockdown options should be kebob-case #2739 merged 🎉 resolve conflicts
  • endo sync
    • lockdown options enum values kebab-case vs camelCase
    • could make no-direct a new evalTaming option instead, however this would mean no longer being able to choose unsafe-eval or no-eval, one would have to be the assumed default
    • could use no-eval instead of unsafe-eval (example added in docs)
    • dynamic no-direct instead of via lockdown option? no since we don't know the user intention, whether to throw SES_DIRECT_EVAL or allow SES to init
    • why not error on safe-eval? did this originally, but better to fail earlier when there are incompatible lockdown options (safe-eval requires direct eval)
    • no-compartment-eval instead of no-direct? maybe not since we also now allow SES to init w/o direct eval
    • --disallow-code-generation-from-strings useful node flag to emulate a strict csp runtime in tests
  • re-review

Follow-up: new Compartment() fails on removeUnpermittedIntrinsics at

  • Tolerating undeletable intrinsics.%CompartmentPrototype%.importNow.prototype === undefined
  • Uncaught TypeError: property is not configurable

test branch https://github.com/endojs/endo/tree/ses-hermes-p2 (from #2334)

  • yarn build:hermes bundle ses for hermes
  • yarn test:hermes run ses/test/_hermes-smoke.js

Hermes eval behaviour on bin/hermesc (standalone compiler) and bin/hermes (vm, eshost)

// Hermes direct eval cannot access or modify variables within its closure scope (sloppy and indirect)

eval = globalThis.eval; // remains direct eval, compiler: "error: invalid assignment left-hand side"

// calling globalThis.eval(...) uses indirect eval

// calling eval on Hermes VM emits: "warning: Direct call to eval(), but lexical scope is not supported."

print(eval(1 + 1));
print(eval("1 + 1"));

function a(eval, TEST) {
  // compiler: "error: cannot declare 'eval'"
  eval("TEST=true");
  return TEST;
}
print(a(eval, false)); // vm: false

function b(eval) {
  // compiler: "error: cannot declare 'eval'"
  var TEST = false;
  eval("TEST=true");
  return TEST;
}
print(b(eval)); // vm: false

function c() {
  var TEST = false;
  eval("TEST=true");
  return TEST;
}
print(c()); // vm: false

function d() {
  var TEST2 = 42;
  return eval("TEST2");
}
print(d()); // ReferenceError: Property 'TEST2' doesn't exist

// Note: eshost only runs bin/hermes (vm), not bin/hermesc (compiler)

@leotm leotm changed the title feat(ses): Hermes eval and compartment taming feat(ses): Hermes eval and compartment taming lockdown option Feb 17, 2025
@leotm leotm force-pushed the ses-hermes-lockdown-taming branch 5 times, most recently from 69a97f5 to 7e2b07a Compare February 19, 2025 17:27
@leotm leotm changed the base branch from ses-hermes-fn-caller-arguments-permits-check to master February 19, 2025 17:29
@leotm leotm changed the base branch from master to ses-hermes-fn-caller-arguments-permits-check February 19, 2025 17:30
@leotm leotm force-pushed the ses-hermes-lockdown-taming branch 3 times, most recently from fa54256 to 5793270 Compare February 19, 2025 18:13
@leotm leotm force-pushed the ses-hermes-lockdown-taming branch 3 times, most recently from 1e87397 to 063ec33 Compare February 19, 2025 19:04
@leotm leotm force-pushed the ses-hermes-lockdown-taming branch 3 times, most recently from 8cf7a5e to d0269ff Compare February 24, 2025 17:08
@leotm leotm marked this pull request as ready for review March 27, 2025 19:10
@leotm leotm requested a review from erights March 27, 2025 19:11
@erights
Copy link
Contributor

erights commented Mar 27, 2025

@Jack-Works , this PR is now proceeding under the assumption that it would be ok with you to change the behavior of 'unsafe-eval' slightly: On a platform (like Hermes) without any direct eval, it would be ok to move the error that compartment-evaluators-are-not-possible from initialization time to the time that someone tries to use a compartment evaluator. This would allow non-compartment use of unsafe evaluators even on those platforms. On platforms with direct eval, this change should have no observable difference.

Would that change in 'unsafe-eval' behavior be ok with you? If not, could you clarify your motivating use case for 'unsafe-eval'? Thanks.

@Jack-Works
Copy link
Contributor

@Jack-Works , this PR is now proceeding under the assumption that it would be ok with you to change the behavior of 'unsafe-eval' slightly: On a platform (like Hermes) without any direct eval, it would be ok to move the error that compartment-evaluators-are-not-possible from initialization time to the time that someone tries to use a compartment evaluator. This would allow non-compartment use of unsafe evaluators even on those platforms. On platforms with direct eval, this change should have no observable difference.

Would that change in 'unsafe-eval' behavior be ok with you? If not, could you clarify your motivating use case for 'unsafe-eval'? Thanks.

Yes, it's ok with me. I'm only using this on platforms with direct eval available

@leotm leotm force-pushed the ses-hermes-lockdown-taming branch from 1bfed4d to 13f4d10 Compare April 1, 2025 15:16
@leotm leotm force-pushed the ses-hermes-lockdown-taming branch from 13f4d10 to 1a348f9 Compare April 1, 2025 15:30
@leotm

This comment was marked as resolved.

@leotm
Copy link
Contributor Author

leotm commented Apr 1, 2025

@erights i've rebased the 9 commits into 6 and ready for merge, unless any further feedback

@leotm leotm enabled auto-merge (rebase) April 1, 2025 16:00
Copy link
Contributor

@erights erights left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@@ -1,4 +1,12 @@
User-visible changes in `ses`:
<!-- markdownlint-disable MD041 -->
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this line mean? Does the need for this have something to do with this PR, or is it a drive-by? Did you use some kind of yarn format-like or prettier-like thing for .md files? Should we bundle that in to yarn format (though not in this PR)? If so, please at least file an issue.

In any case, no change suggested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sorry i resolved #2723 (review) too early, exactly we should add a script (or include it in yarn format) then ensure it's run in CI (example)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you're right it's out of scope of this PR, filed issue here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reverted formatting changes in the end to keep this PR relevant/minimal and not step on any toes

all .md docs in the codebase better updated when addressing the filed issue then reviewed separetely

```sh
$ export LOCKDOWN_ERROR_TAMING=unsafe
Copy link
Contributor

@erights erights Apr 5, 2025

Choose a reason for hiding this comment

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

Was the $ removal manual or by the .md fixer thing?

I do mildly prefer keeping the $ prefix so readers can easily see this is shell and not js.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep .md fixer https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md014.md

Rationale: It is easier to copy/paste and less noisy if the dollar signs are omitted when they are not needed. See https://cirosantilli.com/markdown-style-guide#dollar-signs-in-shell-code for more information.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because some commands do not produce output, it is not a violation if some commands do not have output:

$ mkdir test
mkdir: created directory 'test'
$ ls test

seems a bit silly that some doesn't include one command with no output 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do mildly prefer keeping the $ prefix so readers can easily see this is shell and not js.

agree ^ added exception <!-- markdownlint-disable MD014 -->

@leotm leotm force-pushed the ses-hermes-lockdown-taming branch from 1a348f9 to 224bac2 Compare April 7, 2025 13:21
@leotm leotm mentioned this pull request Apr 7, 2025
@leotm leotm force-pushed the ses-hermes-lockdown-taming branch from 224bac2 to b59c100 Compare April 7, 2025 13:48
@leotm
Copy link
Contributor Author

leotm commented Apr 7, 2025

@leotm
Copy link
Contributor Author

leotm commented Apr 7, 2025

nb: next release ([email protected]) ses-hermes.cjs shim will be consumed by

to plug into Metro for bundling React Native apps

@leotm
Copy link
Contributor Author

leotm commented Apr 7, 2025

RE #2334 (review) @kriskowal

Please add a draft of release notes to NEWS.md. I roll these up to a blog on hardenedjs.org now and this would likely be a headline.

and RE #2108 @erights

None. Nothing Breaking certainly. Nothing newsworthy yet. But when the ses-shim as a whole is know to support Hermes, that will be newsworthy ;)

happy to expand current NEWS.md update in follow-up a PR to be more newsworthy (;

which i imagine would land on https://github.com/endojs/hardenedjs.org/tree/main/src/content/docs/blog

i foresee the blog post could detail how SES can now be used with Metro to run Hardened JS on React Native Hermes (or JSC) apps, like we're doing in LavaMoat/LavaMoat#1438

  • SES now compatible with Hermes compiler/VM
  • SES now tolerates Hermes language features
  • SES can now initialise w/o direct eval using evalTaming
  • lockdown only, no Compartment yet
  • import/require 'ses/hermes'
  • curl/wget .../ses-hermes.cjs
  • currently supporting v0.12.0, next v0.13.0 then either
    • further hermes tags
    • subsequent supported major versions of react-native containing sdk with side-by-side hermes bins
    • (unreleased static hermes, currently too expensive to build and run in CI)

@leotm leotm force-pushed the ses-hermes-lockdown-taming branch from b59c100 to 093bdcb Compare April 7, 2025 15:53
@leotm leotm merged commit 5d350ad into master Apr 7, 2025
15 of 16 checks passed
@leotm leotm deleted the ses-hermes-lockdown-taming branch April 7, 2025 16:05
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.

SES lockdown Hermes compat tracking issue
5 participants