• Keine Ergebnisse gefunden

2.5 Memory Protection

2.5.2 The CHERI Protection Model

2.5.2.1 Capabilities

A capability can be seen as anunforgeabletoken of authority through which access is mediated. A protection domain then refers to a set of capabilities that allow both data access and control flow within a virtual address region. Capabilities are modeled after pointers, with additional metadata

2.5 Memory Protection

to protect their enforce the CHERI protection model. From an architectural perspective, it is a hardware data type and can be destructured into its referenced virtual address, its bounds, and additional protective metadata (see Table 2.1). The additional metadata ensures six properties: (1) integrity, (2) pointer-provenance, (3) monotonicty, (4) bound checking, (5) permissions and (6) encapsulation (see Figure 2.3).

CHERI ensures pointerintegritythrough the out-of-band tag bit. When a capability is modified illegally, either through oversight or malevolence, its tag bit is cleared and any subsequent use of the capability fails.

Capabilities also providepointer-provenance, i.e., they ensure the origin, or provenance, of each pointer[Dav+19b]. More specifically, by only allowing newly-created capabilities to be derived from existing capabilities, each capability must have a valid provenance, if the initial capability state has provenance. On system boot, CHERI-enabled processors derive default capabilities that span the entire address space, and from which the embedded system or operating system can derive capabilities for its protection domains.

Furthermore, capability creation must always bemonotonic, that is any newly created capability may only narrow the permissions or range of an existing capability. Together with tagged integrity protection, this providesunforgabilityof capabilities, which is the foundation of the CHERI protection model.

Where a capability is used to access memory,bounds checkinglimits, in addition to its permissions, the extent of memory that can be accessed. The region triple(base,ad d r ess,l eng th)fully specifies the address space region to which a capability has, albeit restricted, access. While a capability referenced address might move outside its bounds, attempts to dereference out-of-bound capabilities will throw to an exception. Typically, these bounds originate in an allocation event, where a language runtime sets them dynamically.

Additionally, a capability is limited by theirpermissions, which restricts the way it is used. For example, a compiler might restrict a capability so that it can only be used for execution, by granting only the “execute” permission. A capability that points to an array in memory might, on the other hand, have read and write permissions. Specific CHERI implementations, especially when used in conjunction with a custom compiler, might furthermore implement language features (such as C’s constspecifier) directly through capability permissions. Last but not least, capabilities permissions might allow it to use the seal/unseal mechanism, used to provide immutable capabilities. Available permissions may vary between CHERI implementations. Table 2.2 gives an overview of a selection of available permission for the MIPS implementation of CHERI.

Capabilities may either beunsealed, i.e., modifiable and dereferencable, orsealed, i.e., non-modifiable and non-dereferencable. CHERI provides pointerencapsulationthrough this sealing

Field name Width[bit] Purpose

Tag 1 Integrity bit, stored out-of-band

Permissions mask ~ Permissions available through this capability.

SW permissions mask ~ Extended permissions for use in software.

Flags ~ Architecture specific capability flags.

Address 64 The virtual address, which the capability references.

Object type 64 Used for sealed capabilities.

Base 64 The base address of the capability’s memory region.

Length 64 The length (in bytes) of the capability’s memory region.

Table 2.1– The CHERI capability data type. “~” refers to a variable sized field.

2.5 Memory Protection

Name Bounds Use

Global - Allow this capability to be modified by capabilities that do not havePermit_Store_Local_Capability

Permit_Execute Region Allow this capability to fetch and execute instructions Permit_Load Region Allow this capability to load words from memory Permit_Store Region Allow this capability to store words to memory

Permit_Load_Capability - Allow this capability to load other capabilities with valid tags

Permit_Store_Capability - Allow this capability to store other capabilities with valid tags.

Permit_Seal Object

type

Allow this capability to authorize sealing of another capa-bility, whereother.otype == self.address

Permit_CCall - Allow this sealed capability to be used to transition be-tween protection domains.

Permit_Unseal Object

type

Allow this capability to authorize unsealing of another capability, whereother.otype == self.address Access_System_Registers - Allow access to privileged processor registers, such as

registers for interrupt management or MMU configuration.

Table 2.2– Selection of permission bits in the MIPS implementation of the CHERI protection model. Adopted from[Wat+19b].

