Examples

This directory contains a number of examples to understand the system:

  1. Hello world is a simple example with a single compartment.
  2. Compartmentalised hello world splits the first example into two compartments.
  3. A more secure compartmentalised hello world protects the UART compartment from the previous example against malicious callers.
  4. A demonstration of heap temporal safety shows that use-after-free bugs will deterministically trap.
  5. A sealing demonstration shows how the CHERI sealing mechanism can protect opaque types across compartment boundaries.
  6. A trivial producer-consumer system shows the basics of inter-thread communication.
  7. Handling errors in compartments shows how to recover from crashes in compartments.
  8. Memory safety examples demonstrates how the CHERIoT platform enforces memory safety.
  9. JavaScript is a simple example embedding a JavaScript VM in a compartment.

Each example contains a readme file explaining what it is showing.

Building an example

Each example is built with xmake, which first requires a configure step in the terminal:

$ cd {example_dir}
$ xmake config --sdk={path-to-cheriot-llvm-tools} -P .

If you are using the dev container then the --sdk flag will be --sdk=/cheriot-tools/.

You can pass some additional flags to this step.

  • -m {debug,release} will switch between debug and release builds.
  • --debug-{allocator,scheduler,loader}={y,n} will enable verbose output for the specified core RTOS component.
  • --board={board name} to compile for a target other than the default (the interpreter generated from the formal model).

Next, build the firmware image with:

$ xmake -P . -v

The -v (verbose) flag is optional but an xmake bug prevents the objdump output from being generated if it is not specified. You will then end up with a firmware image and a .dump file containing the objdump output in build/cheriot/cheriot/{debug,release}. The penultimate two status lines of the output will be something like:

[ 95%]: linking firmware build/cheriot/cheriot/debug/producer-consumer
[ 95%]: Creating firmware dump build/cheriot/cheriot/debug/producer-consumer.dump

The first of these tells you the path to the firmware image, the second the location of the dump file that is a (somewhat) human-readable version of the same file.

By default, the examples are built targeting the interpreter that is generated from the Sail formal model of the ISA. This is the gold model, so anything that runs there should run on any compliant implementation. This interpreter includes an ELF loader and so can run the examples directly, for example:

$ cheriot_sim -V ./build/cheriot/cheriot/debug/producer-consumer

Where debug is the value that you passed to the -m flag (debug is the default and the path that ends in producer-consumer is the path from the build output.