CC Blog Design Solutions Research & Design Hub

How CHERI Helps Secure Your C/C++ Code

Written by Colin O'Flynn

On an FPGA

Most embedded attacks either start with or end with illegal memory accesses. The typical linear address spaces of most microcontrollers, combined with the many years of non-memory-safe legacy C/C++ code, mean that this will be a threat for many years to come. A newer technology called CHERI is trying to add memory safety to your existing code, and a recent open-source RISC-V version called CHERIoT has turned it into something you can experiment with today.


  • How does CHERI add memory safety to existing code?
  • What is CHERIoT?
  • How can I use CHERIoT?
  • CHERIoT

This column normally covers how to attack embedded systems. For this special issue, I’m taking a step back to look at how to build secure embedded systems. Ultimately, it’s the goal of most embedded engineers to improve their systems. I talk about embedded attacks because understanding attacks is an important step in the process. But once you know the attacks, what do you do next?

In this article, I’m going to introduce a new technology called Capability Hardware Enhanced RISC Instructions (CHERI), which is an extension to microcontroller (MCU) Instruction-Set Architectures (ISAs) that builds in capabilities for fine-grained memory protection and software compartmentalization. The exciting thing about CHERI is that it provides a way for you to take existing C/C++ code (which famously ends up with lots of security vulnerabilities) and provide protection against entire classes of attacks, including ones I’ve shown you before. This means the “what you do next” step may require little effort beyond recompiling your code (and hoping your RISC-V core has the CHERI extensions).

CHERI technology has been around for a few years, and Arm has even built some demonstration boards (called the “Arm Morello”) that include this technology. More recently, an open-source RISC-V specification called CHERIoT was produced, and a demonstration RISC-V core called CHERIoT-Ibex was released which allows you to experiment with this on an FPGA development board. The technology is even easier to access thanks to a new project called the “Sunburst Project,” which will have a special-purpose development board (the “Sonata Board”), designed by yours truly. Watch the lowRISC website for future details of this design. The board design will be open-source, so you can build one yourself if you’re handy with the soldering iron!

ATTACK THE MEMORY

Before we dive into the details of what CHERI is, let’s look at how the most common embedded system attacks work. Most attacks on embedded systems exploit improper access to memory. This works in practice because of two simple facts:

  1. Most embedded systems have one memory space containing everything.
  2. Memory protection, if enabled at all, may not be fine-grained enough to prevent an attacker from reading (or writing) sensitive data.

Buffer overflows are a good example of a simple attack here. The basic idea of a buffer overflow is shown in Figure 1. In a buffer overflow, an attacker overwrites the end of a buffer, which ends up writing data onto the stack. This stack normally includes return addresses, which allows an attacker to change the control flow of the program. In other cases, the attacker is able to write executable code that the victim jumps to and executes.

FIGURE 1
Writing to or reading from memory is a constant source of problems in embedded systems.
FIGURE 1
Writing to or reading from memory is a constant source of problems in embedded systems.

Other common attacks include reading past the end of memory, or reading memory they shouldn’t have access to. This might be possible with logic flaws, such as improperly checking the bounds of a request. But also many of my fault injection attacks exploit this, like when I showed you how I read the private key from a Bitcoin wallet using a fault injection attack. See my article in Circuit Cellar #346 (“Attacking USB Gear with EMFI: Pitching a Glitch” Circuit Cellar 346, May 2019), or my paper “MIN()imum Failure: EMFI Attacks against USB Stacks,” links to both of which are available on Circuit Cellar’s Article Materials and Resources webpage [1][2].

All of these attacks are successful because the processor executing a read (or store) instruction has no context about what the command should or should not have access to. Generally, a low-level read (or store) instruction has access to a huge range of memory. Processors may have a secure and unsecure (or privileged and unprivileged) mode that provides some bounds, but it still leaves the problem that a single flaw in the secure mode gives access to the entire secure memory space.

EVERYTHING OLD IS NEW AGAIN

In an alternate history, we never would have these problems at all. A friend introduced me to the (failed) Intel iAPX 432 processor from 1981, a processor that was built with object-oriented programming supported in hardware. Circuit Cellar’s Article Materials and Resources webpage includes a link to an interesting article detailing this device [3]. It’s too much to cover in a few paragraphs.