mechanism. Unsealed capabilities, when passed to capability-aware load or store instruction, might be dereferenced to mediate memory access inside the virtual address space. Sealed capabilities, on the other hand, may be used as object capabilities that can be invoked and unsealed. To seal or unseal a capability, the (un-)sealing capability must have the(un-)sealpermission and a matching object type with the capability to be (un-)sealed. A capability may also be invoked through special capability-awarecallandreturninstructions to provide, which allows the implementation of an effective inline address space compartmentalization. A domain crossing in the CHERI compartmentalization model always requires a pair of two capabilities with matching object types to initialize the target protection domain. More specially, any protection domain may be uniquely described and initialized from two capabilities: The data capability, which is used to derive any memory capabilities inside the domain, and the control capability which specifies the domain’s entry point and execution bound. When a domain crossing is executed, the CHERI-enabled processor installs the provided pair of capabilitiesatomicallyto the corresponding architectural registers (see Section 2.5.2.2) and execution continues in the target domain. A similar scheme is used during exception handling: By installing a pair of capabilities to be used when an exception occurs, CHERI allows an exception handler to break the monotonicity guarantee and hold privileged access, even when the domain in which the exception occurred has limited access. Recently, CHERI added support forsentrys, which allow domain crossings similar to the previously mentioned call and return mechanism, but instead uses only one code capability to facilitate the crossing. Only the code capability is changed and consequently jumped to. Finally, while sealed capabilities are mostly used to implement protection domains, they may also be used by a software-stack to construct arbitrary protected references.

The CHERI protection model does not provide a general way to revoke or invalidate, an existing capability without modifying each instance of it. However, when it is coupled with a virtual memory system, revocation is still possible. By invalidating the address which is referenced by the capability and instead of mapping the data at a different location in the virtual address space, a capability may

2.5 Memory Protection

be invalidated. Subsequently, a modified capability, with different permissions can be created for the new virtual memory address. Other techniques, for example, the usage of capabilities tagged with an identifier and a global capability table or memory scanning approaches, exist too[Xia+19]. They have been successfully used to implementtemporal memory safetyfor heap memory in the FreeBSD operating system[Fil+20]. Nonetheless, revocation is not a primary design goal of the CHERI protection model and must be retrofitted if it is needed.

2.5.2.2 The CHERI hardware architecture

Similar to a classical load-store architecture, capabilities may be stored in memory or held in capability-enabled registers when they are used or modified. Their in-memory or in-register repre-sentation might vary considerably from the data type structure presented previously (see Figure 2.4).

In the 64 bit MIPS implementation of the CHERI protection model, for example, each capability is 256 bit long with one additional tag bit, which is stored separately (see Figure 2.4a). Of these 256 bits, 192 bits are reserved for the region triple, and the remaining 64 bits are shared among the permissions and object type fields (31 bits and 24 bits respectively), while the flags fields remain unused. In total, a stored capability, therefore, takes four times the storage of a normal 64-bit pointer.

Modern implementations of the CHERI protection, e.g., CHERI-RISCV, instead use the CHERI Con-centrate[Woo+19]representation (see Figure 2.4b). It uses a floating-point format to coalesce the region triple and reduce available permissions and object types, to fit a 64-bit capability into 128-bit (or 32-bit capabilities into 64-bit) memory or register space reducing the storage overhead.

In comparison to the uncompressed representation, CHERI concentrate requires stronger alignment of capabilities in memory to compensate for compression. Still, CHERI Concentrate halves the storage overhead of the protection model.

Architectures, which implement the CHERI protection model, are free to explicitly split the register set into capability-only and normal registers or provide a merged register set, that supports both general-purpose values and capabilities in registers. The program counter capability (PCC) replaces the default program counter register regardless of this decision. A capability enabled program counter allows the CHERI protection model to constrain the control flow by restricting instruction fetch access, and finally, provide compartmentalization. Similarly, other control-flow related registers must be extended, such as the exception program counter, if they are present in the

31 2423 0

object type

user perms perms

address

base

length

(a)256 bit CHERI capabilities.

31 17 15 0

perms object type

compressed bounds address

(b)128 bit CHERIConcentrate capabilities.

Figure 2.4– Compressed (128 bit) and uncompressed (256 bit) capability representations.

2.5 Memory Protection

architecture. Furthermore, CHERI extends the architecture with a default data capability (DDC) register, which holds the default capability that is used for legacy, i.e., non-capability, loads, and stores.

