Skip to content
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

docs(ses): Document environment lockdown options #2018

Merged
merged 1 commit into from
Jan 30, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 154 additions & 29 deletions packages/ses/docs/lockdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,39 @@ compatibility vs better tool compatibility.

Each option is explained in its own section below.

| option | default setting | other settings | about |
|--------------------|------------------|----------------|-------|
| `regExpTaming` | `'safe'` | `'unsafe'` | `RegExp.prototype.compile` |
| `localeTaming` | `'safe'` | `'unsafe'` | `toLocaleString` |
| `consoleTaming` | `'safe'` | `'unsafe'` | deep stacks |
| `errorTaming` | `'safe'` | `'unsafe'` | `errorInstance.stack` |
| `errorTrapping` | `'platform'` | `'exit'` `'abort'` `'report'` `'none'` | handling of uncaught exceptions |
| `unhandledRejectionTrapping` | `'report'` | `'none'` | handling of finalized unhandled rejections |
| `evalTaming` | `'safeEval'` | `'unsafeEval'` `'noEval'` | `eval` and `Function` of the start compartment. |
| `stackFiltering` | `'concise'` | `'verbose'` | deep stacks signal/noise |
| `overrideTaming` | `'moderate'` | `'min'` or `'severe'` | override mistake antidote |
| `overrideDebug` | `[]` | array of property names | detect override mistake |
| `domainTaming` | `'safe'` | `'unsafe'` | Node.js `domain` module |
| `__hardenTaming__` | `'safe'` | `'unsafe'` | Making `harden` no-op for performance in trusted environments |
| option | default setting | other settings | about |
|------------------------------|------------------|----------------------------------------|-------|
| `regExpTaming` | `'safe'` | `'unsafe'` | `RegExp.prototype.compile` |
| `localeTaming` | `'safe'` | `'unsafe'` | `toLocaleString` |
| `consoleTaming` | `'safe'` | `'unsafe'` | deep stacks |
| `errorTaming` | `'safe'` | `'unsafe'` | `errorInstance.stack` |
| `errorTrapping` | `'platform'` | `'exit'` `'abort'` `'report'` `'none'` | handling of uncaught exceptions |
| `unhandledRejectionTrapping` | `'report'` | `'none'` | handling of finalized unhandled rejections |
| `evalTaming` | `'safeEval'` | `'unsafeEval'` `'noEval'` | `eval` and `Function` of the start compartment. |
| `stackFiltering` | `'concise'` | `'verbose'` | deep stacks signal/noise |
| `overrideTaming` | `'moderate'` | `'min'` or `'severe'` | override mistake antidote |
| `overrideDebug` | `[]` | array of property names | detect override mistake |
| `domainTaming` | `'safe'` | `'unsafe'` | Node.js `domain` module |
| `__hardenTaming__` | `'safe'` | `'unsafe'` | Making `harden` no-op for performance in trusted environments |

In the absence of any of these options in lockdown arguments, lockdown will
attempt to read these from the Node.js `process.env` environment.
The corresponding environment variables are the same but in `UPPER_SNAKE_CASE`.
attempt to read these options from `process.env`, using the Node.js convention
for threading environment variables into a JavaScript program.

| option | environment variable | notes |
|------------------------------|-----------------------------------------|-----------------------|
| `regExpTaming` | `LOCKDOWN_REGEXP_TAMING` | |
| `localeTaming` | `LOCKDOWN_LOCALE_TAMING` | |
| `consoleTaming` | `LOCKDOWN_CONSOLE_TAMING` | |
| `errorTaming` | `LOCKDOWN_ERROR_TAMING` | |
| `errorTrapping` | `LOCKDOWN_ERROR_TRAPPING` | |
| `unhandledRejectionTrapping` | `LOCKDOWN_UNHANDLED_REJECTION_TRAPPING` | |
| `evalTaming` | `LOCKDOWN_EVAL_TAMING` | |
| `stackFiltering` | `LOCKDOWN_STACK_FILTERING` | |
| `overrideTaming` | `LOCKDOWN_OVERRIDE_TAMING` | |
| `overrideDebug` | `LOCKDOWN_OVERRIDE_DEBUG` | comma separated names |
| `domainTaming` | `LOCKDOWN_DOMAIN_TAMING` | |
| `__hardenTaming__` | `LOCKDOWN_HARDEN_TAMING` | |

The options `mathTaming` and `dateTaming` are deprecated.
`Math.random`, `Date.now`, and the `new Date()` are disabled within
Expand Down Expand Up @@ -73,6 +88,14 @@ lockdown({ regExpTaming: 'safe' }); // Delete RegExp.prototype.compile
lockdown({ regExpTaming: 'unsafe' }); // Preserve RegExp.prototype.compile
```

If `lockdown` does not receive a `regExpTaming` option, it will respect
`process.env.LOCKDOWN_REGEXP_TAMING`.

```console
LOCKDOWN_REGEXP_TAMING=safe
LOCKDOWN_REGEXP_TAMING=unsafe
```

The `regExpTaming` default `'safe'` setting deletes this dangerous method. The
`'unafe'` setting preserves it for maximal compatibility at the price of some
risk.
Expand Down Expand Up @@ -121,6 +144,14 @@ lockdown({ localeTaming: 'safe' }); // Alias toLocaleString to toString, etc
lockdown({ localeTaming: 'unsafe' }); // Allow locale-specific behavior
```

