Edinburgh Research Explorer Verified Security for the Morello Capability-enhanced Prototype Arm Architecture

,


Introduction
Memory safety bugs continue to be a major source of security vulnerabilities, responsible for around 70% of those addressed by Microsoft security updates, and around 70% of the high-severity bugs impacting Chromium [30,14].Their root causes are well-known legacy design choices and limitations of normal practice: pervasive uses of systems programming languages that do not enforce memory protection; hardware that enforces only coarse-grain protection, using virtual memory; and test-and-debug development methods that cannot provide high assurance.These are baked in to the critical systems codebase across the industry, and the result, in today's adversarial environment, is that programming errors can often lead to exploitable vulnerabilities.
There are many possible approaches to improving this situation, including development of safer programming languages, techniques for full functionalcorrectness verification, and better bug-finding tools.Each is the subject of much research in programming languages and semantics, and all are worthwhile, but the legacy investment, the need for systems code to work close to the machine, and the inability of bug-finding to provide high assurance, have made it very hard to radically improve mass-market systems.
Another path, less well explored, is to change the architectural interface to provide hardware mechanisms that enable better enforcement of memory protection.Over the last twelve years, the CHERI project [1] has been extending conventional hardware Instruction-Set Architectures (ISAs) with new architectural features to enable fine-grained memory protection and highly scalable software compartmentalisation.The CHERI memory protection features allow historically memory-unsafe programming languages such as C and C++ to be adapted to have quite different semantics, replacing many unpredictable undefined behaviour (UB) cases with predictable fail-stop traps, to provide strong and efficient protection against many currently widely exploited vulnerabilities.Crucially, this requires only minor changes to the sources of existing systems software.The CHERI scalable compartmentalisation features enable the finegrained decomposition of operating-system (OS) and application code, to limit the effects of security vulnerabilities.
CHERI provides these via hardware support for unforgeable capabilities: in a CHERI ISA [54], instead of using simple 64-bit machine-word virtual-address pointer values to access memory, restricted only by the memory management unit (MMU), one can use 128+1-bit capabilities that encode a virtual address together with the base and bounds of the memory it can access.Encoding these within the capability enables a fast access-time check, faulting if there is a safety violation.A one-bit tag per capability-sized and aligned unit of memory, cleared in the hardware by any non-capability write and not directly addressable, ensures capability integrity by preventing forging, and the ISA design lets code shrink capabilities but never grow them.This architectural mechanism, along with additional sealed-capability features for secure encapsulation, can be used by programming language implementations and systems software in many ways.
Previous academic work on CHERI has developed CHERI-MIPS and CHERI-RISC-V architectures, FPGA processor implementations, and system software including adaptions of Clang/LLVM, linkers, debuggers, FreeRTOS, FreeBSD, and WebKit.The CHERI processor prototypes implement techniques such as compressed capability bounds [58], and a tag controller and cache [26] required to implement memory tagging on off-the-shelf DRAM.The software prototypes use CHERI's architectural features to implement memory-safe CHERI C/C++ programming languages [55], fine-grained spatial memory safety [15], heap temporal memory safety [15], and scalable software compartmentalisation [57].An analysis of vulnerabilities reported to the Microsoft Security Response Center (MSRC) in 2019 suggested that CHERI memory safety would have deterministically mitigated 30%-70%, depending on the usage scenario [27], and porting the FreeBSD kernel and userspace to CHERI required changes only to 0.18% and 0.04% LoC respectively.Analysis of an open-source desktop stack [53] estimated a 73.8% vulnerability mitigation rate through a combination of memory protection and software compartmentalisation requiring a 0.026% LoC change.
Achieving widespread adoption of any substantial new architectural feature is also challenging, of course, but the issues differ from those for adoption of a new high-level programming language.It needs coordinated hardware and software change, which is hard to arrange, but on the plus side there are very few architecture vendors, so if a feature becomes (say) part of the mainline Arm architecture, and there is pull from major partners, then it will be implemented in all conforming Arm implementations and become ubiquitously available in devices.For CHERI, the academic results are encouraging, but achieving such adoption first needs an industry-scale evaluation of a high-performance silicon processor implementation and software stack above it, to demonstrate viability and enable that pull.This is beyond what can be done academically, but hard to justify as a purely commercial project.The 2019-24 UKRI Digital Security by Design (DSbD) challenge resolves this chicken-and-egg difficulty with a combined public-sector and industry (£70m+117m) programme to build and evaluate such demonstration platform, and support research and development above it [52].
Arm, supported in part by DSbD, is currently designing and building Morello, a CHERI-enabled prototype architecture, processor, system-on-chip (SoC), and development board, extending the Armv8.2-Aarchitecture and the high-performance Neoverse N1 processor [6,8].The Morello processor and SoC implement the CHERI ISAv8 protection model, and utilise CHERI's compressed capability bounds and tagged memory approaches.As of 2021-01, the architecture, emulators, initial development boards with Morello silicon, and initial software toolchains, have all been developed.This will allow evaluation of the CHERI mechanisms in a variety of configurations and use cases on a state-of-the-art hardware platform, and paves the way for the potential adoption of CHERI into future production architectures and devices.
In this paper, we describe work to put the Morello architecture and its security properties on a solid mathematical footing from the outset, and to use semantics to ease conventional engineering.For a new architecture that aims to provide security guarantees, it is especially important to provide high assurance that it actually does.Otherwise, any security flaw in the architecture will be present in any conforming hardware implementation, quite likely impossible to fix or work around after deployment, and the resulting loss of confidence might make further adoption impossible.
For Morello, this is challenging in two ways.First, CHERI needs to be deeply integrated into each base architecture it gets adapted to, most obviously by modifying all virtual-memory-accessing instructions to check bounds and permissions of capabilities, and by adding instructions to explicitly manipulate capabilities, but also in more subtle ways relating to exceptions, virtualisation, and so on.Second, the architecture specification is large and complex.The base Armv8-A architecture is defined in an 8200-page manual [7], to which the Morello architecture supplement adds 1200 more [8].Fortunately, Arm have recently shifted to using an executable version of their ASL language for instruction-set architecture specification [40,41].The sequential behaviour is all defined in ASL, and this is what appears in instruction descriptions and auxiliary functions (e.g. for capability compression and address translation) in the documentation.However, it remains very large, 62 000 non-whitespace lines of specification (LoS), and ASL does not itself have a mechanised semantics.
The main intended security property of the Morello architecture is reachable capability monotonicity, with the intuition that the available capabilities cannot be increased during normal execution (i.e., they are monotonically decreasing).This is a whole-system property about arbitrary machine execution, and conventional techniques cannot provide high assurance that the architecture satisfies it.Instead, it needs proof.We translate the Arm ASL definition via the Sail [9] language into Isabelle/HOL [39], extending previous work for Armv8-A, and give a mechanised statement and proof that the property holds of the architecture.
We deal with the challenge of scale by factoring the proof via a narrow abstraction: four relatively simple properties of arbitrary CHERI instruction execution that capture essential aspects of their behaviour.Our intra-instruction semantics focusses on the behaviour of instructions in isolation, interacting with registers and memory, rather than viewing each thread as a single state machine; this monadic interface lets us conveniently express these abstract-CHERI properties of instructions in terms of their register and memory effects.We prove capability monotonicity for arbitrary sequences of instructions above this abstraction, and we instantiate the abstraction for Morello and prove that its many instructions satisfy the required properties.Manual proof effort was required for a number of helper functions defined in the architecture for manipulating and using capabilities, but the bulk of the architecture is handled by automatic proof tools and tactics.Previous work by Nienhuis et al. [38] proved similar results for the much simpler and smaller (6k LoS) CHERI-MIPS architecture with a different approach, manually defining a larger set of abstract actions and proving that those do abstract the instruction semantics.That let one capture instruction intentions more explicitly, but needed more ad hoc machinery, while the new approach we follow here handles the 10x scale-up successfully.
Our proof was developed while the architecture and hardware design were still evolving, using weekly snapshots of Arm's ASL specification, with our automation letting us quickly adapt to changes.This let us identify a number of bugs that could be fixed before the architecture and hardware were finalised.
To validate the ASL-to-Sail translation of the Morello specification, we used the C emulator automatically generated from the Sail model to compare it against Arm's internal Architecture Compliance Kit (ACK) test suite.
Finally, we developed a test generator, using the Isla symbolic execution tooling for Sail [10], to automatically generate interesting instruction-sequence tests, aiming at good specification coverage.These complemented Arm's test suite and were used by Arm as part of their pre-tape-out validation, and were used as the main test suite for development of a Morello version of the QEMU emulator.This helped uncover some bugs in our own tooling as well as discrepancies between different Morello models and emulators.We also used Isla and an earlier Sail-to-SMT flow for quick checking of properties of capability compression.
To summarise, our contributions are: -A formal and executable semantics of the Morello ISA ( §3), automatically translated from the Arm ASL to Sail, Isabelle, and C, and validated against the Arm ACK ( §6).-An abstract characterisation of the essential properties of CHERI ISA instructions, expressed over their intra-instruction semantics ( §4).-A mechanised proof of capability monotonicity for the full sequential Morello ISA specification (including all instructions, system registers, capability compression, etc.), with large parts of the proof automatically generated, making the proof more maintainable as the architecture was developed ( §5).-Automatic ISA test generation from the specification ( §7).
This gives us machine-checked mathematical proofs of whole-ISA security properties of a full-scale industry architecture, at design-time.To the best of our knowledge, this is the first demonstration that that is feasible, and it significantly increases confidence in Morello.
The main proof took only around 24 person-months, by two people between 2020-03 and 2021-07, following around 23 person-months of preliminary work to get the model into usable Sail and Isabelle forms, to develop our CHERI abstraction in the context of earlier CHERI architectures, and on our Sail-to-SMT flow.Test generation and ACK validation took an additional 17 personmonths, including Morello-specific work on Isla.This suggests that such proof could be not just technically but also economically viable for new architecture design, particularly as doing this routinely, as an established flow, would reduce the effort substantially.
As a side benefit, our well-validated Morello semantics is reusable for future software or hardware verification.The Armv8-A ISA is, along with x86, one of the two most important low-level programming languages, and if Morello is successful, then one would expect CHERI extensions to be similarly widely used.
Sail and Isabelle versions of the Morello specification, as well as our definitions and proofs, are available online [3].
Non-goals and limitations (1) Our results establish confidence that the Morello instruction set architecture design satisfies its fundamental intended security properties.We do not address correctness of the Morello hardware implementation of that architecture, which would be an extremely challenging hardware verification task, and we do not cover system components that are not specified by the ISA itself, e.g. the Generic Interrupt Controller (GIC).(2) The architecture, as usual, expresses only functional correctness properties, not timing or power properties, to allow hardware implementation freedom.Properties and proofs about the architecture therefore cannot address side channels, but see [56] for discussion of side-channels and CHERI.(3) We consider only the sequential architecture.Studying concurrency effects would require a more complex system model integrating the Morello sequential semantics with a whole-system concurrency memory model, which we leave to future work, but we expect the capability properties to be largely orthogonal to concurrency issues, as long as the write of a capability body and tag appear atomic.(4) We assume an arbitrary but fixed translation mapping.CHERI capabilities are in terms of virtual addresses, so system software that manages translations has to be trusted or verified.We also assume that the privileged capability creation instructions are disabled and no external debugger is active, because these features can in general be used to circumvent the capability protections, as discussed in §5.1.(5) Our capability monotonicity property is the most fundamental property one would expect to hold of a CHERI architecture, but it is by no means the only such property.However, stronger properties typically involve specific software idioms, e.g.calling conventions or exception handlers, and their proofs use techniques that have not yet been scaled up to full architectures.We return to this in §8.(6) We prove monotonicity of the Morello specification formally in Isabelle, however, our proof depends on an SMT solver as an oracle for one lemma, as discussed in §5.(7) Our conversion from ASL via Sail to Isabelle is not subject to verification, as neither ASL nor Sail have an independent formal semantics -their semantics is effectively defined by this translation.However, it is nontrivial, and there is the possibility of mismatches with the Sail-generated C emulator used for validation; we do not attempt to verify that correspondence.(8) The ASL specification is subject to the limitations documented by Arm in [7, Appendix K14], e.g. with respect to implementation-defined behaviour.A sophisticated compression scheme allows a capability to include 64-bit lower and upper virtual-address bounds, encoded into 87 bits in total, with 56 of those shared with the value field (see [8, §2.5.1], [58] for details).Small regions can be described precisely, with an arbitrary size in bytes, while for larger regions, only certain bounds and sizes are expressible.The capability value must be either within the bounds or within a certain range above or below, allowing for common C idioms that transiently construct (but do not dereference) slightly out-ofbounds pointers; other combinations of value and bounds are not representable.This scheme trades off bounds precision for reduced capability size: supporting arbitrary bounds would require more than 128+1 bits per capability, which would have unacceptable performance costs.
Four of the 18 permission bits are reserved for software, while the others have architecturally defined meaning.The Load, Store, and Execute permissions control whether a capability can be used for loading or storing data or fetching instructions.Permission bits for loading and storing capabilities, as opposed to data, also exist.The System permission controls access to system registers and operations, in addition to the access control mechanisms of the base Arm architecture.Capabilities can also be sealed, making them immutable and unusable for anything but branching to them; this allows controlled transitions between different security domains.Sealing (or unsealing) a capability requires an authority capability with the Seal (or Unseal) permission; more on this below.