The CHERI protection model extends the base instruction set with several instructions. These can be used to modify, create, or use capabilities. By adding explicit instructions, which only target capabilities, a key design choice of the CHERI protection model,intentionality, is achieved.

Additionally, capability-aware instruction areunprivileged. This does not only reduce context switch overhead but also allows processes to create protection sub-domains without operating system interaction. Nonetheless, it is also the reason why the integrity of capabilities must be protected in memory or registers. Due to the unprivileged nature of capability-aware instructions, it is expected that capabilities are also stored in unprivileged memory. Thus, they may be modified by capability-unaware stores, or arithmetic register operations and must be protected by the aforementioned tag mechanism. The authors of HardBound rely on tagged memory for the same reason, with one important distinction: It allows arbitrary capability creation and, therefore, a capability in HardBound does not constitute a protection domain like in CHERI.

Due to different underlying design principles of the extended architectures, specific implementa-tions of the CHERI architecture vary in micro-architectural implementation details. For example, while ARM processors avoid pointer modification exceptions and instead defer such exceptions to access time, RISC-V architectures always raise precise exceptions. The differences between implementations can be (mostly) reduced to three design decisions:

1. Should the register set be split or merged, or are both variants supported?

2. How should the architecture treat capability errors?

3. How are capability-aware instructions encoded?

Currently, four implementations exist with varying degrees of completeness. They are summarized in Table 2.3. MIPS is the first architecture for which the CHERI protection model was implemented and is therefore the most mature adoption. It supports a split register set, in which all capabilities are managed by an additional co-processor, called CP-1, which runs in parallel to normal processor execution. Due to the vast opcode space in MIPS, CHERI instructions were given their own encoding, completely separate from normal load/store encoding. When a capability error occurs, the capability co-processor raises a synchronous exception which interrupts the current program flow. RISC-V follows similar concepts, except that it supports both split and merged register sets. The ARM implementation on the other hand only supports merged register sets. Additionally, it does not raise precise exceptions when an invalid capability modification occurs. Instead, the capability is simply marked as corrupted (by clearing its tag bit) and execution continues. When the corrupted capability is subsequently used, an exception occurs and the program is notified. Both the RISC-V and the ARM implementation use a so-called “capability-mode” extension, in which the opcode for a capability-aware load/store instruction and a capability-unaware load/store instruction is the same.

The processor is extended with an additional mode-bit, the capability-mode bit, which indicates whether the currently processed instruction is interpreted as a capability-aware instruction or not.

Finally, an early sketch of a CHERI implementation for x86-64 exists, which uses merged register sets and a capability mode.

2.5.2.3 The CHERI software architecture

To use the previously described primitives to provide memory safety in software, CHERI implements a versatile software stack. More specifically, CHERI’s software stack discussed here is used to provide

2.5 Memory Protection

ISA Status Register file Error Mechanism Shared Opcodes

MIPS Complete Split Exception 7

ARM Experimental Merged Invalidate 3

RISC-V Draft Both Exception 3

x86-64 Sketch Merged Undecided 3

Table 2.3– Existing CHERI implementations, adapted from[WSWMN19]

memory safety to two historically unsafe languages: C and C++. At the lowest level, the software stack is a modified version of the LLVM compiler and linker, on top of which various support libraries, such as a hardened standard library are implemented. Then, a CHERI-enabled operating system is stacked on top, which may reuse the high-level primitives provided by the hardened support libraries. Finally, a CHERI-enabled program may run as the last layer of the software stack. Two basic protection modes are implemented by the CHERI software stack: Fine-grained memory safety and scalable software compartmentalization. Only the implementation of fine-grained memory safety is discussed here as it is the relevant technique for this thesis, but[WSWMN19]may be used to gain more insight into the compartmentalization mechanism.

Fine-grained memory safety is provided by the compiler and the runtime system and works by replacing C/C++pointers, either explicitly or implicitly, with capabilities. Two new compilations modes are defined: pure-capability mode and hybrid-capability mode.Pure-capabilitymode uses capabilities for all C/C++ pointers including implied pointers, such as return address or stack pointer. Trying to dereference an integer, that is a legacy pointer, will lead to an exception, in the same way, that using a capability in an invalid way would. Pure-capability compiled code is usually incompatible with legacy code due to different pointer sizes. Hybrid-capabilitymode, on the other hand, uses explicit language-level annotation for pointers to distinguish between pointers which are backed by a capability and unprotected pointers. Pointers are by default unprotected and use the DDC, when dereferenced. Therefore, pointer size is unchanged (in the default case), and hybrid-capability compiled code is binary compatible with both pure-capability and legacy code. As such, it can be either used as a bridging interface between both variants, or when the capability system proves too restrictive to implement the required functionality (e.g., bootloaders, early kernel startup).

