Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ses

Package Overview
Dependencies
Maintainers
5
Versions
105
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ses - npm Package Compare versions

Comparing version 0.14.3 to 0.14.4

src/make-safe-evaluator.js

16

CHANGELOG.md

@@ -6,2 +6,18 @@ # Change Log

### [0.14.4](https://github.com/endojs/endo/compare/ses@0.14.3...ses@0.14.4) (2021-10-15)
### Features
* **ses:** lazily create evaluate ([f1cf92a](https://github.com/endojs/endo/commit/f1cf92a3b8e23aab3894f8431d8b65b4f75daa77))
### Bug Fixes
* **ses:** Add test and warning about the `has` hazard ([9066c97](https://github.com/endojs/endo/commit/9066c97b41b35a4e37fd12256a0802fb656af755))
* **ses:** more detailed `has` hazard test ([f010a9e](https://github.com/endojs/endo/commit/f010a9ebe09dadc72a8f22bd54caed8aa3787243))
* **ses:** Refactor Compartment to use shared evaluator ([dc0bad6](https://github.com/endojs/endo/commit/dc0bad6c1f963ff379e45f320852218228203050))
### [0.14.3](https://github.com/endojs/endo/compare/ses@0.14.2...ses@0.14.3) (2021-09-18)

@@ -8,0 +24,0 @@

16

NEWS.md
User-visible changes in SES:
# 0.14.4 (2021-10-14)
- Fixes a defect in the per-compartment `Function` and `eval` functions, such
that these environments did not have the compartment's `globalLexicals`.
There is no known environment depending on this invariant for security
reasons, but such a scenario would be a program arranging a translator that
introduces run-time security checks, like metering, that depend on the
existence of a named global lexical.
[#898](https://github.com/endojs/endo/issues/898)
- The above fix incidentally improved the performance of compartment evaluation
for cases that do not require special global lexicals, by sharing a single
per-compartment evaluator.
# 0.14.3 (2021-09-18)
- Due to a peculiar bit of error handling code in Node 14, as explained at
[Hardened JavaScript interferes with Node.js 14 Error construction](https://github.com/endojs/endo/issues/868),
[Hardened JavaScript interferes with Node.js 14 Error
construction](https://github.com/endojs/endo/issues/868),
we have added more overrides to the default `overrideTaming: 'moderate'`

@@ -8,0 +22,0 @@ setting. At this setting, assigning to the `name` property of a mutable error

12

package.json
{
"name": "ses",
"version": "0.14.3",
"version": "0.14.4",
"description": "Hardened JavaScript for Fearless Cooperation",

@@ -62,6 +62,6 @@ "keywords": [

"devDependencies": {
"@endo/compartment-mapper": "^0.5.3",
"@endo/eslint-config": "^0.3.15",
"@endo/static-module-record": "^0.6.3",
"@endo/test262-runner": "^0.1.9",
"@endo/compartment-mapper": "^0.5.4",
"@endo/eslint-config": "^0.3.16",
"@endo/static-module-record": "^0.6.4",
"@endo/test262-runner": "^0.1.10",
"ava": "^3.12.1",

@@ -183,3 +183,3 @@ "babel-eslint": "^10.0.3",

},
"gitHead": "619005298bde41e3013b8d704db543c0888a239f"
"gitHead": "e92151ee140769c4de6d8e8533cf9abaac6781e9"
}

@@ -14,4 +14,56 @@ /// <reference types="ses">

} from './transforms.js';
import { performEval } from './evaluate.js';
import { makeSafeEvaluator } from './make-safe-evaluator.js';
export const provideCompartmentEvaluator = (compartmentFields, options) => {
const {
sloppyGlobalsMode = false,
__moduleShimLexicals__ = undefined,
} = options;
let safeEvaluate;
if (__moduleShimLexicals__ === undefined && !sloppyGlobalsMode) {
({ safeEvaluate } = compartmentFields);
} else {
// The scope proxy or global lexicals are different from the
// shared evaluator so we need to build a new one
let { globalTransforms } = compartmentFields;
const {
globalObject,
globalLexicals,
knownScopeProxies,
} = compartmentFields;
let localObject = globalLexicals;
if (__moduleShimLexicals__ !== undefined) {
// When using `evaluate` for ESM modules, as should only occur from the
// module-shim's module-instance.js, we do not reveal the SES-shim's
// module-to-program translation, as this is not standardizable behavior.
// However, the `localTransforms` will come from the `__shimTransforms__`
// Compartment option in this case, which is a non-standardizable escape
// hatch so programs designed specifically for the SES-shim
// implementation may opt-in to use the same transforms for `evaluate`
// and `import`, at the expense of being tightly coupled to SES-shim.
globalTransforms = undefined;
localObject = create(null, getOwnPropertyDescriptors(globalLexicals));
defineProperties(
localObject,
getOwnPropertyDescriptors(__moduleShimLexicals__),
);
}
({ safeEvaluate } = makeSafeEvaluator({
globalObject,
localObject,
globalTransforms,
sloppyGlobalsMode,
knownScopeProxies,
}));
}
return { safeEvaluate };
};
export const compartmentEvaluate = (compartmentFields, source, options) => {

@@ -28,4 +80,2 @@ // Perform this check first to avoid unecessary sanitizing.

transforms = [],
sloppyGlobalsMode = false,
__moduleShimLexicals__ = undefined,
__evadeHtmlCommentTest__ = false,

@@ -46,30 +96,10 @@ __evadeImportExpressionTest__ = false,

let { globalTransforms } = compartmentFields;
const { globalObject, globalLexicals, knownScopeProxies } = compartmentFields;
const { safeEvaluate } = provideCompartmentEvaluator(
compartmentFields,
options,
);
let localObject = globalLexicals;
if (__moduleShimLexicals__ !== undefined) {
// When using `evaluate` for ESM modules, as should only occur from the
// module-shim's module-instance.js, we do not reveal the SES-shim's
// module-to-program translation, as this is not standardizable behavior.
// However, the `localTransforms` will come from the `__shimTransforms__`
// Compartment option in this case, which is a non-standardizable escape
// hatch so programs designed specifically for the SES-shim
// implementation may opt-in to use the same transforms for `evaluate`
// and `import`, at the expense of being tightly coupled to SES-shim.
globalTransforms = undefined;
localObject = create(null, getOwnPropertyDescriptors(globalLexicals));
defineProperties(
localObject,
getOwnPropertyDescriptors(__moduleShimLexicals__),
);
}
return performEval(source, globalObject, localObject, {
globalTransforms,
return safeEvaluate(source, {
localTransforms,
sloppyGlobalsMode,
knownScopeProxies,
});
};

@@ -23,3 +23,6 @@ // @ts-check

} from './commons.js';
import { initGlobalObject } from './global-object.js';
import {
setGlobalObjectConstantProperties,
setGlobalObjectMutableProperties,
} from './global-object.js';
import { isValidIdentifierName } from './scope-constants.js';

@@ -32,2 +35,3 @@ import { sharedGlobalPropertyNames } from './whitelist.js';

import { compartmentEvaluate } from './compartment-evaluate.js';
import { makeSafeEvaluator } from './make-safe-evaluator.js';

@@ -211,3 +215,3 @@ const { quote: q } = assert;

__shimTransforms__ = [],
globalLexicals = {},
globalLexicals: globalLexicalsOption = {},
resolveHook,

@@ -250,19 +254,4 @@ importHook,

const globalObject = {};
initGlobalObject(
globalObject,
intrinsics,
sharedGlobalPropertyNames,
targetMakeCompartmentConstructor,
this.constructor.prototype,
{
globalTransforms,
markVirtualizedNativeFunction,
},
);
assign(globalObject, endowments);
const invalidNames = arrayFilter(
getOwnPropertyNames(globalLexicals),
getOwnPropertyNames(globalLexicalsOption),
identifier => !isValidIdentifierName(identifier),

@@ -278,5 +267,40 @@ );

}
// The caller continues to own the globalLexicals object they passed to
// the compartment constructor, but the compartment only respects the
// original values and they are constants in the scope of evaluated
// programs and executed modules.
// This shallow copy captures only the values of enumerable own
// properties, erasing accessors.
// The snapshot is frozen to ensure that the properties are immutable
// when transferred-by-property-descriptor onto local scope objects.
const globalLexicals = freeze({ ...globalLexicalsOption });
const globalObject = {};
// We must initialize all constant properties first because
// `makeSafeEvaluator` may use them to create optimized bindings
// in the evaluator.
// TODO: consider merging into a single initialization if internal
// evaluator is no longer eagerly created
setGlobalObjectConstantProperties(globalObject);
const knownScopeProxies = new WeakSet();
const { safeEvaluate } = makeSafeEvaluator({
globalObject,
localObject: globalLexicals,
globalTransforms,
sloppyGlobalsMode: false,
knownScopeProxies,
});
setGlobalObjectMutableProperties(globalObject, {
intrinsics,
newGlobalPropertyNames: sharedGlobalPropertyNames,
makeCompartmentConstructor: targetMakeCompartmentConstructor,
safeEvaluate,
markVirtualizedNativeFunction,
});
assign(globalObject, endowments);
weakmapSet(privateFields, this, {

@@ -287,11 +311,4 @@ name,

knownScopeProxies,
// The caller continues to own the globalLexicals object they passed to
// the compartment constructor, but the compartment only respects the
// original values and they are constants in the scope of evaluated
// programs and executed modules.
// This shallow copy captures only the values of enumerable own
// properties, erasing accessors.
// The snapshot is frozen to ensure that the properties are immutable
// when transferred-by-property-descriptor onto local scope objects.
globalLexicals: freeze({ ...globalLexicals }),
globalLexicals,
safeEvaluate,
resolveHook,

@@ -298,0 +315,0 @@ importHook,

@@ -7,25 +7,10 @@ import { defineProperty, objectHasOwnProperty, entries } from './commons.js';

/**
* initGlobalObject()
* Create new global object using a process similar to ECMA specifications
* (portions of SetRealmGlobalObject and SetDefaultGlobalBindings).
* `newGlobalPropertyNames` should be either `initialGlobalPropertyNames` or
* `sharedGlobalPropertyNames`.
* setGlobalObjectConstantProperties()
* Initializes a new global object using a process similar to ECMA specifications
* (SetDefaultGlobalBindings). This process is split between this function and
* `setGlobalObjectMutableProperties`.
*
* @param {Object} globalObject
* @param {Object} intrinsics
* @param {Object} newGlobalPropertyNames
* @param {Function} makeCompartmentConstructor
* @param {Object} compartmentPrototype
* @param {Object} [options]
* @param {Array<Transform>} [options.globalTransforms]
* @param {(Object) => void} [options.markVirtualizedNativeFunction]
*/
export const initGlobalObject = (
globalObject,
intrinsics,
newGlobalPropertyNames,
makeCompartmentConstructor,
compartmentPrototype,
{ globalTransforms, markVirtualizedNativeFunction },
) => {
export const setGlobalObjectConstantProperties = globalObject => {
for (const [name, constant] of entries(constantProperties)) {

@@ -39,3 +24,29 @@ defineProperty(globalObject, name, {

}
};
/**
* setGlobalObjectMutableProperties()
* Create new global object using a process similar to ECMA specifications
* (portions of SetRealmGlobalObject and SetDefaultGlobalBindings).
* `newGlobalPropertyNames` should be either `initialGlobalPropertyNames` or
* `sharedGlobalPropertyNames`.
*
* @param {Object} globalObject
* @param {Object} param1
* @param {Object} param1.intrinsics
* @param {Object} param1.newGlobalPropertyNames
* @param {Function} param1.makeCompartmentConstructor
* @param {(string, Object?) => any} param1.safeEvaluate
* @param {(Object) => void} param1.markVirtualizedNativeFunction
*/
export const setGlobalObjectMutableProperties = (
globalObject,
{
intrinsics,
newGlobalPropertyNames,
makeCompartmentConstructor,
safeEvaluate,
markVirtualizedNativeFunction,
},
) => {
for (const [name, intrinsicName] of entries(universalPropertyNames)) {

@@ -65,8 +76,4 @@ if (objectHasOwnProperty(intrinsics, intrinsicName)) {

globalThis: globalObject,
eval: makeEvalFunction(globalObject, {
globalTransforms,
}),
Function: makeFunctionConstructor(globalObject, {
globalTransforms,
}),
eval: makeEvalFunction(safeEvaluate),
Function: makeFunctionConstructor(safeEvaluate),
};

@@ -73,0 +80,0 @@

@@ -27,3 +27,7 @@ // Copyright (C) 2018 Agoric

import tameLocaleMethods from './tame-locale-methods.js';
import { initGlobalObject } from './global-object.js';
import {
setGlobalObjectConstantProperties,
setGlobalObjectMutableProperties,
} from './global-object.js';
import { makeSafeEvaluator } from './make-safe-evaluator.js';
import { initialGlobalPropertyNames } from './whitelist.js';

@@ -293,12 +297,14 @@ import { tameFunctionToString } from './tame-function-tostring.js';

// start compartment, from the intrinsics.
initGlobalObject(
globalThis,
setGlobalObjectConstantProperties(globalThis);
const { safeEvaluate } = makeSafeEvaluator({ globalObject: globalThis });
setGlobalObjectMutableProperties(globalThis, {
intrinsics,
initialGlobalPropertyNames,
newGlobalPropertyNames: initialGlobalPropertyNames,
makeCompartmentConstructor,
compartmentPrototype,
{
markVirtualizedNativeFunction,
},
);
safeEvaluate,
markVirtualizedNativeFunction,
});

@@ -305,0 +311,0 @@ /**

@@ -1,9 +0,7 @@

import { performEval } from './evaluate.js';
/*
* makeEvalFunction()
* A safe version of the native eval function which relies on
* the safety of performEval for confinement.
* the safety of safeEvaluate for confinement.
*/
export const makeEvalFunction = (globalObject, options = {}) => {
export const makeEvalFunction = safeEvaluate => {
// We use the the concise method syntax to create an eval without a

@@ -22,3 +20,3 @@ // [[Construct]] behavior (such that the invocation "new eval()" throws

}
return performEval(source, globalObject, {}, options);
return safeEvaluate(source);
},

@@ -25,0 +23,0 @@ }.eval;

@@ -8,3 +8,2 @@ import {

} from './commons.js';
import { performEval } from './evaluate.js';
import { assert } from './error/assert.js';

@@ -15,5 +14,5 @@

* A safe version of the native Function which relies on
* the safety of performEval for confinement.
* the safety of safeEvaluate for confinement.
*/
export const makeFunctionConstructor = (globaObject, options = {}) => {
export const makeFunctionConstructor = safeEvaluate => {
// Define an unused parameter to ensure Function.length === 1

@@ -58,3 +57,3 @@ const newFunction = function Function(_body) {

const src = `(function anonymous(${parameters}\n) {\n${bodyText}\n})`;
return performEval(src, globaObject, {}, options);
return safeEvaluate(src);
};

@@ -61,0 +60,0 @@

@@ -42,3 +42,3 @@ import {

* ScopeHandler manages a Proxy which serves as the global scope for the
* performEval operation (the Proxy is the argument of a 'with' binding).
* safeEvaluate operation (the Proxy is the argument of a 'with' binding).
* As described in createSafeEvaluator(), it has several functions:

@@ -156,5 +156,16 @@ * - allow the very first (and only the very first) use of 'eval' to map to

// a property to globalObject instead of throwing a ReferenceError.
// !!!!! WARNING: DANGER ZONE !!!!!!
// The order of the conditions in the `||` expression below is of the
// utmost importance. Under no circumstances should `eval` be checked
// after `globalObject`. The prototype of the global object is under
// full control of user code and may be replaced by a proxy with a
// `has` trap. If we allow that trap to trigger while the
// `allowNextEvalToBeUnsafe` flag is down, it could allow user code
// to get a hold of `FERAL_EVAL`, resulting in a complete escape of
// the compartment.
// !!!!! WARNING: DANGER ZONE !!!!!!
return (
sloppyGlobalsMode ||
prop === 'eval' ||
(allowNextEvalToBeUnsafe && prop === 'eval') ||
prop in localObject ||

@@ -161,0 +172,0 @@ prop in globalObject ||

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc