diff --git a/packages/ses/index.js b/packages/ses/index.js index c64c1696b9..9e4860eaed 100644 --- a/packages/ses/index.js +++ b/packages/ses/index.js @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { globalThis, Error, assign } from './src/commons.js'; +import { globalThis, TypeError, assign } from './src/commons.js'; import { tameFunctionToString } from './src/tame-function-tostring.js'; import { getGlobalIntrinsics } from './src/intrinsics.js'; import { getAnonymousIntrinsics } from './src/get-anonymous-intrinsics.js'; @@ -29,7 +29,7 @@ function getThis() { } if (getThis()) { - throw new Error(`SES failed to initialize, sloppy mode (SES_NO_SLOPPY)`); + throw new TypeError(`SES failed to initialize, sloppy mode (SES_NO_SLOPPY)`); } const markVirtualizedNativeFunction = tameFunctionToString(); diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index d4d69d599b..a8c40e90e2 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -28,7 +28,7 @@ export const { Promise, Proxy, Reflect, - RegExp, + RegExp: FERAL_REG_EXP, Set, String, WeakMap, @@ -36,7 +36,10 @@ export const { } = globalThis; export const { - Error, + // The feral Error constructor is safe for internal use, but must not be + // revealed to post-lockdown code in any compartment including the start + // compartment since in V8 at least it bears stack inspection capabilities. + Error: FERAL_ERROR, RangeError, ReferenceError, SyntaxError, diff --git a/packages/ses/src/compartment-shim.js b/packages/ses/src/compartment-shim.js index bc06d20998..657fd11081 100644 --- a/packages/ses/src/compartment-shim.js +++ b/packages/ses/src/compartment-shim.js @@ -3,7 +3,6 @@ /// import { - Error, Map, ReferenceError, TypeError, @@ -265,7 +264,7 @@ export const makeCompartmentConstructor = ( identifier => !isValidIdentifierName(identifier), ); if (invalidNames.length) { - throw new Error( + throw new TypeError( `Cannot create compartment with invalid names for global lexicals: ${arrayJoin( invalidNames, ', ', diff --git a/packages/ses/src/enable-property-overrides.js b/packages/ses/src/enable-property-overrides.js index 1a3bbdce97..c9b4689555 100644 --- a/packages/ses/src/enable-property-overrides.js +++ b/packages/ses/src/enable-property-overrides.js @@ -4,7 +4,6 @@ // @ts-check import { - Error, Set, String, TypeError, @@ -114,7 +113,7 @@ export default function enablePropertyOverrides( } else { if (isDebug) { // eslint-disable-next-line @endo/no-polymorphic-call - console.error(new Error(`Override property ${prop}`)); + console.error(new TypeError(`Override property ${prop}`)); } defineProperty(this, prop, { value: newValue, @@ -196,7 +195,7 @@ export default function enablePropertyOverrides( break; } default: { - throw new Error(`unrecognized overrideTaming ${overrideTaming}`); + throw new TypeError(`unrecognized overrideTaming ${overrideTaming}`); } } diff --git a/packages/ses/src/error/assert.js b/packages/ses/src/error/assert.js index e9c58308b8..a6d9e9c8cc 100644 --- a/packages/ses/src/error/assert.js +++ b/packages/ses/src/error/assert.js @@ -12,7 +12,7 @@ // module should not be observably impure. import { - Error, + FERAL_ERROR, RangeError, TypeError, WeakMap, @@ -85,7 +85,7 @@ const getMessageString = ({ template, args }) => { let argStr; if (weakmapHas(declassifiers, arg)) { argStr = `${arg}`; - } else if (arg instanceof Error) { + } else if (arg instanceof FERAL_ERROR) { argStr = `(${an(arg.name)})`; } else { argStr = `(${an(typeof arg)})`; @@ -226,7 +226,7 @@ const tagError = (err, optErrorName = err.name) => { */ const makeError = ( optDetails = redactedDetails`Assert failed`, - ErrorConstructor = Error, + ErrorConstructor = FERAL_ERROR, { errorName = undefined } = {}, ) => { if (typeof optDetails === 'string') { @@ -236,7 +236,7 @@ const makeError = ( } const hiddenDetails = weakmapGet(hiddenDetailsMap, optDetails); if (hiddenDetails === undefined) { - throw new Error(`unrecognized details ${quote(optDetails)}`); + throw new TypeError(`unrecognized details ${quote(optDetails)}`); } const messageString = getMessageString(hiddenDetails); const error = new ErrorConstructor(messageString); @@ -286,7 +286,7 @@ const note = (error, detailsNote) => { } const hiddenDetails = weakmapGet(hiddenDetailsMap, detailsNote); if (hiddenDetails === undefined) { - throw new Error(`unrecognized details ${quote(detailsNote)}`); + throw new TypeError(`unrecognized details ${quote(detailsNote)}`); } const logArgs = getLogArgs(hiddenDetails); const callbacks = weakmapGet(hiddenNoteCallbackArrays, error); @@ -365,7 +365,7 @@ const makeAssert = (optRaise = undefined, unredacted = false) => { /** @type {AssertFail} */ const fail = ( optDetails = details`Assert failed`, - ErrorConstructor = Error, + ErrorConstructor = FERAL_ERROR, ) => { const reason = makeError(optDetails, ErrorConstructor); if (optRaise !== undefined) { @@ -382,7 +382,7 @@ const makeAssert = (optRaise = undefined, unredacted = false) => { function baseAssert( flag, optDetails = details`Check failed`, - ErrorConstructor = Error, + ErrorConstructor = FERAL_ERROR, ) { if (!flag) { throw fail(optDetails, ErrorConstructor); diff --git a/packages/ses/src/error/console.js b/packages/ses/src/error/console.js index 3155f97004..40c3fc08c5 100644 --- a/packages/ses/src/error/console.js +++ b/packages/ses/src/error/console.js @@ -6,7 +6,7 @@ // normally commented out. import { - Error, + FERAL_ERROR, WeakSet, arrayFilter, arrayMap, @@ -197,7 +197,7 @@ const makeCausalConsole = (baseConsole, loggedErrorHandler) => { */ const extractErrorArgs = (logArgs, subErrorsSink) => { const argTags = arrayMap(logArgs, arg => { - if (arg instanceof Error) { + if (arg instanceof FERAL_ERROR) { arrayPush(subErrorsSink, arg); return `(${tagError(arg)})`; } diff --git a/packages/ses/src/error/stringify-utils.js b/packages/ses/src/error/stringify-utils.js index 97e9d7b597..86c12b19a5 100644 --- a/packages/ses/src/error/stringify-utils.js +++ b/packages/ses/src/error/stringify-utils.js @@ -1,7 +1,7 @@ // @ts-check import { - Error, + FERAL_ERROR, Set, String, freeze, @@ -70,7 +70,7 @@ const bestEffortStringify = (payload, spaces = undefined) => { return '[Seen]'; } setAdd(seenSet, val); - if (val instanceof Error) { + if (val instanceof FERAL_ERROR) { return `[${val.name}: ${val.message}]`; } if (toStringTagSymbol in val) { diff --git a/packages/ses/src/error/tame-console.js b/packages/ses/src/error/tame-console.js index a884a49fdd..eca3e2995f 100644 --- a/packages/ses/src/error/tame-console.js +++ b/packages/ses/src/error/tame-console.js @@ -1,6 +1,6 @@ // @ts-check -import { Error, globalThis } from '../commons.js'; +import { TypeError, globalThis } from '../commons.js'; import { loggedErrorHandler as defaultHandler } from './assert.js'; import { makeCausalConsole } from './console.js'; import './types.js'; @@ -25,7 +25,7 @@ export const tameConsole = ( optGetStackString = undefined, ) => { if (consoleTaming !== 'safe' && consoleTaming !== 'unsafe') { - throw new Error(`unrecognized consoleTaming ${consoleTaming}`); + throw new TypeError(`unrecognized consoleTaming ${consoleTaming}`); } if (consoleTaming === 'unsafe') { diff --git a/packages/ses/src/error/tame-error-constructor.js b/packages/ses/src/error/tame-error-constructor.js index 57a915b077..bd3c8ac597 100644 --- a/packages/ses/src/error/tame-error-constructor.js +++ b/packages/ses/src/error/tame-error-constructor.js @@ -1,5 +1,6 @@ import { - Error, + FERAL_ERROR, + TypeError, apply, construct, defineProperties, @@ -11,7 +12,7 @@ import { tameV8ErrorConstructor } from './tame-v8-error-constructor.js'; // Present on at least FF. Proposed by Error-proposal. Not on SES whitelist // so grab it before it is removed. -const stackDesc = getOwnPropertyDescriptor(Error.prototype, 'stack'); +const stackDesc = getOwnPropertyDescriptor(FERAL_ERROR.prototype, 'stack'); const stackGetter = stackDesc && stackDesc.get; // Use concise methods to obtain named functions without constructors. @@ -32,30 +33,29 @@ export default function tameErrorConstructor( stackFiltering = 'concise', ) { if (errorTaming !== 'safe' && errorTaming !== 'unsafe') { - throw new Error(`unrecognized errorTaming ${errorTaming}`); + throw new TypeError(`unrecognized errorTaming ${errorTaming}`); } if (stackFiltering !== 'concise' && stackFiltering !== 'verbose') { - throw new Error(`unrecognized stackFiltering ${stackFiltering}`); + throw new TypeError(`unrecognized stackFiltering ${stackFiltering}`); } - const OriginalError = Error; - const ErrorPrototype = OriginalError.prototype; + const ErrorPrototype = FERAL_ERROR.prototype; const platform = - typeof OriginalError.captureStackTrace === 'function' ? 'v8' : 'unknown'; - const { captureStackTrace: originalCaptureStackTrace } = OriginalError; + typeof FERAL_ERROR.captureStackTrace === 'function' ? 'v8' : 'unknown'; + const { captureStackTrace: originalCaptureStackTrace } = FERAL_ERROR; const makeErrorConstructor = (_ = {}) => { // eslint-disable-next-line no-shadow const ResultError = function Error(...rest) { let error; if (new.target === undefined) { - error = apply(OriginalError, this, rest); + error = apply(FERAL_ERROR, this, rest); } else { - error = construct(OriginalError, rest, new.target); + error = construct(FERAL_ERROR, rest, new.target); } if (platform === 'v8') { // TODO Likely expensive! - apply(originalCaptureStackTrace, OriginalError, [error, ResultError]); + apply(originalCaptureStackTrace, FERAL_ERROR, [error, ResultError]); } return error; }; @@ -100,9 +100,9 @@ export default function tameErrorConstructor( defineProperties(InitialError, { stackTraceLimit: { get() { - if (typeof OriginalError.stackTraceLimit === 'number') { - // OriginalError.stackTraceLimit is only on v8 - return OriginalError.stackTraceLimit; + if (typeof FERAL_ERROR.stackTraceLimit === 'number') { + // FERAL_ERROR.stackTraceLimit is only on v8 + return FERAL_ERROR.stackTraceLimit; } return undefined; }, @@ -114,9 +114,9 @@ export default function tameErrorConstructor( // harmless seems the safer option. return; } - if (typeof OriginalError.stackTraceLimit === 'number') { - // OriginalError.stackTraceLimit is only on v8 - OriginalError.stackTraceLimit = newLimit; + if (typeof FERAL_ERROR.stackTraceLimit === 'number') { + // FERAL_ERROR.stackTraceLimit is only on v8 + FERAL_ERROR.stackTraceLimit = newLimit; // We place the useless return on the next line to ensure // that anything we place after the if in the future only // happens if the then-case does not. @@ -149,7 +149,7 @@ export default function tameErrorConstructor( let initialGetStackString = tamedMethods.getStackString; if (platform === 'v8') { initialGetStackString = tameV8ErrorConstructor( - OriginalError, + FERAL_ERROR, InitialError, errorTaming, stackFiltering, diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 7558892957..736769d860 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -2,7 +2,7 @@ import { FERAL_FUNCTION, Float32Array, Map, - RegExp, + FERAL_REG_EXP, Set, String, getOwnPropertyDescriptor, @@ -57,7 +57,7 @@ export const getAnonymousIntrinsics = () => { // 21.2.7.1 The %RegExpStringIteratorPrototype% Object const RegExpStringIterator = - regexpPrototype[matchAllSymbol] && matchAllRegExp(new RegExp()); + regexpPrototype[matchAllSymbol] && matchAllRegExp(new FERAL_REG_EXP()); const RegExpStringIteratorPrototype = RegExpStringIterator && getPrototypeOf(RegExpStringIterator); diff --git a/packages/ses/src/get-source-url.js b/packages/ses/src/get-source-url.js index b29a7ef67d..70cbaec786 100644 --- a/packages/ses/src/get-source-url.js +++ b/packages/ses/src/get-source-url.js @@ -1,4 +1,4 @@ -import { RegExp, regexpExec, stringSlice } from './commons.js'; +import { FERAL_REG_EXP, regexpExec, stringSlice } from './commons.js'; // Captures a key and value of the form #key=value or @key=value const sourceMetaEntryRegExp = @@ -9,7 +9,7 @@ const sourceMetaEntryRegExp = // On account of the mechanics of regular expressions, scanning from the end // does not allow us to capture every pair, so getSourceURL must capture and // trim until there are no matching comments. -const sourceMetaEntriesRegExp = new RegExp( +const sourceMetaEntriesRegExp = new FERAL_REG_EXP( `(?:\\s*//${sourceMetaEntryRegExp}|/\\*${sourceMetaEntryRegExp}\\s*\\*/)\\s*$`, ); diff --git a/packages/ses/src/intrinsics.js b/packages/ses/src/intrinsics.js index 70d4ff78b2..a274824f91 100644 --- a/packages/ses/src/intrinsics.js +++ b/packages/ses/src/intrinsics.js @@ -1,6 +1,6 @@ import { - Error, Object, + TypeError, WeakSet, arrayFilter, defineProperty, @@ -41,7 +41,7 @@ function initProperty(obj, name, desc) { preDesc.enumerable !== desc.enumerable || preDesc.configurable !== desc.configurable ) { - throw new Error(`Conflicting definitions of ${name}`); + throw new TypeError(`Conflicting definitions of ${name}`); } } defineProperty(obj, name, desc); @@ -93,22 +93,22 @@ export const makeIntrinsicsCollector = () => { } const permit = whitelist[name]; if (typeof permit !== 'object') { - throw new Error(`Expected permit object at whitelist.${name}`); + throw new TypeError(`Expected permit object at whitelist.${name}`); } const namePrototype = permit.prototype; if (!namePrototype) { - throw new Error(`${name}.prototype property not whitelisted`); + throw new TypeError(`${name}.prototype property not whitelisted`); } if ( typeof namePrototype !== 'string' || !objectHasOwnProperty(whitelist, namePrototype) ) { - throw new Error(`Unrecognized ${name}.prototype whitelist entry`); + throw new TypeError(`Unrecognized ${name}.prototype whitelist entry`); } const intrinsicPrototype = intrinsic.prototype; if (objectHasOwnProperty(intrinsics, namePrototype)) { if (intrinsics[namePrototype] !== intrinsicPrototype) { - throw new Error(`Conflicting bindings of ${namePrototype}`); + throw new TypeError(`Conflicting bindings of ${namePrototype}`); } // eslint-disable-next-line no-continue continue; @@ -127,7 +127,7 @@ export const makeIntrinsicsCollector = () => { const isPseudoNative = obj => { if (!pseudoNatives) { - throw new Error( + throw new TypeError( 'isPseudoNative can only be called after finalIntrinsics', ); } diff --git a/packages/ses/src/module-instance.js b/packages/ses/src/module-instance.js index 509de48a9a..411a75b21c 100644 --- a/packages/ses/src/module-instance.js +++ b/packages/ses/src/module-instance.js @@ -1,7 +1,6 @@ import { assert } from './error/assert.js'; import { getDeferredExports } from './module-proxy.js'; import { - Error, ReferenceError, SyntaxError, TypeError, @@ -175,7 +174,7 @@ export const makeModuleInstance = ( // init with initValue of a declared const binding, and return // it. if (!tdz) { - throw new Error( + throw new TypeError( `Internal: binding ${q(localName)} already initialized`, ); } diff --git a/packages/ses/src/module-link.js b/packages/ses/src/module-link.js index c29c24c343..ab30cfae1d 100644 --- a/packages/ses/src/module-link.js +++ b/packages/ses/src/module-link.js @@ -14,9 +14,9 @@ import { makeThirdPartyModuleInstance, } from './module-instance.js'; import { - Error, Map, ReferenceError, + TypeError, entries, isArray, isObject, @@ -163,7 +163,7 @@ export const instantiate = ( resolvedImports, ); } else { - throw new Error( + throw new TypeError( `importHook must return a static module record, got ${q( staticModuleRecord, )}`, diff --git a/packages/ses/src/scope-handler.js b/packages/ses/src/scope-handler.js index 97c557fff1..22d29d5aa2 100644 --- a/packages/ses/src/scope-handler.js +++ b/packages/ses/src/scope-handler.js @@ -1,8 +1,8 @@ import { - Error, FERAL_EVAL, Proxy, String, + TypeError, create, freeze, getOwnPropertyDescriptor, @@ -178,7 +178,7 @@ export const createScopeHandler = ( // eslint-disable-next-line @endo/no-polymorphic-call console.warn( `getOwnPropertyDescriptor trap on scopeHandler for ${quotedProp}`, - new Error().stack, + new TypeError().stack, ); return undefined; }, diff --git a/packages/ses/src/tame-date-constructor.js b/packages/ses/src/tame-date-constructor.js index 52ab49d7b0..acc2d0d61b 100644 --- a/packages/ses/src/tame-date-constructor.js +++ b/packages/ses/src/tame-date-constructor.js @@ -1,10 +1,16 @@ // @ts-check -import { Error, Date, apply, construct, defineProperties } from './commons.js'; +import { + Date, + TypeError, + apply, + construct, + defineProperties, +} from './commons.js'; export default function tameDateConstructor(dateTaming = 'safe') { if (dateTaming !== 'safe' && dateTaming !== 'unsafe') { - throw new Error(`unrecognized dateTaming ${dateTaming}`); + throw new TypeError(`unrecognized dateTaming ${dateTaming}`); } const OriginalDate = Date; const DatePrototype = OriginalDate.prototype; diff --git a/packages/ses/src/tame-locale-methods.js b/packages/ses/src/tame-locale-methods.js index 17c17c557d..dba175949d 100644 --- a/packages/ses/src/tame-locale-methods.js +++ b/packages/ses/src/tame-locale-methods.js @@ -1,5 +1,4 @@ import { - Error, Object, String, TypeError, @@ -40,7 +39,7 @@ const nonLocaleCompare = tamedMethods.localeCompare; export default function tameLocaleMethods(intrinsics, localeTaming = 'safe') { if (localeTaming !== 'safe' && localeTaming !== 'unsafe') { - throw new Error(`unrecognized dateTaming ${localeTaming}`); + throw new TypeError(`unrecognized dateTaming ${localeTaming}`); } if (localeTaming === 'unsafe') { return; diff --git a/packages/ses/src/tame-math-object.js b/packages/ses/src/tame-math-object.js index 7020d32363..562f92ac0d 100644 --- a/packages/ses/src/tame-math-object.js +++ b/packages/ses/src/tame-math-object.js @@ -1,6 +1,6 @@ import { - Error, Math, + TypeError, create, getOwnPropertyDescriptors, objectPrototype, @@ -8,7 +8,7 @@ import { export default function tameMathObject(mathTaming = 'safe') { if (mathTaming !== 'safe' && mathTaming !== 'unsafe') { - throw new Error(`unrecognized mathTaming ${mathTaming}`); + throw new TypeError(`unrecognized mathTaming ${mathTaming}`); } const originalMath = Math; const initialMath = originalMath; // to follow the naming pattern diff --git a/packages/ses/src/tame-regexp-constructor.js b/packages/ses/src/tame-regexp-constructor.js index 9e66444469..5659cbba62 100644 --- a/packages/ses/src/tame-regexp-constructor.js +++ b/packages/ses/src/tame-regexp-constructor.js @@ -1,6 +1,6 @@ import { - Error, - RegExp as OriginalRegExp, + FERAL_REG_EXP, + TypeError, construct, defineProperties, getOwnPropertyDescriptor, @@ -9,17 +9,17 @@ import { export default function tameRegExpConstructor(regExpTaming = 'safe') { if (regExpTaming !== 'safe' && regExpTaming !== 'unsafe') { - throw new Error(`unrecognized regExpTaming ${regExpTaming}`); + throw new TypeError(`unrecognized regExpTaming ${regExpTaming}`); } - const RegExpPrototype = OriginalRegExp.prototype; + const RegExpPrototype = FERAL_REG_EXP.prototype; const makeRegExpConstructor = (_ = {}) => { // RegExp has non-writable static properties we need to omit. const ResultRegExp = function RegExp(...rest) { if (new.target === undefined) { - return OriginalRegExp(...rest); + return FERAL_REG_EXP(...rest); } - return construct(OriginalRegExp, rest, new.target); + return construct(FERAL_REG_EXP, rest, new.target); }; defineProperties(ResultRegExp, { @@ -30,7 +30,7 @@ export default function tameRegExpConstructor(regExpTaming = 'safe') { enumerable: false, configurable: false, }, - [speciesSymbol]: getOwnPropertyDescriptor(OriginalRegExp, speciesSymbol), + [speciesSymbol]: getOwnPropertyDescriptor(FERAL_REG_EXP, speciesSymbol), }); return ResultRegExp; }; diff --git a/packages/ses/src/transforms.js b/packages/ses/src/transforms.js index 308969682f..eed4ed57e9 100644 --- a/packages/ses/src/transforms.js +++ b/packages/ses/src/transforms.js @@ -1,7 +1,7 @@ // @ts-check import { - RegExp, + FERAL_REG_EXP, SyntaxError, stringReplace, stringSearch, @@ -34,7 +34,7 @@ function getLineNumber(src, pattern) { // ///////////////////////////////////////////////////////////////////////////// -const htmlCommentPattern = new RegExp(`(?:${'<'}!--|--${'>'})`, 'g'); +const htmlCommentPattern = new FERAL_REG_EXP(`(?:${'<'}!--|--${'>'})`, 'g'); /** * Conservatively reject the source text if it may contain text that some @@ -103,7 +103,10 @@ export const evadeHtmlCommentTest = src => { // ///////////////////////////////////////////////////////////////////////////// -const importPattern = new RegExp('(^|[^.])\\bimport(\\s*(?:\\(|/[/*]))', 'g'); +const importPattern = new FERAL_REG_EXP( + '(^|[^.])\\bimport(\\s*(?:\\(|/[/*]))', + 'g', +); /** * Conservatively reject the source text if it may contain a dynamic @@ -169,7 +172,10 @@ export const evadeImportExpressionTest = src => { // ///////////////////////////////////////////////////////////////////////////// -const someDirectEvalPattern = new RegExp('(^|[^.])\\beval(\\s*\\()', 'g'); +const someDirectEvalPattern = new FERAL_REG_EXP( + '(^|[^.])\\beval(\\s*\\()', + 'g', +); /** * Heuristically reject some text that seems to contain a direct eval diff --git a/packages/ses/src/whitelist-intrinsics.js b/packages/ses/src/whitelist-intrinsics.js index 6317d937dc..4eabb9e77b 100644 --- a/packages/ses/src/whitelist-intrinsics.js +++ b/packages/ses/src/whitelist-intrinsics.js @@ -45,7 +45,6 @@ import { whitelist, FunctionInstance, isAccessorPermit } from './whitelist.js'; import { - Error, String, TypeError, arrayIncludes, @@ -116,7 +115,9 @@ export default function whitelistIntrinsics( } // We can't clean [[prototype]], therefore abort. - throw new Error(`Unexpected intrinsic ${path}.__proto__ at ${protoName}`); + throw new TypeError( + `Unexpected intrinsic ${path}.__proto__ at ${protoName}`, + ); } /*