Author: Roddy Urquhart, Sr Technical Marketing Director, Codasip
Introducing CHERI
With cyber-attacks on systems growing in frequency and sophistication it is essential to improve the security of software execution. Many vulnerabilities arise from the use of traditional memory-unsafe C/C++ languages. Other challenges arise from integrating applications from a wide variety of code sources including in-house, commercial, and open source. With varied provenance there are varying degrees to which the sources can be trusted.
Approaches to tackling memory safety are at compile time or run time. Memory safe languages such as Rust provide compile time assurance. However, in practice it is prohibitively expensive to use only memory safe languages and not to draw on existing C/C++ code sources. Also, even memory safe languages need to be used in ‘unsafe’ ways for low level programming of operating systems and drivers – for example Unsafe Rust.
Run-time counter measures may be implemented in software or hardware and can be either statistical or deterministic. Stack canaries are common statistical software counter measures but while providing some protection they succumb to brute force attacks. Arm’s Memory Tagging Extension (MTE) is an example of a statistical approach in hardware using 4-bit meta data to implement a lock/key mechanism. With just 16 possible values a diligent hacker can unpick the lock.
CHERI, standing for Capability Hardware Enhanced RISC Instructions, aims to address memory unsafety and to provide scalable software compartmentalization. CHERI achieves this by using architectural capabilities as unforgeable tokens of authority. CHERI, like RISC-V, is an open standard and is also ISA-independent.
CHERI has been a research project principally involving the University of Cambridge and SRI International since 2010. With this solid base, CHERI is now moving into commercial deployment and the first such use will be based on the RISC-V architecture.
In this blog post we cover some of the basic aspects of how CHERI capabilities can enhance runtime security and address common security concerns. We also discuss how the Codasip A730 application processor was designed to include CHERI instructions and microarchitectural features.
Some software-related security challenges
Memory safety is one of the most widespread and severe issues in cyber security. Microsoft’s Security Response Center (MSRC) has stated that consistently ~70% of CVE (Common Vulnerabilities and Exposures) reported relate to memory safety. Similar figures have been reported by the Chromium Project and Ubuntu. Out-of-bounds write and out-of-bounds read have been consistently ranked among the top Common Weakness Enumeration (CWE)s ranking 1 and 7 respectively. Even a recent White House statement on cyber-attacks stated “Some of the most infamous cyber events in history … were headline-grabbing cyberattacks that caused real-world damage to the systems that society relies on every day. Underlying all of them is a common root cause: memory safety vulnerabilities.”
Fig. 1 pointers
The root cause of these memory safety issues is the use of pointers in C/C++ these being integer variables containing a memory address. Programmers have complete freedom to determine the values of pointers which gives the programmer both great power and potential to create vulnerabilities.
Consider the pointer in fig. 1 and let us say we have a buffer in memory with a defined upper and lower bound. C & C++, with no constraints on buffer bounds, allow the address to be defined outside the bounds as well as inside. This enables both out-of-bounds writes which corrupt memory and out-of-bounds reads such as the Heartbleed vulnerability in OpenSSL.
Fig. 2 Integrating software from multiple code sources
In the past, it was not unusual to write entire applications in-house from scratch but using in-house libraries. With in-house code it was manageable to review the code for vulnerabilities. Today complex applications are routinely assembled from multiple internal and external sources. There are huge volumes of open-source code available as well as code licensed from commercial 3rd parties.
Checking multiple sources of code is hugely challenging and there may be other complications including:
- Old libraries: some may be well-used but if they are old, it is possible that the original developers are no longer available for support. They may have changed company or have even retired.
- Binaries: If a third-party licenses source code, it is possible to inspect it for good coding practice. However, if binaries are licensed it is impossible to assess the source code that was used to generate them.
- Open-source security risks: Overall, open-source software such as Linux has been very successful. However, its very openness can potentially allow bad actors to deliberately introduce code vulnerabilities.
What is a CHERI capability?
A CHERI capability replaces a pointer with a more complex atomic token. For example, a 64-bit pointer will be replaced by a token with a 64-bit integer address, 64-bit metadata and a 1-bit Tag.
Figure 3: CHERI capability overview
The metadata includes:
- Upper and lower bounds of a buffer
- Architectural permissions (including read, write, capability, execute and access to privileged CSRs)
- A sealing bit which can prevent modification and limit use
- Software defined permissions.
In addition, a 1-bit tag is used to indicate capability integrity. These tags are set under hardware control being readable by software but not directly writeable. If an instruction attempts to use an untagged capability, a hardware exception will be thrown.
CHERI capabilities have the following properties:
- Provenance: they are always derived via valid manipulations of other capabilities
- Monotonicity: the rights associated with derived capabilities shall only ever be equal or less permissive
- Integrity: corrupted capabilities cannot be dereferenced
When a processor has a hardware reset, initially the program counter capability (PCC) and default data capability (DDC) have infinite bounds and permissions. After the boot loader, the OS is given a memory capability and PCC & DDC restrictions. Applications are then assigned memory regions with caps and architectural permissions. This process follows the principles of provenance and monotonicity.
How capabilities help memory safety
By including explicit buffer bounds in metadata, capabilities can ensure spatial memory safety. The capability acts as a better “smart” pointer.
Figure 4: bounds checking with CHERI capabilities
By being aware of the upper and lower bounds, memory access is permitted (green arrow) if the address is within the bounds and otherwise blocked (red arrow). In this way CHERI can prevent the common and serious out-of-bounds write and out-of-bounds read vulnerabilities.
How capabilities help manage software trust
Compartmentalization has been used to ensure that different software is given limits in terms of its rights. For example, privilege modes are used to vertically compartmentalize software with full rights to processor resources restricted to drivers and other low-level software while applications have more limited rights.
With processors running software with differing levels of trustworthiness it is common to horizontally separate memories into enclaves. Secure applications are limited to their secure execution environment (SEE) while other less trusted ones run in one or more rich execution environments (REE).
CHERI capabilities enable a more sophisticated, scalable compartmentalization of software.
Figure 5: scalable compartmentalization with CHERI
CHERI enables the simultaneous use of vertical and horizontal compartmentalization. Capabilities enable sandboxing at a variety of granularities. For example, a hypervisor, operating system, or application can be given a compartment. At a low level, individual drivers or even functions can be compartmentalized. This allows less trustworthy code to be restricted very precisely.
Using CHERI scalable compartmentalization eliminates the need for execution modes (M/S/U) thus avoiding the performance penalty of context switching.
Implementing CHERI with Codasip’s A730
With CHERI having reached maturity, Codasip has developed the first commercially licensed processor core using the A730 dual-issue application core as the base. With CHERI involving extending the instruction set of a RISC core, RISC-V is an ideal ISA for implementing CHERI given its modularity and extensibility. Codasip describes all its cores using the processor description language CodAL which has facilitated developing standard and CHERI versions of A730 using the same codebase.
Fig 6: Overview of A730 showing CHERI-specific blocks
The baseline A730 is a 64-bit RISC-V core with 64-bit general purpose registers. With CHERI capabilities needing an additional 64-bits for metadata plus a tag bit, a metadata register file is needed to accommodate this. Similarly, CHERI requires additional control and status registers (CSR). The program counter (PC) is replaced with the program counter capability (PCC). CHERI instructions are used for operations on CHERI capabilities requiring support in hardware. Simpler operations such as querying metadata are supported by extending the ALUs while more complex operations such as bounds calculation are supported in the CHERI calculation unit (CCU).
The additional metadata and tag also require support in the load/store unit and memory subsystem. This requires a 129-bit bus (double 64-bits plus the tag bit). In the case of off-chip DDR memory the memory word cannot be extended requiring more complicated logic to keep tag atomic with the capability data. Additionally, peripherals can be made CHERI-aware.
The above microarchitectural features add a small overhead to the processor design. But there are savings too. Most RISC-V cores included a physical memory protection (PMP) unit which provides coarse-grained protection typically in 16 regions. This unit is both costly in area and power hungry. With the fine-grained protection and compartmentalization of CHERI this unit can be removed and replaced by more power and area efficient circuits.
CHERI modes
One of the objectives of the CHERI project was to support the continued use of existing C/C++ code. To take advantage of the improved security possible through CHERI capabilities, some software rewriting is necessary, and the code must be compiled using a CHERI-compatible compiler. The software impact is greatest with low-level system code such as bootloaders and firmware. However, the impact on application code is minimal (<0.5%),
CHERI supports two modes of operation:
- Purecap : with all pointers are converted to capabilities
- Legacy: standard RISC-V code can run alongside purecap code
With legacy mode, C/C++ code the standard compiler can be used but the security benefits of CHERI are not available. With purecap mode a CHERI compatible compiler must be used, and the full security benefits of CHERI are realized.
Conclusion
With growing cybersecurity threats the vulnerability of software written in memory unsafe languages is a major concern. CHERI, a deterministic hardware-based security approach can address two major categories: a) memory safety and b) scalable compartmentalization. It is estimated that these two categories account for 74% of serious CVEs in Linux. Some very damaging vulnerabilities – such as Heartbleed – would have been prevented by CHERI.
CHERI is a mature technology after over a decade of research and so Codasip has developed the first commercially licensed processor IP core with CHERI. RISC-V – already demonstrated as a target by the University of Cambridge – provides an excellent starting point for extending the ISA with CHERI instructions. Codasip has implemented the necessary microarchitectural features to implement CHERI on the A730 application class core. CHERI brings major security benefits while having a minimal cost in performance.