Capabilities in Registers and Memory
Morello extends the Armv8-A general-purpose integer register file, as well as certain control and status registers, from 64 bits to 128+1 bits.Memory is extended with a tag bit for each 128-bit sized and aligned unit of DRAM.
The Program Counter (PC) is extended to become a Program-Counter Capability (PCC), constraining instruction fetch as well as PC-relative loads (e.g., of global variables).A new Default Data Capability (DDC) special register controls and transforms memory accesses relative to machine-word pointer values by legacy (non-capability) instructions, for legacy code using integer pointers.

Capability-aware Instructions
Morello extends Armv8-A with new instructions and modifies existing instructions to use and respect capabilities.For example, a Load capability (literal) instruction LDR <Ct>,<label> calculates an address from the PCC value and an immediate offset, loads a capability from memory, and writes it to capability register Ct [8, §4.4.76].If the PCC capability does not have the load permission, or the calculated address is outside its bounds, a capability fault exception is raised.The tag of the PCC capability is also checked (as part of instruction fetching).Most other instructions authorise loads and stores via a capability in an explicitly identified register, or use DDC, rather than implicitly use PCC.
Conventional execution flow is also controlled by capabilities, with branch instructions to capability destinations (or implicitly w.r.t. the PCC for legacy instructions).Here too the capability must have its tag set and the target virtual address must be within the bounds, and in this case it must authorise execution.
Then there are instructions to access and manipulate the fields of a capability, including arithmetic on its virtual-address value field (corresponding to conventional pointer arithmetic), comparisons, and other operations to extract and manipulate its permissions and other data.

Domain Transition
CHERI distinguishes between sealed and unsealed capabilities.An unsealed capability can be used directly (e.g. to load and store), but a sealed capability can only be used to request actions be taken by other software.This feature can be used in the context of protection domains or software compartments, in which whole subsystems are given access to a limited subset of memory.Domain X may have no direct authority to domain Y, but may call into domain Y by invoking one or more sealed capabilities originally sealed by (or for) Y.The invocation will install unsealed versions of the invoked capabilities in registers.This always includes replacing the current PCC, thus, this performs a jump to a specific code entry point provided by domain Y.These domain transitions are non-monotonic and must be treated specially in our proof.
Variations on this sealing and invocation mechanism enable slightly different calling styles.When sealing capabilities, they can be labelled with an object type, if the authorising capability has that object type in its bounds.The "branch to sealed capability pair" instruction invokes a given code capability and also an argument data capability, checking their object types match, providing object-style encapsulation.Three kinds of specialised sentry (sealed entry) capabilities may be used transparently by direct branch instructions, memory-indirect branch instructions, and memory-indirect branch-to-pair instructions, respectively.

Exceptions and the Memory Management Unit
In addition to compiler-facing instructions, system functionality such as virtual memory, cache management, and exception handling is also extended, e.g.adding new exception cause codes, and page-table permission bits for loading or storing capabilities.Because exception handling is able to restore reserved registers during exception-level transitions, it is also a form of domain transition, as reserved registers may contain capabilities not available to the executing code.

Using CHERI in Software
For context, we sketch how CHERI's capability mechanisms are used by software to control and constrain execution.The CHERI team has adapted a large open-source software stack to CHERI, including the LLVM compiler, linkers, debuggers, multiple OSs, and application suites.The verification in this paper is motivated by this software usage, but is itself purely about the architecture.
One of the main uses of capabilities is fine-grain memory protection.Spatial memory safety is achieved in CHERI C/C++ by implementing explicit pointers (those visible in the language, e.g.variables with pointer type) and implied pointers (used by the generated code and runtime, e.g. the stack pointer, PLT entries, and Global Offset Table pointers) with capabilities instead of conventional machine-word integers.These are protected (from corruption or reinjection) by the CHERI tag mechanism and monotonicity, and hence the memory contents they point to are protected, by the capability permissions and bounds checks, so long as no other capabilities give undesired access to them.This relies on compiler-generated code, the kernel, run-time linker, and C runtime (e.g., heap allocator) narrowing capability bounds and permissions during execution as appropriate.This protects against many cases in which a C/C++ coding error could lead to an exploitable vulnerability.
Temporal memory safety, additionally protecting against reuse-after-reallocation errors, is not directly supported by the architecture, but there are a variety of techniques to implement it, especially for heap memory, using CHERI's features [22].Morello extends the page-table mechanism to allow capability flow to be tracked through memory, supporting revocation of old capabilities.
The other main use of CHERI is software compartmentalisation, splitting the address space into different compartments running separate software.The capability monotonicity property ensures these components are contained in their compartment boundaries.Domain transitions are possible via the sealed capability mechanism, which can be used to set up various inter-compartment interfaces.Often these transitions will all be to a privileged control component, but the architecture also supports direct transition between two mutually distrusting pieces of code.Various software models are supported, from implementing fast inter-process IPC to sandboxed libraries within processes.

Concrete Semantics of Morello
The basis for our verification and validation work for Morello is the ISA specification written by Arm in their ASL language.It includes sequential semantics of the capability mechanisms and instructions, along with all of the Armv8-A AArch64 base architecture and its extensions supported by Morello, e.g.floating point and vector instructions, system registers, exceptions, user mode, system mode, hypervisor mode, some debugging features, and virtual memory address translation.In total, the Morello ASL specification is around 62 000 nonwhitespace lines, covering 409 instructions, 1050 encodings, 600 automatically generated accessor functions for reading and writing system registers, and 1500 additional helper functions.Arm provided weekly snapshots of the ASL specification while it was being developed.
ASL is a first-order imperative language with exceptions.Originally a paper language only, it was made executable by Reid et al. [40,41].It supports bitvectors of computed sizes, but bitvector indexing is not statically checked; it also supports mathematical integers and some limited structured types.The Arm documentation provides an informal description of the language [7, Appendix K14], but does not provide a formal semantics.We obtain a formal semantics of Morello by translating the ASL specification into Sail [9], a similar language but with a richer type system and open-source tooling, and thence into Isabelle/HOL, as 90 000 and 210 000 LoS respectively.Fig. 2 shows parts of the Sail semantics for the Morello LDR (literal) instruction for loading a capability from a PCC-relative address.This is just an iceberg-tip of the whole semantics, even just for this instruction: the MemC _ read involves all of address translation, and the call graph of the definitions shown amounts to 7 300 lines of Sail.
We reused the existing open-source Sail tooling and ASL-to-Sail translation [9,10] mostly as-is, with only minor improvements and some engineering work needed to handle Morello.In addition to the Isabelle definitions, we generate a C emulator for validation ( §6) using the Sail tool, and we reuse the Isla symbolic execution engine for Sail [10] to generate tests ( §7).

