From d2e502f4e69e6f8c0c87d10b8fb7812036e7e525 Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Fri, 18 Aug 2023 17:18:38 -0700 Subject: [PATCH 1/4] chore(ses): Rename non-shims to make room for shim layers --- packages/ses/src/{compartment-shim.js => compartment.js} | 0 packages/ses/src/{lockdown-shim.js => lockdown.js} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/ses/src/{compartment-shim.js => compartment.js} (100%) rename packages/ses/src/{lockdown-shim.js => lockdown.js} (100%) diff --git a/packages/ses/src/compartment-shim.js b/packages/ses/src/compartment.js similarity index 100% rename from packages/ses/src/compartment-shim.js rename to packages/ses/src/compartment.js diff --git a/packages/ses/src/lockdown-shim.js b/packages/ses/src/lockdown.js similarity index 100% rename from packages/ses/src/lockdown-shim.js rename to packages/ses/src/lockdown.js From 40b59cce6aa75de0635bcaddba8d6b8dd598a8c2 Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Fri, 18 Aug 2023 17:21:28 -0700 Subject: [PATCH 2/4] feat(ses): Support vetted shims --- packages/ses/index.js | 34 ++---------- packages/ses/src/assert-shim.js | 4 ++ packages/ses/src/assert-sloppy-mode.js | 11 ++++ packages/ses/src/compartment-shim.js | 15 ++++++ packages/ses/src/get-anonymous-intrinsics.js | 2 +- packages/ses/src/lockdown-shim.js | 35 +++++++++++++ packages/ses/src/lockdown.js | 55 +++++++++----------- packages/ses/src/make-safe-evaluator.js | 4 +- packages/ses/test/test-global-object.js | 2 +- packages/ses/test/test-lockdown-options.js | 8 +-- packages/ses/test/test-repair-intrinsics.js | 15 ++---- packages/ses/types.d.ts | 9 +++- 12 files changed, 113 insertions(+), 81 deletions(-) create mode 100644 packages/ses/src/assert-shim.js create mode 100644 packages/ses/src/assert-sloppy-mode.js create mode 100644 packages/ses/src/compartment-shim.js create mode 100644 packages/ses/src/lockdown-shim.js diff --git a/packages/ses/index.js b/packages/ses/index.js index b0a3be63b0..06f4ab107d 100644 --- a/packages/ses/index.js +++ b/packages/ses/index.js @@ -12,34 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { globalThis, TypeError, assign } from './src/commons.js'; - -import { tameFunctionToString } from './src/tame-function-tostring.js'; -import { getGlobalIntrinsics } from './src/intrinsics.js'; -import { lockdown } from './src/lockdown-shim.js'; -import { makeCompartmentConstructor } from './src/compartment-shim.js'; -import { assert } from './src/error/assert.js'; - -/** getThis returns globalThis in sloppy mode or undefined in strict mode. */ -function getThis() { - return this; -} - -if (getThis()) { - // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_NO_SLOPPY.md - throw TypeError(`SES failed to initialize, sloppy mode (SES_NO_SLOPPY)`); -} - -const markVirtualizedNativeFunction = tameFunctionToString(); - -const Compartment = makeCompartmentConstructor( - makeCompartmentConstructor, - getGlobalIntrinsics(globalThis), - markVirtualizedNativeFunction, -); - -assign(globalThis, { - lockdown, - Compartment, - assert, -}); +import './src/lockdown-shim.js'; +import './src/compartment-shim.js'; +import './src/assert-shim.js'; diff --git a/packages/ses/src/assert-shim.js b/packages/ses/src/assert-shim.js new file mode 100644 index 0000000000..83b1808846 --- /dev/null +++ b/packages/ses/src/assert-shim.js @@ -0,0 +1,4 @@ +import { globalThis } from './commons.js'; +import { assert } from './error/assert.js'; + +globalThis.assert = assert; diff --git a/packages/ses/src/assert-sloppy-mode.js b/packages/ses/src/assert-sloppy-mode.js new file mode 100644 index 0000000000..0c19edf91f --- /dev/null +++ b/packages/ses/src/assert-sloppy-mode.js @@ -0,0 +1,11 @@ +import { TypeError } from './commons.js'; + +/** getThis returns globalThis in sloppy mode or undefined in strict mode. */ +function getThis() { + return this; +} + +if (getThis()) { + // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_NO_SLOPPY.md + throw TypeError(`SES failed to initialize, sloppy mode (SES_NO_SLOPPY)`); +} diff --git a/packages/ses/src/compartment-shim.js b/packages/ses/src/compartment-shim.js new file mode 100644 index 0000000000..ecdfac9d2b --- /dev/null +++ b/packages/ses/src/compartment-shim.js @@ -0,0 +1,15 @@ +/// + +import { globalThis } from './commons.js'; +import { makeCompartmentConstructor } from './compartment.js'; +import { tameFunctionToString } from './tame-function-tostring.js'; +import { getGlobalIntrinsics } from './intrinsics.js'; + +const markVirtualizedNativeFunction = tameFunctionToString(); + +// @ts-ignore Compartment is definitely on globalThis. +globalThis.Compartment = makeCompartmentConstructor( + makeCompartmentConstructor, + getGlobalIntrinsics(globalThis), + markVirtualizedNativeFunction, +); diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 3300c66a14..cf402c3339 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -15,7 +15,7 @@ import { regexpPrototype, globalThis, } from './commons.js'; -import { InertCompartment } from './compartment-shim.js'; +import { InertCompartment } from './compartment.js'; /** * Object.getConstructorOf() diff --git a/packages/ses/src/lockdown-shim.js b/packages/ses/src/lockdown-shim.js new file mode 100644 index 0000000000..e821df579c --- /dev/null +++ b/packages/ses/src/lockdown-shim.js @@ -0,0 +1,35 @@ +// @ts-check + +// We import this first to fail as fast as possible if the shim has been +// transformed or embedded in a way that causes it to run in sloppy mode. +// See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_NO_SLOPPY.md +import './assert-sloppy-mode.js'; +import { globalThis } from './commons.js'; +import { repairIntrinsics } from './lockdown.js'; + +/** + * @param {import('./lockdown.js').LockdownOptions} options + */ +globalThis.lockdown = options => { + const hardenIntrinsics = repairIntrinsics(options); + globalThis.harden = hardenIntrinsics(); +}; + +/** + * @param {import('./lockdown.js').LockdownOptions} options + */ +globalThis.repairIntrinsics = options => { + const hardenIntrinsics = repairIntrinsics(options); + // Reveal hardenIntrinsics after repairs. + globalThis.hardenIntrinsics = () => { + // Reveal harden after hardenIntrinsics. + // Harden is dangerous before hardenIntrinsics because hardening just + // about anything will inadvertently render intrinsics irreparable. + // Also, for modules that must work both before or after lockdown (code + // that is portable between JS and SES), the existence of harden in global + // scope signals whether such code should attempt to use harden in the + // defense of its own API. + // @ts-ignore harden not yet recognized on globalThis. + globalThis.harden = hardenIntrinsics(); + }; +}; diff --git a/packages/ses/src/lockdown.js b/packages/ses/src/lockdown.js index 39c4e81e23..6b7946cdab 100644 --- a/packages/ses/src/lockdown.js +++ b/packages/ses/src/lockdown.js @@ -49,7 +49,7 @@ import { tameConsole } from './error/tame-console.js'; import tameErrorConstructor from './error/tame-error-constructor.js'; import { assert, makeAssert } from './error/assert.js'; import { getAnonymousIntrinsics } from './get-anonymous-intrinsics.js'; -import { makeCompartmentConstructor } from './compartment-shim.js'; +import { makeCompartmentConstructor } from './compartment.js'; import { tameHarden } from './tame-harden.js'; import { tameSymbolConstructor } from './tame-symbol-constructor.js'; @@ -58,7 +58,10 @@ import { tameSymbolConstructor } from './tame-symbol-constructor.js'; const { Fail, details: d, quote: q } = assert; /** @type {Error=} */ -let priorLockdown; +let priorRepairIntrinsics; + +/** @type {Error=} */ +let priorHardenIntrinsics; // Build a harden() with an empty fringe. // Gate it on lockdown. @@ -124,7 +127,6 @@ const assertDirectEvalAvailable = () => { /** * @param {LockdownOptions} [options] - * @returns {() => void} repairIntrinsics */ export const repairIntrinsics = (options = {}) => { // First time, absent options default to 'safe'. @@ -190,17 +192,17 @@ export const repairIntrinsics = (options = {}) => { extraOptionsNames.length === 0 || Fail`lockdown(): non supported option ${q(extraOptionsNames)}`; - priorLockdown === undefined || + priorRepairIntrinsics === undefined || // eslint-disable-next-line @endo/no-polymorphic-call assert.fail( - d`Already locked down at ${priorLockdown} (SES_ALREADY_LOCKED_DOWN)`, + d`Already locked down at ${priorRepairIntrinsics} (SES_ALREADY_LOCKED_DOWN)`, TypeError, ); // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_ALREADY_LOCKED_DOWN.md - priorLockdown = TypeError('Prior lockdown (SES_ALREADY_LOCKED_DOWN)'); + priorRepairIntrinsics = TypeError('Prior lockdown (SES_ALREADY_LOCKED_DOWN)'); // Tease V8 to generate the stack string and release the closures the stack // trace retained: - priorLockdown.stack; + priorRepairIntrinsics.stack; assertDirectEvalAvailable(); @@ -357,7 +359,21 @@ export const repairIntrinsics = (options = {}) => { * repair separately from hardening. */ - function hardenIntrinsics() { + const hardenIntrinsics = () => { + priorHardenIntrinsics === undefined || + // eslint-disable-next-line @endo/no-polymorphic-call + assert.fail( + d`Already locked down at ${priorHardenIntrinsics} (SES_ALREADY_LOCKED_DOWN)`, + TypeError, + ); + // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_ALREADY_LOCKED_DOWN.md + priorHardenIntrinsics = TypeError( + 'Prior lockdown (SES_ALREADY_LOCKED_DOWN)', + ); + // Tease V8 to generate the stack string and release the closures the stack + // trace retained: + priorHardenIntrinsics.stack; + // Circumvent the override mistake. // TODO consider moving this to the end of the repair phase, and // therefore before vetted shims rather than afterwards. It is not @@ -369,27 +385,8 @@ export const repairIntrinsics = (options = {}) => { // must be the operation that modifies the intrinsics. tamedHarden(intrinsics); - // Reveal harden after lockdown. - // Harden is dangerous before lockdown because hardening just - // about anything will inadvertently render intrinsics irreparable. - // Also, for modules that must work both before or after lockdown (code - // that is portable between JS and SES), the existence of harden in global - // scope signals whether such code should attempt to use harden in the - // defense of its own API. - // @ts-ignore harden not yet recognized on globalThis. - globalThis.harden = tamedHarden; - - // Returning `true` indicates that this is a JS to SES transition. - return true; - } + return tamedHarden; + }; return hardenIntrinsics; }; - -/** - * @param {LockdownOptions} [options] - */ -export const lockdown = (options = {}) => { - const hardenIntrinsics = repairIntrinsics(options); - hardenIntrinsics(); -}; diff --git a/packages/ses/src/make-safe-evaluator.js b/packages/ses/src/make-safe-evaluator.js index 0458e71c98..78ce9e1a94 100644 --- a/packages/ses/src/make-safe-evaluator.js +++ b/packages/ses/src/make-safe-evaluator.js @@ -19,7 +19,7 @@ const { Fail } = assert; * @param {object} options * @param {object} options.globalObject * @param {object} [options.moduleLexicals] - * @param {Array} [options.globalTransforms] + * @param {Array} [options.globalTransforms] * @param {boolean} [options.sloppyGlobalsMode] */ export const makeSafeEvaluator = ({ @@ -54,7 +54,7 @@ export const makeSafeEvaluator = ({ /** * @param {string} source * @param {object} [options] - * @param {Array} [options.localTransforms] + * @param {Array} [options.localTransforms] */ const safeEvaluate = (source, options) => { const { localTransforms = [] } = options || {}; diff --git a/packages/ses/test/test-global-object.js b/packages/ses/test/test-global-object.js index 30984de783..babba4d9fe 100644 --- a/packages/ses/test/test-global-object.js +++ b/packages/ses/test/test-global-object.js @@ -9,7 +9,7 @@ import { setGlobalObjectEvaluators, } from '../src/global-object.js'; import { sharedGlobalPropertyNames } from '../src/permits.js'; -import { makeCompartmentConstructor } from '../src/compartment-shim.js'; +import { makeCompartmentConstructor } from '../src/compartment.js'; test('globalObject', t => { const intrinsics = { diff --git a/packages/ses/test/test-lockdown-options.js b/packages/ses/test/test-lockdown-options.js index eb7b9d1fc5..53754c69fe 100644 --- a/packages/ses/test/test-lockdown-options.js +++ b/packages/ses/test/test-lockdown-options.js @@ -1,14 +1,14 @@ import test from 'ava'; -import { lockdown } from '../src/lockdown-shim.js'; +import { repairIntrinsics } from '../src/lockdown.js'; -test('lockdown throws with non-recognized options', t => { +test('repairIntrinsics throws with non-recognized options', t => { t.throws( - () => lockdown({ mathTaming: 'unsafe', abc: true }), + () => repairIntrinsics({ mathTaming: 'unsafe', abc: true }), undefined, 'throws with value true', ); t.throws( - () => lockdown({ mathTaming: 'unsafe', abc: false }), + () => repairIntrinsics({ mathTaming: 'unsafe', abc: false }), undefined, 'throws with value false', ); diff --git a/packages/ses/test/test-repair-intrinsics.js b/packages/ses/test/test-repair-intrinsics.js index a12db77a2e..91a97a3120 100644 --- a/packages/ses/test/test-repair-intrinsics.js +++ b/packages/ses/test/test-repair-intrinsics.js @@ -1,13 +1,8 @@ +/// /* global globalThis */ import test from 'ava'; -import '../index.js'; -import { repairIntrinsics } from '../src/lockdown-shim.js'; -import { getAnonymousIntrinsics } from '../src/get-anonymous-intrinsics.js'; -import { - makeCompartmentConstructor, - CompartmentPrototype, -} from '../src/compartment-shim.js'; +import { repairIntrinsics } from '../src/lockdown.js'; // eslint-disable-next-line no-eval if (!eval.toString().includes('native code')) { @@ -26,11 +21,7 @@ test('permitted prototypes - on', t => { Object.prototype.hasOwnProperty.foo = 1; console.time('Benchmark repairIntrinsics()'); - const hardenIntrinsics = repairIntrinsics( - makeCompartmentConstructor, - CompartmentPrototype, - getAnonymousIntrinsics, - ); + const hardenIntrinsics = repairIntrinsics(); console.timeEnd('Benchmark repairIntrinsics()'); console.time('Benchmark hardenIntrinsics()'); diff --git a/packages/ses/types.d.ts b/packages/ses/types.d.ts index c8e119634a..aa5ddae860 100644 --- a/packages/ses/types.d.ts +++ b/packages/ses/types.d.ts @@ -19,7 +19,7 @@ // version of harden. export type Harden = (value: T) => T; // not Hardened; -export interface LockdownOptions { +export interface RepairOptions { regExpTaming?: 'safe' | 'unsafe'; localeTaming?: 'safe' | 'unsafe'; consoleTaming?: 'safe' | 'unsafe'; @@ -36,6 +36,11 @@ export interface LockdownOptions { __hardenTaming__?: 'safe' | 'unsafe'; } +// Deprecated in favor of the more specific RepairOptions +export type LockdownOptions = RepairOptions; + +export type RepairIntrinsics = (options?: LockdownOptions) => void; +export type HardenIntrinsics = () => void; export type Lockdown = (options?: LockdownOptions) => void; export type __LiveExportMap__ = Record; @@ -224,6 +229,8 @@ interface CompartmentEvaluateOptions { declare global { var harden: Harden; + var repairIntrinsics: RepairIntrinsics; + var hardenIntrinsics: HardenIntrinsics; var lockdown: Lockdown; var assert: Assert; From 7addc5c69c723d0d274cc6bc6842f507459543f3 Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Fri, 18 Aug 2023 17:27:39 -0700 Subject: [PATCH 3/4] fix(compartment-mapper): Update stack trace sensitive snapshots --- .../test/snapshots/test-error-handling.js.md | 92 +++--------------- .../snapshots/test-error-handling.js.snap | Bin 923 -> 781 bytes 2 files changed, 16 insertions(+), 76 deletions(-) diff --git a/packages/compartment-mapper/test/snapshots/test-error-handling.js.md b/packages/compartment-mapper/test/snapshots/test-error-handling.js.md index 749c039ea8..21359b73c1 100644 --- a/packages/compartment-mapper/test/snapshots/test-error-handling.js.md +++ b/packages/compartment-mapper/test/snapshots/test-error-handling.js.md @@ -95,14 +95,14 @@ Generated by [AVA](https://avajs.dev). `Error: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/cjs/␊ at Object.execute (file://.../compartment-mapper/src/import-archive.js:…)␊ at execute (file://.../ses/src/module-instance.js:…)␊ - at compartmentImportNow (file://.../ses/src/compartment-shim.js:…)␊ - at Compartment.importNow (file://.../ses/src/compartment-shim.js:…)␊ + at compartmentImportNow (file://.../ses/src/compartment.js:…)␊ + at Compartment.importNow (file://.../ses/src/compartment.js:…)␊ at require (file://.../compartment-mapper/src/parse-cjs-shared-export-wrapper.js:…)␊ at eval (eval at (eval at makeEvaluate (file://.../ses/src/make-evaluate.js:…)), :…)␊ at Object.execute (file://.../compartment-mapper/src/parse-pre-cjs.js:…)␊ at execute (file://.../ses/src/module-instance.js:…)␊ - at compartmentImportNow (file://.../ses/src/compartment-shim.js:…)␊ - at file://.../ses/src/compartment-shim.js:…` + at compartmentImportNow (file://.../ses/src/compartment.js:…)␊ + at file://.../ses/src/compartment.js:…` ## fixtures-error-handling / cjs / makeArchive / parseArchive with a prefix @@ -111,14 +111,14 @@ Generated by [AVA](https://avajs.dev). `Error: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/cjs/␊ at Object.execute (file://.../compartment-mapper/src/import-archive.js:…)␊ at execute (file://.../ses/src/module-instance.js:…)␊ - at compartmentImportNow (file://.../ses/src/compartment-shim.js:…)␊ - at Compartment.importNow (file://.../ses/src/compartment-shim.js:…)␊ + at compartmentImportNow (file://.../ses/src/compartment.js:…)␊ + at Compartment.importNow (file://.../ses/src/compartment.js:…)␊ at require (file://.../compartment-mapper/src/parse-cjs-shared-export-wrapper.js:…)␊ at eval (eval at (eval at makeEvaluate (file://.../ses/src/make-evaluate.js:…)), :…)␊ at Object.execute (file://.../compartment-mapper/src/parse-pre-cjs.js:…)␊ at execute (file://.../ses/src/module-instance.js:…)␊ - at compartmentImportNow (file://.../ses/src/compartment-shim.js:…)␊ - at file://.../ses/src/compartment-shim.js:…` + at compartmentImportNow (file://.../ses/src/compartment.js:…)␊ + at file://.../ses/src/compartment.js:…` ## fixtures-error-handling / cjs / writeArchive / loadArchive @@ -127,14 +127,14 @@ Generated by [AVA](https://avajs.dev). `Error: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/cjs/␊ at Object.execute (file://.../compartment-mapper/src/import-archive.js:…)␊ at execute (file://.../ses/src/module-instance.js:…)␊ - at compartmentImportNow (file://.../ses/src/compartment-shim.js:…)␊ - at Compartment.importNow (file://.../ses/src/compartment-shim.js:…)␊ + at compartmentImportNow (file://.../ses/src/compartment.js:…)␊ + at Compartment.importNow (file://.../ses/src/compartment.js:…)␊ at require (file://.../compartment-mapper/src/parse-cjs-shared-export-wrapper.js:…)␊ at eval (eval at (eval at makeEvaluate (file://.../ses/src/make-evaluate.js:…)), :…)␊ at Object.execute (file://.../compartment-mapper/src/parse-pre-cjs.js:…)␊ at execute (file://.../ses/src/module-instance.js:…)␊ - at compartmentImportNow (file://.../ses/src/compartment-shim.js:…)␊ - at file://.../ses/src/compartment-shim.js:…` + at compartmentImportNow (file://.../ses/src/compartment.js:…)␊ + at file://.../ses/src/compartment.js:…` ## fixtures-error-handling / cjs / writeArchive / importArchive @@ -143,71 +143,11 @@ Generated by [AVA](https://avajs.dev). `Error: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/cjs/␊ at Object.execute (file://.../compartment-mapper/src/import-archive.js:…)␊ at execute (file://.../ses/src/module-instance.js:…)␊ - at compartmentImportNow (file://.../ses/src/compartment-shim.js:…)␊ - at Compartment.importNow (file://.../ses/src/compartment-shim.js:…)␊ + at compartmentImportNow (file://.../ses/src/compartment.js:…)␊ + at Compartment.importNow (file://.../ses/src/compartment.js:…)␊ at require (file://.../compartment-mapper/src/parse-cjs-shared-export-wrapper.js:…)␊ at eval (eval at (eval at makeEvaluate (file://.../ses/src/make-evaluate.js:…)), :…)␊ at Object.execute (file://.../compartment-mapper/src/parse-pre-cjs.js:…)␊ at execute (file://.../ses/src/module-instance.js:…)␊ - at compartmentImportNow (file://.../ses/src/compartment-shim.js:…)␊ - at file://.../ses/src/compartment-shim.js:…` - -## fixtures-error-handling / both / loadLocation - -> Snapshot 1 - - `TypeError: Failed to load module "./main.js" in package "file://.../compartment-mapper/test/fixtures-error-handling/node_modules/both/" (1 underlying failures: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/esm/␊ - at load (file://.../ses/src/module-load.js:…)␊ - at async file://.../compartment-mapper/test/scaffold.js:…␊ - at async file://.../compartment-mapper/test/scaffold.js:…` - - -## fixtures-error-handling / both / makeArchive / parseArchive - -> Snapshot 1 - - `TypeError: Failed to load module "./main.js" in package "file://.../compartment-mapper/test/fixtures-error-handling/node_modules/both/" (1 underlying failures: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/esm/␊ - at load (file://.../ses/src/module-load.js:…)␊ - at async digestLocation (file://.../compartment-mapper/src/archive.js:…)␊ - at async makeAndHashArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async makeArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async file://.../compartment-mapper/test/scaffold.js:…␊ - at async file://.../compartment-mapper/test/scaffold.js:…` - -## fixtures-error-handling / both / makeArchive / parseArchive with a prefix - -> Snapshot 1 - - `TypeError: Failed to load module "./main.js" in package "file://.../compartment-mapper/test/fixtures-error-handling/node_modules/both/" (1 underlying failures: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/esm/␊ - at load (file://.../ses/src/module-load.js:…)␊ - at async digestLocation (file://.../compartment-mapper/src/archive.js:…)␊ - at async makeAndHashArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async makeArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async file://.../compartment-mapper/test/scaffold.js:…␊ - at async file://.../compartment-mapper/test/scaffold.js:…` - -## fixtures-error-handling / both / writeArchive / loadArchive - -> Snapshot 1 - - `TypeError: Failed to load module "./main.js" in package "file://.../compartment-mapper/test/fixtures-error-handling/node_modules/both/" (1 underlying failures: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/esm/␊ - at load (file://.../ses/src/module-load.js:…)␊ - at async digestLocation (file://.../compartment-mapper/src/archive.js:…)␊ - at async makeAndHashArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async makeArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async writeArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async file://.../compartment-mapper/test/scaffold.js:…␊ - at async file://.../compartment-mapper/test/scaffold.js:…` - -## fixtures-error-handling / both / writeArchive / importArchive - -> Snapshot 1 - - `TypeError: Failed to load module "./main.js" in package "file://.../compartment-mapper/test/fixtures-error-handling/node_modules/both/" (1 underlying failures: Cannot find external module "missing" in package file://.../compartment-mapper/test/fixtures-error-handling/node_modules/esm/␊ - at load (file://.../ses/src/module-load.js:…)␊ - at async digestLocation (file://.../compartment-mapper/src/archive.js:…)␊ - at async makeAndHashArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async makeArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async writeArchive (file://.../compartment-mapper/src/archive.js:…)␊ - at async file://.../compartment-mapper/test/scaffold.js:…␊ - at async file://.../compartment-mapper/test/scaffold.js:…` + at compartmentImportNow (file://.../ses/src/compartment.js:…)␊ + at file://.../ses/src/compartment.js:…` diff --git a/packages/compartment-mapper/test/snapshots/test-error-handling.js.snap b/packages/compartment-mapper/test/snapshots/test-error-handling.js.snap index ec130441ab87edd03f025aa4259b6898955ea42d..1ba5b1f98c7b74cf5cb24249ccfbc68102285f49 100644 GIT binary patch literal 781 zcmV+o1M>VqRzVY00000000B+n9qyTKorOO0}=G(RS<@ry3izeEsL-$D-}d9f_Rd*$xAbB zG81Pe+xDjS{U_Fge}?~o;C~?ampDn9wb}kiTB}{z$ssh!oA11N?|mleyYkON?vCZ< zXH-;$IPLj#suF?HLLs=Y0$^T9*^oE{Wu(s`2k#|!K~c`AWDv`MEBWcl^FYD7=8tyc zej`1a_Zp8{-7lXPI8oC0H9 z5uY-T;8dYt5MFy0Q7N@~$*+C7^?>LDR347*g0j>GQn*fTY^Be2eEL5>emN?}fSfV6 zjyKW;-{)Z=@TcR8Ij2K4trBy1#{};I9ErH9w{|#~mIfLAe$ZhDw zxFcEJi|LgRd(xcab+A&_PG6UDzC8>$AJ<7xZfynHe07r2NW9e_!aPygDo@fSF4y`7 zUTQQp@}O5XHcZ%e2>XWbxjgLKbP3vVDFx8JO(}SNK0;U7I7K&6wYH~u8rJMmtAuU@ zoHD6^xl2PA=6jLN@rqAY>MR)E)Hq#uM0XVt_#vU9Rxq;6TRNbY3_ze~;WUfRL}WHg z(Yeqm?q+9wbqtKNS;Q0h?Dx&Ivd;AH1lC1S8(28EC?+`SEvl8~+&;tkqV!+*bYZtF z!L_VwG%~6%u4-f$s14Kx>O(+X`EK5-*J3a>7#oZafboV7&Pt4{IyeSo1F`}6AAIT4$KX10N~mE= zWzMQotsjdB00000000B+nn7>VFcinvRtO2Wa0MY*J8e>v2##eSP1DdOA>e?7I8AQi zEM5~k*v{JCK;jed4aR|w0iOT_p8&)s!AY8}S<^b%ijsBip<3GK=jZqSzc_pKiQD(7 zJ>Z`{BY}mFMqL+=M8ps`5Mz`X9wd&B$sw=+;(>hkDRiDw8wyMb<^+b^qk?}paU3Y% z+t%;S+Re52)w;2ExBavAdK{wN*i#QYgV;w75H#@t0_sFQ0_&y~KupXdz78+}A+!hZ zP=4%6JQvq8!@33J3yL%y8&jUSG~mp(Qez|jUgoFw z_x+d6Yz*XMVwZ`A+t78XpEL*Ip?-l~MvYK-R@&wpPvmRE>iV<%}7`IUfbl#V%o5xng%orHQi#xtA4uDK3}ft3F2dF3t!T zV&MS@LWZOhO^hbyS`ee$RfY_UDP-b`&D~Wx_i~Kf?r26dBg^uY6XMkcZmS}2>GQuv zP9vw0yC8B4dNKA9SNCGNIm8~cCV15*Wf}CTl+)Y89;Jga1xl?APns7ODbBNKeYFZ)Nx7A6`YI})XC zPm?mtxl0u}I+t)vxPZi-89FuJelo`kIxO@v9T@j;aNg0*+4m;ClqZJXMVOUJOQHco zrdB$F3^@iGC3zaM#AYT>$FkTP$-BJTf`pQBKqLP2?88`NyYlY{&daAXFwn#zn_#m$ z?JYNF^;)NklK;%d3u|Jj%MU5h+)$ydYHn!IHRu}jrhu;8!z=Y+n5h`pUUTNWuxg&j^g|AB519tPUkBauVW6RpeCtCk>s3PD58b{vStgJuDP90004{vvmLf From 76787e7765fe3cc38a2dc9ffa07fa9119702258f Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Mon, 21 Aug 2023 13:11:44 -0700 Subject: [PATCH 4/4] docs(ses): Document vetted shims --- packages/ses/NEWS.md | 35 ++++++----- packages/ses/docs/guide.md | 104 +++++++++++++++++++++++++++++---- packages/ses/docs/reference.md | 23 ++++++++ 3 files changed, 138 insertions(+), 24 deletions(-) diff --git a/packages/ses/NEWS.md b/packages/ses/NEWS.md index 2f67762874..7041eff19e 100644 --- a/packages/ses/NEWS.md +++ b/packages/ses/NEWS.md @@ -2,21 +2,28 @@ User-visible changes in SES: # Next release +- Extracts `repairIntrinsics(options)` and `hardenIntrinsics()` from the + behavior of `lockdown(options)` so vetted shims can run between these + calls. + Any modifications to shared intrinsics survive if applied after + `repairIntrinsics()`. - In the SES-shim implementation of HardenedJS, all constructed compartments -get the same safe `Date` -constructor, that does not provide the ability to measure duration. It used -to do this by having `Date.now()` return `NaN`, and to have calls on the -constructor that would normally have returned an indication of the current date, -instead return the corresponding invalid date indication. Now, all of these -throw a `TypeError` whose message begins with `'secure mode'`. This aligns with -the XS implementation of HardenedJS. -- Similarly, In the SES-shim implementation of HardenedJS, -all constructed compartments get the same safe `Math` namespace -object that does not provide a working `random()` function. It used to do that -by omitting the `random` property from the safe `Math` namespace object. Now, -the safe shared `Math` namespace object has a `Math.random()` function that -throws a `TypeError whose message begins with `'secure mode'`. This again -aligns with the XS implementation of HardenedJS. + get the same safe `Date` constructor, that does not provide the ability to + measure duration. + It used to do this by having `Date.now()` return `NaN`, and to have calls on + the constructor that would normally have returned an indication of the + current date, instead return the corresponding invalid date indication. + Now, all of these throw a `TypeError` whose message begins with `'secure + mode'`. + This aligns with the XS implementation of HardenedJS. +- Similarly, In the SES-shim implementation of HardenedJS, all constructed + compartments get the same safe `Math` namespace object that does not provide + a working `random()` function. + It used to do that by omitting the `random` property from the safe `Math` + namespace object. + Now, the safe shared `Math` namespace object has a `Math.random()` function + that throws a `TypeError whose message begins with `'secure mode'`. + This again aligns with the XS implementation of HardenedJS. # v0.18.6 (2023-08-07) diff --git a/packages/ses/docs/guide.md b/packages/ses/docs/guide.md index c77377c274..4d50f40de8 100644 --- a/packages/ses/docs/guide.md +++ b/packages/ses/docs/guide.md @@ -28,7 +28,7 @@ Hardened JavaScript: - Removes non-determinism by modifying a few built-in objects. - Adds functionality to freeze and make immutable both built-in JavaScript objects and program created objects and make them immutable. -- Is (as SES) is a proposed extension to the JavaScript standard. +- Is (tentatively named SES) a proposed extension to the JavaScript standard. Hardened JavaScript consists of three parts: - Lockdown is a function that irreversibly repairs and hardens an existing @@ -39,6 +39,12 @@ Hardened JavaScript consists of three parts: globals and modules, but shared hardened primordials and limited access to other powerful objects in global scope. +Lockdown consists of separable Repair Intrinsics and Harden Intrinsics phases, +so that shims (other programs that alter JavaScript) may run between them. +These shims are obliged to maintain the object capability safety invariants +provided by Lockdown and must be carefully reviewed. +We call these "vetted shims". + ## What is SES? SES is an old umbrella term for the Hardened JavaScript effort, and while we @@ -143,6 +149,53 @@ To use SES as a script on the web, use the UMD build.