When using the pure-capability mode, capability creation is deferred to the runtime, which will derive valid capabilities either at runtime, e.g., when a dynamic pointer is allocated, or during load time, e.g., when a global capability is created. Additionally, a C/C++runtime might use load-time capabilities to protect runtime internal structures, such as the procedure linkage table (PLT), or thread-local storage (TLS), from corruption. Furthermore, the PCC is usually the only capability, which holds execute permissions and access to the code region of the loaded program. The DDC usually contains theNULLcapability, an always invalid capability, such that any legacy pointer access will throw an exception.

The described memory safety techniques have been successfully used to implement fully memory safe operating systems: Notable examples are:

CheriBSD[Cheb], a port of the FreeBSD operating system, which supports both hybrid and pure-capability mode compiled binaries in its userspace and provides compartmentalization and memory safety.

CheriFreeRTOS, a port of the FreeRTOS operating system, which is compiled in pure-capability mode to provide memory safety.

2.5 Memory Protection

CheriOS[Chea], a clean-slate, single-address spaceµ-kernel design which uses CHERIs com-partmentalization techniques to efficiently implement its design primitives.

2.6 Summary

This chapter first defined the terms fault, error, and failure in the context of this thesis. Next, it used them to define a resilience concept that is based on theRAMSprinciples. It then presented fault injection, a fault forecasting technique, that can be used to evaluate the dependability and resilience of a system. Furthermore, related work was presented that mostly focused on existing soft-error protection schemes due to the lack of research, which used memory protection as a method for soft-error protection. Finally, memory protection was defined and the CHERI memory protection model was discussed in detail. It is a hybrid protection scheme that provides its memory protection through a combination of hardware extensions and software augmentation. Similar to the presented soft-error protection schemes, it works between the architectural and software level of an architecture. Its influence on soft-error resilience is further evaluated in the rest of this thesis.

3

A R C H I T E C T U R E

After laying the theoretical foundation, this chapter first outlines – from a theoretical standpoint – how extending an architecture with memory protection might improve the soft-error resilience in Section 3.1. Next, Section 3.2 presents the fault injection framework FAIL*, that forms the basis on which the soft-error resilience of an architecture can be evaluated. Finally, Section 3.3 presents the concrete memory protection architecture – CHERI RISC-V – and its integration into the FAIL*

framework.

3.1 Soft-Error Resilience Through Memory Protection

To understand how a system, which employs memory protection, might have improved soft-error resilience, consider what improved resilience constitutes. Generally speaking, a system can be considered to be more resilient than another system, if it adheres to stricter guarantees regarding the RAMSprinciples (see Section 2.2.1). For example, if such a system provides better fault detection, i.e., detects faults earlier, it can be considered to be morereliablethan the baseline system. In consequence, it is more resilient, as it allows for failures to be detected and corrected in a more timely fashion. Similarly, a system, which by design exhibits less catastrophic modes of failures or exhibits such failures less frequently, may be considered to besaferand, thus, more resilient than a comparable system. In the context of this thesis, a system is defined to be more resilient against soft-errors if it either:

1. Exhibits reduced frequency of specific failure modesor 2. Improves detection of existing failure modes

Therefore, to assess a system’s resiliency, its failure modes must be considered in greater detail. A system, as described in the previous chapter has six different failure modes: early timing failures, late timing failures, erratic failures, halt failures, unsignaled content failures and signaled content failures. Of these six failure modes, two are considered in greater details as they provide opportunity for improvement through memory protection: Unsignaled content failures and late timing failures.

Unsignaled content failures are system failures in which the system silently corrupts content or, in other words, data contained in a system. These system failures are often called silent data corruption. For a processor-based system most of its corruptible data is usually contained in an attached random-access memory, while only a small fraction is loaded to its registers at any given moment. Depending on the system architecture an executed instruction may operate directly on

Unsignaled content failures are system failures in which the system silently corrupts content or, in other words, data contained in a system. These system failures are often called silent data corruption. For a processor-based system most of its corruptible data is usually contained in an attached random-access memory, while only a small fraction is loaded to its registers at any given moment. Depending on the system architecture an executed instruction may operate directly on