Abstract Formal Model of Capability Monotonicity
The main challenge in proving whole-ISA security properties of Morello is the scale and complexity of the model.Rather than a direct proof above the 210 000line Isabelle specification, we factor the proof via an abstraction (instantiated for Morello in §5) that captures the essential properties of arbitrary instruction behaviour in any CHERI ISA.It has to spell out aspects of CHERI in some detail, e.g. the different kinds of non-monotonic domain transitions (cf.§2.4), but it abstracts away ISA details not directly relevant for capability monotonicity.

ISA Abstraction
The abstraction is defined as properties of an arbitrary sequential ISA semantics, encoded in a monadic type with a trace semantics that exposes the individual register and memory effects of instructions.This interface was originally designed to connect Sail ISA semantics to relaxed memory models, but we found the factorisation via effects useful for reasoning even in a simple sequential setting.
The monad essentially corresponds to a free monad over an effect datatype.It is parameterised with a return type 'a, an exception type 'e, and a sum type of register value types 'regval (automatically generated by Sail for each ISA): Finished outcomes either indicate successful termination with a return value a (denoted as Done a), an exception (Exception e) which can be caught using a try _ catch combinator, or a failure (Fail msg), e.g.due to a failed assertion.Effect outcomes carry a continuation that expects a response and returns the next monadic outcome.Monadic return wraps a value in Done, while bind just nests the outcomes without interpreting the effects.We also define a corresponding type of events, e.g.E _ read _ reg (with only concrete values, not continuations), along with an effect trace semantics for monadic expression.We define our requirements on CHERI ISAs in terms of constraints on these traces in §4.4.

CHERI ISA Parameters
In addition to the ISA semantics themselves, our properties are parameterised on aspects of the ISA relevant to CHERI.This includes names of special registers, in particular the program counter capability register PCC, the invoked data capability register IDC (capability register 29 on Morello, r31 on CHERI-RISC-V), registers holding capabilities to exception handlers (VBAR _ ELn on Morello), and privileged registers requiring system register access permission.
Moreover, we need to know which instructions may perform sealed capability invocations, as this potentially constitutes a non-monotonic security domain transition.We model this as functions taking an instruction identifier and an effect trace of a particular execution, and returning, respectively, the directly or indirectly invoked sealed capabilities in the trace.For example, the Morello BRS instruction invokes the sealed capabilities in its two input registers, and other branch instructions can also invoke sealed capabilities if they are sentries.
Finally, the mapping from virtual to physical memory addresses is captured by a pure partial function taking a virtual address and a (partial) instruction execution trace, from which it can extract the required information about the address mapping to determine the physical address, if any.This is needed because capabilities are in terms of virtual addresses, but the memory effects produced by the ISA semantics are in terms of physical addresses, so we need a way to translate between those when formulating requirements on memory accesses in the abstract model.We also assume another function as a parameter to distinguish memory operations that happen as part of an in-memory translation table walk, as the constraints on them differ from those on other memory operations.

Capability Abstraction
We capture capabilities in the abstract model via a typeclass that provides methods for accessing the various fields of capabilities, as well as sealing and unsealing operations.We also define a notion of derivability that serves as an upper bound on the capability manipulations that instructions are normally allowed to perform.Starting from a set of capabilities C, e.g.provided as inputs to an instruction, the set of capabilities derivable from C is defined inductively as the smallest set that contains C itself as well as capabilities obtained from other derivable ones via one of the following: manipulating an unsealed capability c into c such that bounds or permissions are not increased, formalised using an ordering where c ≤ c iff either c = c, or c is untagged, or both are tagged and unsealed and the bounds and permissions of c include those of c ; turning a capability into a sealed entry capability; sealing a capability using another derivable sealing authority capability, setting the object type of the sealed capability to the current address value of the authority capability (interpreted as an object type), if the authorising capability is tagged and unsealed, has sealing permission, and its value (and therefore the object type) is within its bounds; or unsealing a capability using another derivable unsealing authority capability, if the latter is tagged and unsealed, has unsealing permission, and its value is within bounds and matches the object type of the sealed capability.
Of these operations, unsealing is the only one that may grant new privileges that are not already granted by the input capabilities.However, unsealing requires specific authority.An operating system, for example, can control what capabilities a user-space process can unseal by only handing out unsealing authority capabilities with a limited set of object types in their bounds.

CHERI ISA Intra-instruction Properties
Our abstraction is defined as the conjunction of four instruction-local properties.They are relatively straightforward to verify for a concrete ISA, and we will describe the proof for Morello in §5.At the same time, the properties imply the whole-ISA property of reachable capability monotonicity, as explained in §4.5.Hence, they serve as a useful intermediate abstraction layer for structuring the overall proof.
The central security guarantee that CHERI ISAs aim to provide is that software cannot forge capabilities and thereby escalate its privileges.Hence, we require that instructions only produce capabilities via the above derivation rules, except for the effects of well-defined transition mechanisms for switching control to another security domain.
Property 1 (Capability register writes).In any execution trace of a single instruction, for every write of a tagged capability to a register at a given point in the trace, one of the following holds: 1.The capability is derivable from the capabilities that the instruction has available at this point in the trace.2. The capability is an invoked capability and written to the PCC or IDC register as part of a sealed capability invocation.3. The capability has been loaded from an exception handler base register and is written to the PCC register as part of raising an ISA exception.
The first case permits the normal operation of instructions, manipulating capabilities according to the above derivability rules.We allow instructions to use their available capabilities in these operations, which normally includes capabilities read from registers or loaded from memory up to the given point in the trace, with some exceptions: First, capabilities read from privileged registers are unavailable unless the system access permission is also available, i.e. if a tagged and unsealed capability with that permission has been read from PCC before.Second, we exclude capabilities loaded as part of translation table walks, as those loads are not subject to capability checks (although none of the existing CHERI ISAs attempt to load capabilities during translation table walks).Third, capabilities used in a domain transition, e.g.capabilities loaded from memory as part of an indirect sealed capability invocation, are unavailable for normal operations and handled separately by the other cases of Property 1 as follows.
The sealed capability invocation case applies when the capability being written is an invoked capability of the current instruction, as declared when instantiating the CHERI ISA abstraction (see §4.2).Such an invocation performs a branch to the unsealed code capability by writing it to the PCC register, and possibly writes an unsealed data capability to IDC.One of the following cases must hold, representing the different supported kinds of capability invocation: Sealed pair A pair of capabilities sealed with the same, non-sentry object type and with BranchSealedPair permission is available, the capability that is being written is an unsealed version of one of those, and it is written either to PCC and it has the execute permission, or it is written to the invoked data capability register IDC and does not have the execute permission.Direct sentry The capability is written to PCC, and a version of it that is sealed with a sentry object type is available to the instruction.Indirect sentry An indirect sentry capability is available and used to load either two capabilities from memory that may be written to the PCC and IDC registers, or one capability that may be written to PCC while the unsealed version of the indirect sentry itself may be written to IDC.
The ISA exception case is signalled in the Morello model by the helper function AArch64.TakeException throwing a (Sail language) exception after setting up the branch to the exception handler.In this case, we allow a capability to the exception handler to be read from a privileged exception handler base register and written to PCC, even if system register access permission is not available.However, the definition of available capabilities together with our properties guarantee that this capability is not used for any other operations.

