Build Compartments

Build compartments by mapping authority first, then give each component only the memory, services, and entry points required for its task.

Memory-safe code can still be over-privileged. A parser may correctly read the input it receives but have no reason to access encryption keys, update controls, or unrelated application state. A compartment boundary limits what the component can reach even if it is buggy or compromised.

The hard part is not adding the boundary instruction. It is deciding which authority must cross it.

Choose a useful first boundary

Good first compartments have a narrow purpose and an existing interface. Examples include:

A source-directory split alone does not create a useful security boundary. A compartment should correspond to assets and threats that can be described and tested.

Describe the authority each component needs

Before writing code, list what the component needs:

This list describes the proposed security policy. Review it before implementation and keep it with the tests.

Design a narrow interface

Prefer interfaces that pass bounded data and small, well-defined values:

int parse_message(const unsigned char *input,
                  size_t input_length,
                  struct parsed_message *output);

The interface should define:

Passing a pointer to a large application context is convenient but usually grants too much authority.

Derive, do not widen

The caller should derive a narrower capability from authority it already holds:

  1. restrict the bounds to the specific object
  2. remove permissions the callee does not need
  3. pass only the required service entry points
  4. avoid ambient globals that bypass the interface

CHERI capabilities can normally be reduced but not amplified. The design should not depend on the callee inventing authority later.

Select the platform mechanism

Compartment application programming interfaces (APIs) differ by environment:

Use the platform’s maintained mechanism. A calling convention assembled from raw sealing operations is appropriate only when the architecture work itself is the goal.

Test the negative cases

A compartment test suite must show what fails:

Check not only that the processor faults, but also what the system does next. Does it terminate one compartment, restart a service, reset the device, or stop the whole application? Availability is part of the design.

Measure boundary cost

Fine-grained compartments trade reduced authority for transition and communication overhead. Measure:

If a boundary is too expensive, first reduce call frequency or batch data. Removing the security boundary should not be the automatic optimisation.

Review checklist

For an embedded worked path, use the CHERIoT Programmer’s Guide. For the underlying mechanism, read Compartmentalisation and Sealing.

Where next

Continue with maintained tutorials for the selected platform, compartment model, and development tools.

Tutorials & Training →