CHERI and Rust - Technical Overview

Why it is not CHERI vs Rust, but CHERI and Rust.

Rust and CHERI both aim to reduce memory-safety vulnerabilities, but they do so in fundamentally different ways.

Rust uses a language-based approach. Through ownership, borrowing, lifetimes, and type checking, it prevents many classes of memory-safety error before software is compiled.

CHERI uses a hardware-based approach. It extends the processor architecture with capabilities that carry bounds, permissions, and provenance information, allowing memory accesses to be checked while software is running.

Because they operate at different layers, Rust and CHERI are best viewed as complementary technologies rather than alternatives. A system can use Rust to prevent vulnerabilities from being introduced and CHERI to constrain memory accesses when software executes.

Rust and CHERI: side by side

Legend: ● Covered, ○ Partial, blank = Not covered

Property Rust CHERI Rust + CHERI Notes
Spatial memory safety        
Buffer overflow prevention Only in safe Rust, via bounds checks on slices; CHERI uses hardware capability bounds on every pointer.
Out-of-bounds read This is caught in safe Rust; CHERI also catches it in inline assembly and FFI code.
Bounds on heap allocations Rust checks bounds only in safe code; CHERI tags every allocation with hardware bounds regardless of language.
Pointer-integer confusion CHERI capabilities cannot be forged from integers: a hardware tag bit enforces this. Rust’s type system allows raw pointer casts via unsafe.
Pointer provenance enforcement Safe Rust tracks provenance conceptually; CHERI enforces it in silicon, with no capability without derivation from a valid source.
Temporal memory safety        
Use-after-free prevention Rust’s ownership model statically prevents this in safe code. CHERI provides use-after-free protection with capability revocation.
Dangling pointer prevention Rust’s borrow checker statically prevents dangling pointers; CHERI requires revocation support for equivalent temporal safety.
Double-free prevention Rust’s ownership enforces single deallocation; handled by the CHERI memory allocator.
Memory leak prevention   Rust reduces accidental memory leaks but does not eliminate them entirely. Programmer care or dedicated tooling is still required.
Type and value safety        
Type confusion between same-size structures   Rust’s type system distinguishes structures of the same size; CHERI only tracks bounds and provenance.
Data race prevention Rust’s Send and Sync traits enforce thread safety at compile time. CHERI has no concurrency model, but guarantees relaxed atomicity for all pointer loads and stores.
Uninitialised reads and arithmetic errors   Rust requires initialisation before use and panics on integer overflow in debug builds; these issues are outside CHERI’s scope.
Isolation and compartmentalisation        
Cross-component memory isolation   CHERI compartmentalisation enforces that objects in one compartment cannot be accessed by another. Rust has no equivalent at the process or component boundary.
Prevent C/C++ code from corrupting Rust objects   Without CHERI, a bug in linked C code can corrupt any Rust object in the same process. CHERI enforces bounds on all code in a compartment, regardless of language.
Supply-chain isolation   CHERI provides tools for building compartments that isolate third-party or malicious library code.
Least-privilege enforcement   CHERI capabilities are monotonically non-increasing: a component can delegate only a subset of its own permissions.
Coverage and scope        
Protects unsafe Rust blocks   Although tools can help, Rust waives its own guarantees in unsafe blocks. CHERI hardware checks continue to apply.
Protects assembly and non-Rust code   CHERI hardware protects all code, including inline assembly, operating-system kernels, and bootloaders that Rust cannot cover.
No compiler trust required   Rust’s guarantees depend on compiler correctness. CHERI enforces its properties in silicon, so a buggy or malicious compiler cannot bypass hardware capabilities.
Reuse existing software   Rust requires a complete code rewrite. CHERI requires recompilation and correction of a small number of issues.
Works on existing hardware     Rust requires only compiler support. CHERI requires hardware support.
Developer experience and adoption        
Zero runtime overhead for safe code Safe Rust has near-zero overhead. CHERI shows less than 3% overhead, while runtime protection can enable further optimisation at the same security level.
Protects legacy codebases without rewriting   CHERI requires only recompilation of most C/C++ code. Rust requires a full rewrite.
Capability sealing and object authority   CHERI supports sealing capabilities so they can be held but not dereferenced except by the designated unsealer, enabling secure object references and cross-compartment handles.
Embedded and bare-metal support Both support embedded systems without an operating system.

What safe Rust provides

Rust’s ownership and borrowing rules let the compiler check how references are created and used. In safe Rust, these rules prevent many problems including use-after-free, invalid aliasing, null dereferences, and data races.

The checks happen mainly at compile time, so safe Rust normally avoids the runtime cost associated with garbage collection or pervasive bounds metadata. Arrays and slices still use runtime bounds checks where needed.

This makes Rust a strong choice for new systems code when its platform and library ecosystem meet the project’s needs.

Where the language boundary ends

Rust permits unsafe code because some low-level operations cannot be expressed or verified through the safe subset. An unsafe block may dereference a raw pointer, access hardware registers, call a C interface, or implement a data structure that presents a safe application programming interface (API).

unsafe does not disable the compiler or mean that anything is allowed. It means the programmer is responsible for upholding additional rules that the compiler cannot check. A mistake can still cause memory corruption.

Safe Rust may also depend on:

The whole system is only as well protected as these boundaries allow.

What CHERI adds

CHERI checks memory authority in hardware when an access occurs. A raw pointer represented by a capability can still be constrained by bounds, permissions, and validity. This can turn some mistakes in unsafe Rust or native code into precise faults instead of unrestricted memory corruption.

CHERI also supports compartmentalisation. Two memory-safe components may each be correct in isolation but should not necessarily have access to each other’s secrets or services. Capabilities can express the minimum authority passed across that boundary.

This creates complementary layers:

Important limits

CHERI does not automatically validate all Rust safety assumptions. Compiler support, application binary interface (ABI) design, standard-library support, and the handling of pointer metadata all matter. A capability with broad bounds can still authorise broad access, and a component given a powerful service capability can legitimately misuse it.

Likewise, Rust does not automatically provide least privilege between all components. A memory-safe program can still contain a logic flaw or expose more authority than intended.

Rust support varies across CHERI platforms and continues to evolve. Check the Rust software ecosystem page and the documentation for the chosen target before planning a production migration.

Key takeaways

Where next

How Secure is a Product?

Assess a CHERI system by its software mode, protected assets, authority boundaries, and supporting evidence.

Continue