Fig. 3. Formal definition of capability register write Property 1, slightly simplified
We formalise Property 1 as a predicate on traces, given in Fig. 3.It takes a number of arguments that we instantiate using the CHERI ISA parameters of §4.2, e.g. with invoked _caps set to the capabilities that the given instruction invokes in the given trace.The predicate details the different cases (and invocation subcases) of Property 1 for all capabilities written to registers, using helper definitions such as available_caps or invokable (checking permissions and object types of a pair of sealed capabilities).
The other three properties state that capabilities stored to memory must be derivable from available capabilities (here there are no non-monotonic exception cases), and that accesses to memory or privileged registers must be authorised by capabilities with sufficient permissions and bounds.
Property 2 (Capability stores).Every tagged capability stored to memory at a given point in an execution trace of a single instruction is derivable from the available capabilities at that point in the trace.
Property 3 (Privileged registers).Reads from or writes to privileged registers in an execution trace of a single instruction happen only after a tagged and unsealed capability with system register access permission has been read from PCC, unless an ISA exception is raised in the trace and the event is a read from an exception handler base register.
Property 4 (Memory accesses).For every load or store event at a given point in an execution trace of a single instruction, there is a tagged capability available at that point in the trace that authorises the memory operation (further explained below), unless the event is part of a translation table walk.The authorising capability must be unsealed, unless it is an indirect sentry capability being invoked in this trace and the event is a load.If the event is a load or a store of a tagged capability, then the address must be aligned to the capability size.
The authorising capability for memory accesses must be tagged and have the right bounds and permissions: the latter must include load/store permission, and there must be a virtual address range covered by the bounds of the capability that translates to the physical address range covered by the memory event.
Loading/storing capabilities (and not just untagged data) requires additional permission bits.The authorising capability must also normally be unsealed; the only allowed case of using a sealed capability for a memory operation is the invocation of an indirect sentry capability.In that case, Property 1 allows the loaded capability (or pair of capabilities) to be written to PCC (or IDC).However, due to the definition of available capabilities, the loaded capabilities will in this case be unavailable for other purposes.Only capabilities loaded via unsealed authorising capabilities can be used for regular operations.
In addition to the instruction semantics, our ISA models also contain ASL/Sail code defining instruction fetch and decode behaviour.We use this for generating emulators, but also for stating the whole-ISA monotonicity theorem below with respect to multi-instruction traces produced by a fetch-decode-execute loop.For the fetch segments of these traces, we require the same properties to hold as for individual instruction execution traces, with the only difference being in the authorisation of memory loads: we assume that instruction fetching only loads instructions from memory, so we do not allow instruction fetching to perform capability memory loads, and we require that it checks for the execute rather than the load permission in the authorising capability.

Capability Monotonicity Theorem
The above single-instruction properties are sufficient to prove a whole-ISA monotonicity theorem for reachable capabilities.This set of reachable capabilities for a given state of the system is defined inductively as the smallest set that includes: capabilities in non-privileged registers, and those in privileged registers if a tagged and unsealed capability with system access permission is reachable; in-memory capabilities at capability-aligned virtual addresses, if there is a reachable capability that authorises loading the capability; and capabilities derivable from reachable capabilities via the rules of §4.3, i.e. restricting bounds or permissions, creating sentry capabilities, or sealing/unsealing capabilities (if a suitable authorising capability is also reachable).
This set is intended to provide an upper bound on the set of capabilities that software can construct (on its own) when starting execution in the given state, and the monotonicity theorem confirms that it is indeed an upper bound.
We assume a sequential setting and state the theorem with respect to executions of a sequential fetch-decode-execute loop; reasoning about concurrent behaviour is beyond the scope of this paper.Executing an effect trace t from a state s leading to a state s , written s t − → s , is possible if the register and memory contents in read events along the trace t correspond to the last written values, if any, or the contents in the initial state s otherwise, and if s results from s by updating register and memory contents with the values in t.
Proving the instruction-local properties of the last subsection for a concrete ISA might also require certain architecture-specific assumptions.We allow the specification of both a capability invariant that is preserved by capability derivation and assumed to hold initially, and a predicate on traces capturing further assumptions, e.g. about system registers.We say that an architecture is a CHERI ISA if all possible traces of instruction execution and fetching that satisfy the architecture-specific trace assumptions, and that read only capabilities satisfying the architecture-specific capability invariants, satisfy the properties of §4.4.Reachable capability monotonicity then holds for executions of arbitrary sequences of instructions, unless and until a transition to another security domain occurs via an ISA exception or sealed capability invocation.
. .be a trace of the fetch-decode-execute loop of a CHERI ISA, alternating fetch/decode traces tf i and instruction execution traces te i , and let s be a state such that s t − → s .If all of the following hold: 1. all traces tf i and te i satisfy the architecture-specific assumptions, 2. the capabilities in s satisfy the architecture-specific capability invariants, 3. none of the fetch and execute traces tf i and te i raise an ISA exception, 4. the address translation mapping stays invariant along t, and 5. unsealed versions of the invoked sealed capabilities in t are reachable in s, the set of capabilities reachable in s is a subset of the capabilities reachable in s.
This guarantees that software cannot escalate its privileges by forging capabilities that are not reachable from the starting state.Non-monotonic changes in the set of reachable capabilities are limited to the specific mechanisms defined above for transferring control to another security domain, i.e.ISA exceptions or sealed capability invocations, installing capabilities belonging to the new domain in the PCC (and possibly IDC) register.The monotonicity guarantee stops before such a domain transition happens.Sealed capability invocations within a security domain are monotonic, however; the theorem does cover capability invocation instructions, e.g.branch instructions taking sentry capabilities, if the unsealed invoked capability is reachable in the current security domain (condition 5 above).The translation invariance assumption (condition 4) rules out non-monotonicity due to the interpretation of capabilities changing when the memory mapping changes.It is assumed to hold for the duration of the given intra-domain trace, but after a domain transition and return, e.g. a system call, one could continue using this theorem with a modified translation mapping.
The proof of Theorem 1 starts with an induction on the number of instructions in the trace.For each individual subtrace t of an instruction fetch or execution with s t − → s , we show that the available capabilities at any point in t are reachable in s, as the definition of available capabilities excludes non-monotonic cases and only includes capabilities that are accessed with suitable permission due to the properties we require.Hence, state updates along t leading to s (only writing available or invoked, but reachable capabilities due to the requirements and assumptions) are monotonic.

