Skip to content

Commit

Permalink
docs(ses): Document environment lockdown options (merge #2018)
Browse files Browse the repository at this point in the history
  • Loading branch information
kriskowal authored Jan 30, 2024
2 parents 193e403 + a2d796a commit 4040f0e
Showing 1 changed file with 154 additions and 29 deletions.
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.

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();
};
```

**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

0 comments on commit 4040f0e

Please sign in to comment.