Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,12 @@ Always run `yarn lint` in each package you've modified before committing.
- Use conventional commits: `feat(pkg):`, `fix(pkg):`, `refactor(pkg):`, `chore:`, `test(pkg):`
- Breaking changes: `feat(pkg)!:` or `fix(pkg)!:`
- File conversions (`.js` to `.ts`) get their own `refactor:` commit

## Prose style

- Avoid em-dashes (`—`, U+2014) in prose.
Prefer separate sentences, parentheses, or colons.
In technical documentation, em-dashes obscure the rhythm of the prose
and almost always read better as their own sentence.
- Wrap markdown lines at 80 to 100 columns.
- Start each sentence on a new line so that diffs are per-sentence.
55 changes: 55 additions & 0 deletions docs/lockdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -1218,3 +1218,58 @@ The "`__`" in the option name indicates that this option is temporary. XS now
has a fast native `harden`, but SwingSet currently runs on node/v8, which does
not. If node/v8 ever implements a fast native `harden`, we hope to deprecate
and eventually remove this option.

# Limitations

Compartments isolate the *authority* and *intrinsics* available to guest code,
but every compartment in a realm shares the same JavaScript *agent*.
In engine terms, that is a single thread of execution and a single heap.
The following limitations are intrinsic to running JavaScript in one agent and
are not threats a `Compartment` can mitigate.
A host that needs to defend against them must impose a coarser boundary,
as a separate worker or process around the
suspect code.
Comment on lines +1229 to +1231

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should dedicate a section timing side-channels. Note that the default Compartment does not include any timers of any resolution, but it is very difficult to avoid inadvertently giving a guest program the ability to measure duration. Asynchronous communication to another worker or process is often enough to inadvertently expose a confined guest to a gadget for measuring the passage of time.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Added the Timing side-channels section in f299f8e, placed as a third subsection under Limitations alongside Availability and Memory exhaustion. The section notes that the default Compartment excludes Date, performance.now, setTimeout, setImmediate, and other host scheduling primitives; explains that asynchronous round-trips to any other agent recover wall-clock duration; spells out the audit obligation (every async boundary the guest can reach, not just timer-like APIs in the global scope); and lists the host mitigation menu (separate worker or process; outbound rate throttling; padded guest-visible message timing).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The section on timing side channels should cite https://papers.agoric.com/taxonomy-of-security-issues/

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Added a reference paragraph at the end of the Timing side-channels section pointing at https://papers.agoric.com/taxonomy-of-security-issues/ as the broader catalog this section samples. Pushed in the latest commit.


## Availability

A compartment cannot protect availability for code running in sibling
compartments or in the start compartment.
Because all compartments share the agent's single thread, a guest that enters
an infinite loop (such as `for (;;) {}`), a runaway recursion, or any other
non-terminating synchronous computation denies synchronous progress to every
other compartment until the engine itself intervenes (for example, by hitting
an engine-imposed call-stack limit or by the host terminating the worker or
process).

This applies even to ostensibly cooperative code.
A guest method invoked synchronously by host code can refuse to return.
This includes calls through a property accessor, a proxy trap, a `then`
callback resolved synchronously, or any other synchronous call.
Host code that wishes to remain available in the face of an unresponsive guest
must arrange to interact with guest objects across an asynchronous boundary
(for example, by using promises and a watchdog timer in a separate agent), or
must run the guest in a separate worker or process where the host can
terminate it.

## Memory exhaustion

A compartment cannot protect the integrity of its exports against an
out-of-memory (OOM) attack mounted by another compartment in the same agent.
The ECMAScript specification does not require an engine to abort the agent on
OOM; see the TC39
[OOM-fails-fast proposal](https://github.com/tc39/proposal-oom-fails-fast)
for the current state of efforts to standardize that behavior.
In its absence, a malicious compartment can intentionally allocate stack
frames or heap objects until the engine raises a `RangeError` or other
allocation failure at an arbitrary point in unrelated code.

The failure can surface inside an unrelated synchronous call, including a
call into an object exported from another compartment.
The victim object may then be left in a partially updated state.
The result is an *integrity* compromise (broken invariants on otherwise
trusted objects) on top of the *availability* compromise (the agent or
process may exit).
Hosts that need to defend exported objects against this class of attack
should run untrusted guests in a separate agent (such as a worker or
subprocess) with its own heap, and treat any synchronous call into a guest as
potentially failure-inducing.
4 changes: 4 additions & 0 deletions packages/ses/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ const powerfulCompartment = new Compartment({
powerfulCompartment.globalThis.Date = Date;
```

Because every compartment shares one JavaScript agent, see
[Limitations](../../docs/lockdown.md#limitations) for the availability and
memory-exhaustion threats a `Compartment` cannot mitigate.

### Compartment + Lockdown

Together, Compartment and lockdown isolate client code in an environment with
Expand Down
Loading