Instantiation of the Abstract Model
In order to instantiate Theorem 1 for Morello, we instantiate the parameters of the abstract model, e.g. the set of privileged registers or the concrete capability representation.We do not currently instantiate the address translation mapping, effectively treating address translation as a black box and assuming an arbitrary but fixed partial mapping, together with a predicate on events to capture assumptions on register and memory contents, under which the mapping produced by the ASL address translation code is guaranteed to coincide with the given mapping.A candidate for instantiating this is the purely functional characterisation of address translation presented in [9, §8] and proved correct there for the base Armv8.3architecture, under some assumptions about control registers.Using this would also allow (and require) us to substantiate the translation invariance assumption of Theorem 1.In particular, since the translation control registers are protected by the system register access permission, code running without that permission and without write access to the in-memory translation tables cannot modify the translation mapping.
For the monotonicity proof, the main architecture-specific assumption we make is that two privileged system features that could be used to violate monotonicity are inactive: external debuggers, and the experimental instructions SCTAG and STCT that allow setting tags of arbitrary capability bit patterns.Hence, we make assumptions on the contents of certain control registers to disable these (e.g.EDSCR.STATUS = 2 to model non-debug state); the tag setting instructions can also be disabled by removing the system access permission.
The capability invariant that we assume in the initial state is that bounds do not go beyond the 64-bit address space and that their length is non-negative, e.g. to rule out memory accesses that wrap around the edge of the address space.There exist capability encodings that violate this property, but the only way to generate them on Morello is via the tag setting instructions or an external debugger, which we assume to be disabled.
We also assume that the PCC capability is initially unsealed, if it is tagged, which the ASL code relies on in a few places.We proved this as an invariant after a bug we found in a branching helper function (see §5.4) was fixed.Finally, we have to limit certain kinds of "constrained unpredictable" behaviour.For example, the LDP instruction loads a pair of words into two desti-nation registers.However, if the same register index is used for both destination register arguments to the instruction, then it is left underspecified what value is written to the destination register, if any.One might expect this to be either the original register value or one of the loaded values, but Morello inherits from the base Armv8-A architecture the specification that the register value may be set to an architecturally UNKNOWN value in such cases.For capabilities, the Morello specification [8] further constrains this in rule TSNJF: "If an UNKNOWN value is written to a capability register or to capability-tagged memory, the write does not increase the Capability defined rights available to software."We formalise this by adding an assumption that, in traces for which we want to use the monotonicity theorem, all UNKNOWN capabilities used (appearing in traces in nondeterministic choice events) are reachable from the initial state of the trace.

Manual Proofs about Capability Encoding Functions
We have to prove that the various functions that make changes to the concrete 129-bit capability representation (as used by the instruction semantics) do so in a monotonic way.The challenging aspect is the compressed capability bounds encoding introduced in [58] and used by Morello (as opposed to the version of CHERI-MIPS targeted by previous verification work [38], which used a simpler, uncompressed 256+1-bit encoding).The compression scheme allows the capability address value and both bounds, three 64-bit values, to be encoded in less than 128 bits.This exploits the fact that in well-behaved code the address should be within the bounds or nearby, so the bounds can be expressed as smaller offsets from it.They are encoded in a floating-point style, with an exponent and a floating "mantissa" window.Typical smaller capabilities have precise bounds, but large capabilities require aligned bounds, to save encoding space; the encoding uses various optimisations to maximise precision [58], [8, §2.5.1].
We initially SMT-checked the encoding functions using Sail's existing SMT backend.This provided early design feedback, including discovering an issue in the CapSetBounds function (see §5.4).
When moving from SMT checks to Isabelle proofs that can be integrated into the overall proof, one challenging function is CapIsRepresentableFast, which checks that an update to the capability value by an offset does not change the decoding of the bounds.It is important for performance that this check is done quickly.This fast version only considers the offset arithmetic within the mantissa window, making pessimistic assumptions about overflow/underflow in lower bits.We can prove that this check is sufficient, using algebraic methods in Isabelle/HOL without bit-blasting or SMT proofs.
The most challenging function for us to verify is called CapSetBounds, and is used to narrow capability bounds.The function checks that the requested new bounds fit monotonically in the existing bounds.It also picks an appropriate exponent, aligns to that exponent, and encodes an updated capability.
The main complication is that aligning the bounds to an exponent changes the length slightly, which may be an increase that requires a higher exponent.
The core argument for monotonicity here is non-trivial: the chosen alignment is the minimum one for which bounds can be encoded which enclose the requested bounds.Since the original capability also enclosed this range, its alignment cannot be less than this minimum, thus the bounds of the original capability are already aligned to the selected exponent.This finally implies that coercing the requested bounds to the selected exponent does not move them across the original bounds.A part of the proof of this lemma involved a brute-force split into cases for all possible selected exponents and reducing the cases to SMT bitvector lemmas which we pass to the CVC4 SMT solver [11].This relies on the solver as an oracle, as replay of bitvector proofs in Isabelle is only experimental.Initial work on the CHERI compression scheme [58] included HOL4 proofs about these two functions, but this is the first time the crucial monotonicity proof has been done for the set-bounds function.