The processor is described as “anti-RISC” to set the stage for what comes next. As an example of the complexity, the variable-length instructions could be from 6 to 321 bits, and didn’t need to be stored byte-aligned. All this complexity did buy you a fully memory and capability-safe processor, long before people were thinking seriously about computer security.

Fundamentally, the iAPX 432 implemented the idea of instructions operating on objects. This means it was impossible to “read beyond” memory, since memory existed only for the given purpose. Like many failed good ideas, the practical implementation left much to be desired. The implementation choices resulted in such excessive performance hits that it simply wouldn’t survive in the marketplace.

Forty years later, CHERI offers memory and capability-safe processors as well. But unlike the iAPX 432, it offers it in a RISC format, and with a minimal overhead. Work has been done to ensure this overhead remains small even with practical considerations, such as how the DRAM refresh cycle impacts trying to add memory tagging. This practical focus is what makes CHERI exciting (and what makes it unlike the iAPX 432)—it’s not just a research project, but a complete set of tools including specification, compilers, debuggers, reference cores, and more.

TAG YOU’RE IT

When discussing the previous attacks, it often comes down to: an attacker should only be able to access a certain segment of memory. A pointer should point to an 8-byte buffer for example, but an error in the bounds check logic lets them access memory beyond the end of the buffer. Or a user passes a string to a print() call which is missing the null, resulting in the print() call dumping additional sensitive data.

One way to solve this is by using memory-safe languages (such as Rust). These languages provide the memory with protection as part of the output of the compiled code, and provide language syntax to use these features.

The big downside to using a memory-safe language is it requires rewriting your code in a memory-safe language. If you have many years of legacy code to support, this can be no small feat. Instead of doing this with the compiler output, CHERI does this in hardware with tags.

The tag format in Figure 2 shows that the pointers being referenced suddenly have a few extra fields. The inclusion of a bounds field means an attacker no longer has access to arbitrary lengths of memory. This bounds is somewhat cleverly encoded to reduce the bit-space needed, by using a “floating-point” or “logarithmic” type encoding. That means you have more precision at smaller boundary sizes, but for larger blocks must pick the closest boundary.

FIGURE 2
CHERI adds bounds and capabilities to memory spaces.
FIGURE 2
CHERI adds bounds and capabilities to memory spaces.

The validity tag is a single bit indicating if the memory access should be used at all, and the type and permission provide additional granularity. Memory can be made read-only or disallow execution through the permissions.

The validity tag in Figure 2 isn’t shown as being in the same memory space, as it’s held in an out-of-bounds memory. Modifying this requires special instructions, which ensures that an attacker cannot simply mark invalid memory as valid. The validity tag is cleared by hardware when capabilities become invalid as well.

Beyond memory safety, CHERI enables a variety of other security features, including that:

  • It makes it easy to compartmentalize your software so that tasks can only access their own memory.
  • It makes it possible to easily pass pointers which allow read-only access (enforced by the core itself and not just a polite request).
  • It can seal sections of memory to prevent modification.

The best way to see these in action is to look at a few examples, and I’ll use the CHERIoT-RTOS project for that.

USING CHERIOT

The CHERIoT-RTOS project is a Real-Time Operation System (RTOS) that supports CHERI features to provide a high level of security. To be clear, you don’t need to use CHERIoT-RTOS to access the security features of CHERIoT. But it provides a useful framework for experimenting with CHERIoT.

The CHERIoT-RTOS repository includes numerous examples of using the CHERI extension. These can run on the CHERIoT RISC-V core, be it an emulator or the real CHERIoT-Ibex soft core which you can program into an FPGA board. Soon this will be even easier to experiment with on the open-source Sonata Board, which includes all required debugging hardware.

I’ll bring up a simple example so you can get an idea of how the CHERI extensions work. To start with, let’s look at simply printing a few different strings. This is shown in Listing 1, and recreates the hello.cc file from the error-handling examples that are part of the CHERIoT-RTOS repository.