If `lockdown` does not receive a `localeTaming` option, it will respect
`process.env.LOCKDOWN_LOCALE_TAMING`.

```console
LOCKDOWN_LOCALE_TAMING=safe
LOCKDOWN_LOCALE_TAMING=unsafe
```

The `localeTaming` default `'safe'` option replaces each of these methods with
the corresponding non-locale-specific method. `Object.prototype.toLocaleString`
becomes just another name for `Object.prototype.toString`. The `'unsafe'`
Expand Down Expand Up @@ -166,17 +197,35 @@ lockdown({
overrideTaming: 'min', // Until https://github.com/endojs/endo/issues/636
});
```

If `lockdown` does not receive a `consoleTaming` option, it will respect
`process.env.LOCKDOWN_CONSOLE_TAMING`.

```console
LOCKDOWN_CONSOLE_TAMING=safe
LOCKDOWN_CONSOLE_TAMING=unsafe
```

The `consoleTaming: 'safe'` setting replaces the global console with a tamed
console, and that tamed console is safe to endow to a guest `Compartment`.
Additionally, any errors created with the `assert` function or methods on its
namespace may have [redacted details](../src/error/README.md): information
included in the error message that is informative to a debugger and made
invisible to an attacker.
The tamed console removes redactions and shows these details to the original
console.

The `consoleTaming: 'unsafe'` setting leaves the original console in place.
The `assert` package and error objects will continue to work, but the `console`
logging output will not show any of this extra information.

The risk is that the original platform-provided `console` object often has
additional methods beyond the de facto `console` "standards". Under the
`'unsafe'` setting we do not remove them.
We do not know whether any of these additional
methods violate ocap security. Until we know otherwise, we should assume these
are unsafe. Such a raw `console` object should only be handled by very
trustworthy code.
additional methods beyond the de facto `console` "standards" and may be unsafe
to endow to a guest `Compartment`.
Under the `'unsafe'` setting we do not remove them.
We do not know whether any of these additional methods violate ocap security.
Until we know otherwise, we should assume these are unsafe. Such a raw
`console` object should only be handled by very trustworthy code.
Comment on lines +227 to +228
Copy link
Contributor

Choose a reason for hiding this comment

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

FYI

// The untamed Node.js console cannot itself be hardened as it has mutable
// internal properties, but some of these properties expose internal versions
// of classes from node's "primordials" concept.
from @mhofman 's #1939 does mitigate the case we're aware of.


Until the bug
[Node console gets confused if .constructor is an accessor (#636)](https://github.com/endojs/endo/issues/636)
Expand Down Expand Up @@ -267,6 +316,14 @@ lockdown({ errorTaming: 'safe' }); // Deny unprivileged access to stacks, if pos
lockdown({ errorTaming: 'unsafe' }); // stacks also available by errorInstance.stack
```

If `lockdown` does not receive an `errorTaming` option, it will respect
`process.env.LOCKDOWN_ERROR_TAMING`.

```console
LOCKDOWN_ERROR_TAMING=safe
LOCKDOWN_ERROR_TAMING=unsafe
```

The `errorTaming` default `'safe'` setting makes the stack trace inaccessible
from error instances alone, when possible. It currently does this only on
v8 (Chrome, Brave, Node). It will also do so on SpiderMonkey (Firefox).
Expand Down Expand Up @@ -336,6 +393,17 @@ lockdown({ errorTrapping: 'report' }); // just report
lockdown({ errorTrapping: 'none' }); // no platform error traps
```

If `lockdown` does not receive an `errorTrapping` option, it will respect
`process.env.LOCKDOWN_ERROR_TRAPPING`.

```console
LOCKDOWN_ERROR_TRAPPING=platform
LOCKDOWN_ERROR_TRAPPING=exit
LOCKDOWN_ERROR_TRAPPING=abort
LOCKDOWN_ERROR_TRAPPING=report
LOCKDOWN_ERROR_TRAPPING=none
```

On the web, the `window` event emitter has a trap for `error` events.
In the absence of a trap, the platform logs the error to the debugger console
and continues.
Expand Down Expand Up @@ -383,6 +451,14 @@ lockdown({ unhandledRejectionTrapping: 'report' }); // print finalized unhandled
lockdown({ unhandledRejectionTrapping: 'none' }); // no special unhandled rejection traps
```

If `lockdown` does not receive an `unhandledRejectionTrapping` option, it will
respect `process.env.LOCKDOWN_UNHANDLED_REJECTION_TRAPPING`.

```console
LOCKDOWN_UNHANDLED_REJECTION_TRAPPING=report
LOCKDOWN_UNHANDLED_REJECTION_TRAPPING=none
```