Proof Engineering
With the model instantiation and lemmas about auxiliary functions in place, the remaining task is to prove that the rest of the ISA uses these functions correctly and satisfies the properties defined in §4.4.We tackle this using a combination of custom proof tactics within Isabelle and an external tool that automatically generates lemmas about the functions and instructions in the architecture.This simple approach worked sufficiently well that we were able to keep up with weekly snapshots of the ASL specification while it was being developed.Re-running the lemma generation tool mostly worked without affecting the existing manually written parts of the proof, with only few exceptions, e.g. when a refactoring of the (crucial) VACheckAddress function broke some lemmas about it.
The generated lemmas are stated in terms of predicates that reformulate the properties of §4.4 into properties of partial traces, taking an additional parameter that summarises the capabilities available at the start of this part of the trace.This allows us to split up an instruction proof into proofs that the auxiliary functions satisfy the properties and that they are used correctly, e.g. that a function performing a memory store is only called if a suitable authorising capability is available.Most of these proofs are automatically handled by straightforward proof tactics, but our tooling allows manually overriding specific parts of generated lemmas where necessary.We do this for about 100 of the ASL functions and instructions, generally taking the form of small patches, e.g.giving additional hints to the proof tactics, such as additional simplification rules or loop invariants, or adding side conditions to lemma statements, such as assumptions about capability checks for memory-accessing helper functions.The tool outputs the generated lemmas in theory files which are then checked by Isabelle; hence, the external tool does not need to be trusted.The proof consists of around 37 000 generated lines, 8 600 manually written lines, as well as 8 900 lines for the abstract model, monotonicity proof, and proof tools.The proof executes in 7hrs 20mins CPU time on an i7-10510U CPU at 1.80GHz, but only 3hrs 23mins real time thanks to parallel execution, with peak memory consumption of 18GB.

Bugs and Issues Found
Our verification work uncovered several bugs and issues in the ASL specification.
During our initial SMT-checking of the capability manipulation helper functions, one issue we discovered that was not known previously was a bug in the top-byte normalisation logic of the CapSetBounds function, which could have led to some of the top bits of the lower or upper bound of a capability changing when modifying some of their lower bits, even if the requested bounds were within the original bounds of the input capability, thereby violating monotonicity.
Our Isabelle proof uncovered a bug in the BranchToCapability function where the branch target capability was modified without a check that it is unsealed.Hence, branch instructions could have modified sealed capabilities.The result would not have been directly available to the code that performed the branch, because the modified sealed capability would be installed into PCC, and the subsequent instruction fetch would fault with a sealed capability exception, but as part of exception handling the modified sealed capability would then have been written to the CELR register and become accessible to the exception handler.
Another issue we found was a case of missing capability checks in the implementation of the DC ZVA instruction.This would have allowed software to overwrite memory regions with zeros without capability authorisation.
We also found various issues that were already known to Arm, e.g. the STP instruction checking the tag of the wrong capability, as well as functional bugs not directly affecting our proof of security properties, e.g. a bug in the LDNP and STNP instructions where the wrong memory access type was used.
We reported all of our findings to Arm, and the issues have been fixed.

Validating the Concrete Semantics
Confidence in our results about Morello's security properties relies on our translation of the specification (from ASL into Sail and Isabelle) accurately reflecting the intended architecture.A key part of ensuring that hardware designs implement Arm architectures correctly is to test against Arm's internal Architectural Compliance Kit (ACK); to validate our translation we ran a large collection of tests from the Morello ACK against a Sail generated C emulator.This approach was also taken with an earlier AArch64 Sail model [9].These tests are typically self-contained executables that can be run directly after processor reset without an operating system or peripherals, except for a simple serial device for reporting results and diagnostic information.Each test executes tens or even hundreds of thousands of instructions, so using our fast C emulator was essential.
The ACK covers Morello-specific functionality alongside the relevant parts of the base Arm-v8.2architecture in more than 25000 tests.Its scope is wider than the ASL model, including features such as performance counters, debug, and tracing, where the ASL has only interfaces or partial information, leaving the detailed specification to prose descriptions.There are also tests for the generic interrupt controller (GIC), a distinct system-on-chip component with a separate specification which is not part of the ISA.Moreover, for the Morello-feature suites, the "implementation defined" behaviour expected by the tests is more constrained than normal to match the single Morello hardware design.
To manage this complexity we first obtained baseline results from a Morello Arm Fast Model simulator, without the additional support normally used in the ACK testing environment.This matches the contents of the ASL specification more closely.We then excluded tests which required features that are not fully modelled, and adjusted the "implementation defined" portions of the specification to approximate the hardware.By comparing the results from our Sail generated emulator against the baseline we could identify and repair faults in both the ASL specification and our translation.Repairing these issues was important both to ensure that our understanding of the problem was correct and to ensure that tests could run to completion to rule out further issues.
Specific issues that we encountered involved minutiae about how system register bits behave when features are not present (such as AArch32 instructions), a couple of missing cases in our built-in operations used by SIMD instructions, a variable shadowing issue in our translation tools, corner cases in the ASL specification handling of page table capability tracking, and a few exception handling problems.None of these issues affect capability monotonicity.
The resulting pass rate was 98.1% compared with the baseline.The discrepancies were mostly due to limitations of the ASL model, such as limited debugging support, corner cases in address space handling, and the lack of secure memory; a few details with some SIMD instructions and particular processor exceptions require further investigation, but again, they do not affect monotonicity.

