CHERI represents a new system design that blocks exploits. Architectural changes to the CPU and memory systems add integrity checks to pointers that prevent reading, writing, or executing from memory that is out of bounds or using corrupted pointers, the most common classes of severe vulnerabilities. CHERI is supported by a complete compiler toolchain, multiple operating systems, is open source, and already implemented for several different RISC CPUs including Arm’s recently released Morello prototype.
Linux and Solaris have capabilities, but they are different from what I’ll be addressing here. These capabilities limit root privileges, so instead of having programs that execute as root having all the root privileges, they have a limited subset of superuser capabilities. This is particularly important in SUID root-owned programs that can be generally limited instead of extremely privileged. These capabilities have been a software feature in kernels for two decades.
I haven’t mentioned the second problem yet, but it’s the most important one I’ll be discussing. Exploiting software so that it misbehaves requires doing things, like heap spraying or buffer overflows, that often rely on misusing pointers in the C and C++ programming languages. C and C++ offer perhaps too much flexibility, features that have been used to create hundreds of millions of lines of working, mostly debugged code in operating systems, libraries and software in general. And compilers have matured to the point where they often fix the mistakes that programmers make, for example, by optimizing away code loops that don’t do anything with their results. But not pointer abuse.
Unlike Capsicum, which uses the concept of software-based capabilities, CHERI is based on hardware changes system-wide. Registers in the CPU control which ranges of memory can be used for loading or storing data, and for fetching code. Memory itself is changed by adding a tag bit that indicates that a region in memory contains a capability. And a capability can only be changed, without resetting the tag, by capability instructions. Capabilities are created at boot time, and capabilities derived from these initial ones are more restrictive. The new instructions for manipulating capabilities also mean changing the instruction set architecture, or ISA.
CheriBSD is an example of a pure capability system. A FreeBSD kernel, as well as its boot chain, libraries and user programs, have all been compiled using a CLANG/LLVM C compiler that replaces explicit and implied pointers with capabilities. Converting the kernel and libraries did take additional work, more than just recompilation because of issues with the way pointers have been used in the past. Capabilities get initialized during the boot process, and get narrowed each time those capabilities are granted to less privileged processes. The kernel itself can use capabilities, and the system call interface must also be changed to take advantage of capabilities. Obvious examples of system calls include program execution and memory allocation.
The kernel creates capabilities for an executed program that limits its access to both code and data. This is not unsimilar to what is commonly done using virtual memory. But the initial capabilities provided to a program become the basis for capabilities within the program, for example, a capability pointing to an array representing a string or a structure. A return address becomes a capability, one that cannot be changed by overwriting memory. Function pointers, such as those in C++ vtables, also become capabilities that cannot be overwritten without resetting the tag that marks them as valid capabilities. The addresses contained in capabilities can be changed, but only within the bounds they were created with, and only with special capability instructions. Thus, pointer arithmetic still works, but is bounded. The permissions associated with a capability, load, store, fetch (think read, write, execute), can be reduced but not increased.
In our prior work, the kernel interacted with capabilities via assembly stubs. Our enhanced version of the CheriBSD kernel is a hybrid C program where nearly all interactions with userspace are via explicitly annotated capability pointers. Of the 675 C and 8 assembly language files in our test kernels, 26 were created to support capabilities and 146 required adaptation for capabilities. In the full kernel source, about 750 files were touched. Other than a single file, implementing the CHERI-MIPS specific portions of CheriABI, the changes for CheriABI apply to any CHERI implementation. We continue to support the large suite of “legacy” mips64 userspace applications that adhere to the SysV ABI, alongside CheriABI userspace programs.
In a more recent project [3] (2020), Robert Watson, Alex Richardson and Ben Laurie converted the software stack for an open-source desktop. They needed to modify only .026% of the six million lines of code, as general purpose C/C++ code needs less adaptation than OS code. They also refined CHERI C/C++ along the way.
While pointers in C/C++ are the size of integers, capabilities have twice the size and must be aligned in memory. The first part of a 64 bit capability includes the permissions, bounds, and object type. The second 64 bits include the address. Structures and other places in existing C code that used integer-sized allocations as pointers will not be properly aligned and involve refactoring. Notably, the amount of space used for pointers gets doubled. The doubling of memory for pointers does harm performance in some applications, but in a few cases, because capabilities are loaded into registers, some applications and benchmarks actually perform better.
Sealed capabilities offer another advantage. A capability is sealed when the object type field is negative (the high bit is set). Sealed capabilities can be used in environments where there is a flat memory space instead of the typical way that operating systems are designed, with the kernel running as privileged and processes also running in a flat memory space. Sealed capabilities provide a means to partition a flat memory space into regions that are isolated from one another, but still accessible. They can exchange data without interprocess communication (IPC) and execute more privileged code without the penalty of the system call interface. These features are particularly useful for IoT applications and would add to the security of microkernels.
Sealed capabilities also allow the splitting of a single process into partitions that can be accessed only via the capabilities. Sealed capabilities include both the address to jump to and a capability that contains the range of memory that can be used for data. Sealed capabilities nicely express objects with the additional feature that hardware, the architectural capability, provides an inviolable partition within which the object gets manipulated.
The whole point of having architectural capabilities is to improve the security of applications. While the main targets are applications written in C or C++, all applications in any programming language use pointers internally, as they are an integral part of ISAs that allow indirect addressing.
A pointer is a unit of data that represents a location in memory. But pointers in most CPUs are not represented by using a type of registers specific to pointers. There are integer registers and floating point registers, but not pointer registers. Pointers are dealt with as if they were integers, and that has been the primary source of the problems with pointers.
In CHERI, pointers are a specific data type that have been enshrined in architecture. They get loaded in special registers, and flagged in memory with tag bits that are not accessible as ordinary memory, but only via interactions with the CHERI ISA.
The design of CHERI architectures for MIPS, RISC-V, and Arm began with the Sail instruction set definition language. Sail generates sequential emulators, in C and OCaml, and theorem-prover definitions, in Coq, HOL4, and Isabelle, and SMT. These versions allow for both a means of testing in emulation and creating formal proofs of the correctness of the design.
In January of 2022, Arm announced the Morello board, a system-on-chip (SoC) design that implements CHERI. Morello represents the first time that CHERI has been implemented in silicon, rather than emulations (QEMU) and FPGA versions of MIPS and RISC-V. All versions of CHERI include a toolchain of CHERI Clang/LLVM/LLD and GDB, Cheri-FreeRTOS, and CheriBSD.

The author wishes to thank Robert N. M. Watson and Peter G. Neumann for their assistance in writing this article.
Comments
A very useful article about