On the web, the `window` event emitter has a trap for `unhandledrejection` and
`rejectionhandled` events. In the absence of a trap, the platform logs
rejections that were not handled in the same turn in which they were created to
Expand Down Expand Up @@ -410,13 +486,14 @@ triggering the SES trap handler.

This option only affects the start compartment!

To disallows eval in the explicit compartments, replace the constructors in the compartment.
To disallow `eval` in specific compartments, replace `eval` and the function
constructors in the compartment.

```js
const c = new Compartment()
c.globalThis.eval = c.globalThis.Function = function() {
throw new TypeError()
}
throw new TypeError();
};
Comment on lines +495 to +496
Copy link
Contributor

Choose a reason for hiding this comment

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

Too bad eslint doesn't run on "```js" blocks in .md files ;)

```

**Background**: Every realm has an implicit initial compartment we call the "start compartment". Explicit compartments are made with the `Compartment` constructor.
Expand Down Expand Up @@ -459,6 +536,15 @@ lockdown({ evalTaming: 'noEval' }); // disallowing calling eval like there is a
lockdown({ evalTaming: 'unsafeEval' });
```

If `lockdown` does not receive an `evalTaming` option, it will respect
`process.env.LOCKDOWN_EVAL_TAMING`.

```console
LOCKDOWN_EVAL_TAMING=safeEval
LOCKDOWN_EVAL_TAMING=noEval
LOCKDOWN_EVAL_TAMING=unsafeEval
```

## `stackFiltering` Options

**Background**: The error stacks shown by many JavaScript engines are
Expand All @@ -480,6 +566,14 @@ lockdown({ stackFiltering: 'concise' }); // Preserve important deep stack info
lockdown({ stackFiltering: 'verbose' }); // Console shows full deep stacks
```

If `lockdown` does not receive a `stackFiltering` option, it will respect
`process.env.LOCKDOWN_STACK_FILTERING`.

```console
LOCKDOWN_STACK_FILTERING=concise
LOCKDOWN_STACK_FILTERING=verbose
```

When looking at deep distributed stacks, in order to debug distributed
computation, seeing the full stacks is overwhelmingly noisy. The error stack
proposal leaves it to the host what stack trace info to show. SES virtualizes
Expand Down Expand Up @@ -617,6 +711,15 @@ lockdown({ overrideTaming: 'min' }); // Minimal mitigations for purely modern co
lockdown({ overrideTaming: 'severe' }); // More severe legacy compat
```

If `lockdown` does not receive a `overrideTaming` option, it will respect
`process.env.LOCKDOWN_OVERRIDE_TAMING`.

```console
LOCKDOWN_OVERRIDE_TAMING=moderate
LOCKDOWN_OVERRIDE_TAMING=min
LOCKDOWN_OVERRIDE_TAMING=severe
```

The `overrideTaming` default `'moderate'` option of `lockdown` is intended to
be fairly minimal, but we expand it as needed, when we
encounter code which should run under SES but is prevented from doing so
Expand Down Expand Up @@ -661,9 +764,11 @@ by our override mitigation.

## `overrideDebug` Options

To help diagnose problems with the override mistake, you can set this option to
a list of properties that will print diagnostic information when their override
enablement is triggered.
To help diagnose problems with the [Property Override Mistake][POM], you can
set this option to a list of properties that will print diagnostic information
when their override enablement is triggered.

[POM]: https://github.com/endojs/endo/discussions/1855

For example, to find the client code that causes a `constructor` property override
mistake, set the options as follows:
Expand All @@ -675,12 +780,24 @@ mistake, set the options as follows:
}
```

If `lockdown` does not receive a `regExpTaming` option, it will respect
`process.env.LOCKDOWN_OVERRIDE_DEBUG`, a comma-separated list of property names
on shared intrinsics to replace with debugger accessors.

```console
LOCKDOWN_OVERRIDE_DEBUG=constructor,toString
```

The idiom for `@agoric/install-ses` when tracking down the override
mistake with the `constructor` property is to set the following
environment variable:

```sh
LOCKDOWN_OPTIONS='{"errorTaming":"unsafe","stackFiltering":"verbose","overrideTaming":"severe","overrideDebug":["constructor"]}'
LOCKDOWN_ERROR_TAMING=unsafe \
LOCKDOWN_STACK_FILTERING=verbose \
LOCKDOWN_OVERRIDE_TAMING=severe \
LOCKDOWN_OVERRIDE_DEBUG=constructor \
node ...
```

Then, when some script deep in the require stack does:
Expand Down Expand Up @@ -748,6 +865,14 @@ lockdown({ __hardenTaming__: 'safe' }); // harden works
lockdown({ __hardenTaming__: 'unsafe' }); // harden is noop. Other tests pretend
```

If `lockdown` does not receive a `__hardenTaming__` option, it will respect
`process.env.LOCKDOWN_HARDEN_TAMING`.

```console
LOCKDOWN_HARDEN_TAMING=safe
LOCKDOWN_HARDEN_TAMING=unsafe
```

We created this option specifically for
speed of the SwingSet kernel. It could also be used for other highly vetted, style
restricted, security-critical, and speed-critical code. This would be safe to turn
Expand Down
Loading