Model-based Test Generation
In addition to the ACK, and before we had access to it, we generated a test suite from the model to check core instruction and capability functions against the implementations; and also to adapt QEMU to support most of Morello.We use symbolic execution, well-established as a way to generate high coverage test suites [12,43] and used previously for a much simpler CHERI architecture [13], both to perturb the initial state to explore different instruction behaviours and to control whether processor exceptions are taken.The latter is particularly useful for CHERI ISAs because most input values would trivially fault at one of the capability checks (e.g.see CheckCapability in Fig. 2).Instruction set specifications are good candidates for symbolic execution because the languages tend to be relatively simple and the number of paths for any given instruction is bounded.To build a test generator for Morello we were able to reuse the Isla symbolic execution tool, which was already being developed for work combining Sail ISAs with relaxed memory models [10].
The test generator operates on traces of instructions, partially or fully chosen at random from the encoding diagrams included in the original ASL.Isla's symbolic execution was extended with a simple sequential memory model using SMT arrays for the main memory and tags.In outline, the generator: 1. initialises the model by running the processor reset function in the symbolic executor (this is deterministic and does not involve any symbolic state); 2. alters the state so that the parts the test harness can change are symbolic, and fix other values as necessary (e.g., for memory translation); 3. symbolically executes each instruction in turn to find feasible behaviours and pick one; 4. passes the accumulated path conditions to the Z3 SMT solver [16] to find suitable concrete values for the initial and final states; and 5. constructs the final test with the instructions and the test harness which will set up the initial state and check the final state after execution.This harness is hand-written (although automatically producing it in the style of Martignoni et al. [29] would be interesting to explore), so to accelerate development we first restricted our attention to fault-free behaviours with memory management turned off, then gradually added support for exceptions, for a simple fixed memory mapping, and checks of more of the processor state after execution.
Our coverage goal for test generation was to ensure that all of the specification code for manipulating capabilities and for instructions that were added or modified for Morello would be executed in some test.This was complicated by non-determinism in parts of the specification.Some instructions have "constrained unpredictable" forms which can have one of several effects; e.g., a loadpair where both destination registers are the same might write UNKNOWN to them, do nothing, or take a fault.In principle allowing for all of these is possible, but the resulting disjunctions are likely to be much more difficult to solve, and the behaviours themselves are not very interesting, so we discarded these paths.
Another area of non-determinism in the specification is the load/store exclusive instructions that are used for synchronisation.Even during single-core execution these instructions have such behaviour due to the particular memory architecture choices, which are left as unimplemented primitive operations in the specification.To test these instructions we added a simple model of the guaranteed behaviour in Sail, which includes assertions to avoid uncertain cases.
While the number of paths to explore in any instruction is bounded, the number of paths found for some instructions remains impractically large.The main cause is the case splits in the capability compression scheme.We reduce these to a single path by pushing the decisions into the SMT solver using Isla's linearisation feature, extended to support more of the language, which transforms functions with no side effects into a single SMT expression.This was sufficient to perform large-scale test generation with the Morello model.
We checked our progress against our coverage goal using the Sail C backend's coverage measurement support, counting, for each expression in a Sail specification, the number of tests that exercise it.Once we had enough tests that the accumulated coverage began to level out, it was apparent that certain instructions and corner cases were not exercised enough.Overriding the random instruction choice filled in most of the gaps, and temporarily disabling the linearisation allowed exhaustive testing of a key capability function.
The tests found a few minor issues in our tooling and some more bugs in the original ASL specification: several undefined variants of instructions were included, a new load-pair that should have been marked "constrained unpredictable", a set-bounds operation could read the wrong register, and a translation fault could be missed in a load-tags instruction.Corrections were made to the specification for these issues; a couple also arose in one of the implementations of Morello, which were then fixed.
Comparing the coverage of these tests with the ACK is instructive.As we used the Sail coverage as a goal, we hit a few gaps in the ACK, such as the set-bounds issue, and a rare corner case in a core capability function.However, the ACK's coverage goals included semantic notions that we cannot capture easily.For example, if a conditional is supposed to be false because the first of three checks will fail, human-authored coverage includes the other checks passing, whereas our generator does not reason about the other checks because the symbolic execution does not reach them.
The generated test suite was also used as the basis for test-driven development of an extension of QEMU's Armv8-A support to Morello.After adding basics, such as tagged memory and the expanded register file, the tests guided which features to implement, easing development.Small errors were picked up automatically, such as confusing the stack pointer and zero registers (which share an encoding) and sign extension bugs, including one in the pre-existing QEMU code where a previous attempt to fix it had missed a subtle issue.
The adapted QEMU now boots CheriBSD, a version of FreeBSD with capability support, although this required some fixes for issues that were not found by the generated test suite.A few involved parts of the state that were not explicitly included in the self-test, particularly around exception handling, but most of them concerned out-of-scope system features.

Related Work
Nienhuis et al. [38] proved similar results for the CHERI-MIPS architecture, above the Isabelle generated from L3 [23].CHERI-MIPS is much smaller than Morello (6k LoS), and much simpler, without page tables, virtualisation, vector instructions, etc.They identified 9 properties of the ISA semantics that sufficed to show reachable capability monotonicity and a secure encapsulation result.These captured the capability-relevant intentions of instructions explicitly, but were expressed in terms of a conventional whole-system semantics, instead of the intra-instruction semantics we use here, and that was key to scaling.Each instruction had to be annotated with its intention, extensive work was needed to prove commutativity results, and the properties were MIPS-specific.
The other most closely related work, proving properties of capability architectures, establishes stronger results but for highly idealised architecture definitions.While our monotonicity theorem is about arbitrary machine execution up to a domain crossing, Skorstengaard et al. and Georges et al. [46,47,49,48,24] establish logical-relation methods for reasoning about combinations of arbitrary and known code, the latter mechanised in Iris [28], but for idealised machines rather than full architectures.These add new features to help enforcing strong properties, but with unclear hardware implementation cost.Strydonck et al. [50] and El-Korashy et al. [19] study secure compilation in similarly idealised settings.Ultimately one would like to scale all these methods to production CHERI architectures.de Amorim et al. [5,4] verify information-flow properties of their SAFE architecture, also for a simplified model.
Capabilities have also been used in the interfaces of numerous operating systems.PSOS [37] uses a similar hardware tag bit to CHERI, but all capability operations are implemented in the OS rather than hardware.Various other operating system use standard hardware but have capabilities as part of their interfaces.These systems are very different to CHERI, but their security models have many similarities.Proofs that a (simplified) OS interface matches an abstract capability security model have been done for the EROS OS [45] and for the seL4 kernel [20].A subsequent proof connects to the seL4 implementation [44].Each of these abstract models somewhat resembles ours, e.g. with notions of reachable and derivable capabilities.Our observation that domain-crossing events create extra complications also seems to apply to seL4.
There is a great deal of work devoted to other approaches to improve memory safety which we cannot detail here, but see the review [51].For just a sample, many projects have developed software-implemented variants of C or C++ that provide greater safety, but typically with rather different performance and code-porting costs to CHERI, and without considering whole-system aspects outside a single C/C++ program [25,36,34,35,17,42,21]. Then there are many hardware-accelerated approaches, e.g.MPX and WatchdogLite, Watchdog, and Hardbound [33,32,31,18].A different line of work aims at bug-finding rather than deterministic mitigation, e.g.AddressSanitizer [2] and many others.
If widely adopted, Morello would radically change the landscape for such work, and for computer security more generally.
Open Access This chapter is licensed under the terms of the Creative Commons Attribution 4.0 International License (http://creativecommons.org/licenses/by/4.0/),which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons license and indicate if changes were made.
The images or other third party material in this chapter are included in the chapter's Creative Commons license, unless indicated otherwise in a credit line to the material.If material is not included in the chapter's Creative Commons license and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder.

Fig. 1 .
Fig. 1.From Morello ASL source (blue) to auto-generated artifacts (yellow) and verification outcomes (green) Fig.2.Sample Morello instruction semantics, in Sail, for parts of the LDR (literal) instruction[8,  §4.4.76] for loading a capability from a PCC-relative address.Lines 1-5 are the relevant opcode pattern-match clause.That calls the decode function on Lines 7-11, which calls the execute function on Lines 13-21.That uses auxiliary function VACheckAddress (Lines 23-29) to check that the PCC capability (wrapped in a VirtualAddress structure) has the right bounds and permissions, raising an exception otherwise (Lines 47-50).MemC _ read (Line 19) performs the load, and CapSquashPostLoadCap (Line 20) performs additional checks, in particular clearing the tag of the loaded capability if the authorising capability does not have capability load permission.