You’ll see this includes three calls to the write() function, which sends data out the UART. The implementation is shown in Listing 2. Note that there is no special handling at all to check the validity of the passed memory. The only call is one that checks for a lock to prevent concurrent entry (which would be common in most RTOSs).

LISTING 1
The “hello.cc” file from 07.error_handling example

// Copyright Microsoft and CHERIoT Contributors.// SPDX-License-Identifier: MIT#include “hello.h”#include <fail-simulator-on-error.h>/// Thread entry point.void __cheri_compartment(“hello”) entry(){	// Try writing a string with a missing null terminator	char maliciousString[] = {‘h’, ‘e’, ‘l’, ‘l’, ‘o’};	write(maliciousString);	// Now try one that doesn’t have read permission:	CHERI::Capability storeOnlyString{maliciousString};	storeOnlyString.permissions() &= CHERI::Permission::Store;	write(storeOnlyString);	// Now one that should work	write(“Non-malicious string”);}
LISTING 2
The write function of “uart.cc”

/// Write a message to the UART.void write(const char *msg){	LockGuard g{lock};	Debug::log(“Message provided by caller: {}”, msg);}

If a memory error occurs, a handler can capture that to print a useful debug message. But it doesn’t require you to add any memory safety check. The hardware provides memory safety checking, which is the entire point of CHERI.

Going back to Listing 1, the first call to write() is missing the null terminator. This results in the function attempting to read beyond the allowed memory space, and it shows how CHERI can help with this common problem. The second call to write() shows how CHERI’s capabilities give you more control over how data is used. Here the passed string doesn’t actually have read capability; it’s only allowed to be used for storing data. Again, the hardware prevents the write() function from reading from this memory.

A SUNNY FUTURE

If the examples in this column have piqued your interest, take a look at the CHERIoT repositories to see all the details of both the RTOS and core [4]. And watch the lowRISC website for more about the Sunburst Project, which will include the open-source Sonata board to make it easy to run the sort of demos I showed in Listing 1.

When it comes to practical usage, you’ll of course need CHERIoT implemented in some physical MCU. Right now, the answer to that isn’t as clear—I don’t know of any commercial MCUs planned with CHERI support. But hopefully, with a few more accessible examples, we’ll see it get picked up. But the soft-core CHERIoT-Ibex that is currently available has the advantage of not locking you into a specific configuration.

CHERI is an exciting technology to me because it doesn’t have to be turned on all at once. If you have a CHERI-enabled MCU, you can use your existing code almost as-is. From there, improving the security can be done in stages by adding in the additional features to your code. To me this is the main advantage of CHERI, and why it has a higher chance of finding commercial relevance. It doesn’t require you to rewrite your entire codebase at once. For better or worse, it might give all that memory-unsafe C/C++ code another lease on life in a world where more people are demanding security by design. 

REFERENCES
[1] Colin O’Flynn, “Attacking USB Gear with EMFI: Pitching a Glitch.” Circuit Cellar 346, May 2019, pp. 44-51.[2] “MIN()imum Failure: EMFI Attacks against USB Stacks” by Colin O’Flynn: https://www.usenix.org/system/files/woot19-paper_oflynn_0.pdf[3] “iAPX432: Gordon Moore, Risk and Intel’s Super-CISC failure”: https://thechipletter.substack.com/p/iapx432-gordon-moore-risk-and-intels[4] CHERIoT-RTOS Repository: https://github.com/microsoft/cheriot-rtos

SOURCES
An Introduction to CHERI: https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-941.pdf

RESOURCES
lowRISC | lowrisc.org

Code and Supporting Files

PUBLISHED IN CIRCUIT CELLAR MAGAZINE • NOVEMBER 2023 #400 – Get a PDF of the issue

Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.


Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
Website | + posts

Colin O’Flynn has been building and breaking electronic devices for many years. He is an assistant professor at Dalhousie University, and also CTO of NewAE Technology both based in Halifax, NS, Canada. Some of his work is posted on his website (see link above).

Supporting Companies

Upcoming Events


Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2024 KCK Media Corp.

How CHERI Helps Secure Your C/C++ Code

by Colin O'Flynn time to read: 9 min