From 49eaa35316e8c8c3f53734185eb23c4ded246ff0 Mon Sep 17 00:00:00 2001 From: PeterRugg Date: Tue, 20 Dec 2022 16:18:25 +0000 Subject: [PATCH] Move from exceptions to tag clearing for RISC-V * Initial text change towards tag-clearing * Add detail on optimisations enabled by tag clearing Co-authored-by: Alexander Richardson * Avoid references to trapping on monotonicity violations * Promote tag-clearing to a 'fundamental' principle * Move tag-clearing rationale to rationale chapter * Remove exception codes redundant with tag clearing * Remove potential ISA changes inconsistent with tag clearing * Update Sail functions with refactored tag clearing * Fix inconsistency Co-authored-by: Alexander Richardson --- chap-architecture.tex | 72 ++++++++----------------------------------- chap-cheri-riscv.tex | 4 +-- chap-intro.tex | 10 +----- chap-isaref-riscv.tex | 1 - chap-model.tex | 49 +++++++++-------------------- chap-rationale.tex | 52 +++++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 107 deletions(-) diff --git a/chap-architecture.tex b/chap-architecture.tex index 62847026..e1f8a2b4 100644 --- a/chap-architecture.tex +++ b/chap-architecture.tex @@ -2056,7 +2056,7 @@ \section{Handling Failures} favored throwing an exception at the earliest possible point: the instruction attempting to violate guarded manipulation. - Another potential design choice is to instead strip the tag from the value + However, in all current architectures, we instead strip the tag from the value being written back to a target capability register, which maintains our security safety properties, but defers exception delivery until an attempted dereference -- e.g., an instruction load via the resulting invalid @@ -2067,6 +2067,8 @@ \section{Handling Failures} exception delivery means that failures that could otherwise be easily detected and handled by a compiler or language run time via an explicit tag check are now complex to handle. + In addition, stripping the tag avoids encouraging implementations that + are vulnerable to speculative side channel attacks. %%%% STRANGE USAGE. more difficult to handle? more complex? When using tag stripping in ISAs with status registers (e.g., ARMv8-A), the @@ -2075,11 +2077,6 @@ \section{Handling Failures} For ISAs without status registers, checking results can come at a significant cost, and a deferred exception delivery at time of dereference will be the best choice for performance-critical code. - - We therefore make design choices about exception delivery for violations of - guarded manipulation in a case-by-case basis, taking into account more - general architectural design philosophies, and also specific use cases where - software may benefit from tag clearing rather than exception delivery. \end{description} %\subsection{Object-Capability Invocation} @@ -2227,7 +2224,7 @@ \subsection{Architectural Privilege} exempting a component from the normal protection and access-control models -- perhaps for the purposes of system bootstrapping, system management, or low-level functionality such as direct hardware access. -In CHERI, three notions of privilege are defined, complementing current +In CHERI, two notions of privilege are defined, complementing current notions of architectural privilege: \begin{description} @@ -2349,10 +2346,6 @@ \subsubsection{New Exceptions for Existing and New Instructions} \item New capability-relative load and store instructions will trap if they attempt to access memory locations in a manner not authorized by the explicitly presented capability. - -\item New capability-manipulation instructions may trap if they violate - guarded-manipulation rules, such as by attempting to increase the bounds on - a capability. \end{itemize} \noindent @@ -2469,7 +2462,7 @@ \subsubsection{Capability Exception Causes} 0x07 & \emph{reserved} \\ 0x08 & Software-defined Permission Violation \\ 0x09 & \emph{reserved} \\ -0x0a & Representability Violation \\ +0x0a & \emph{reserved} \\ 0x0b & Unaligned Base \tnote{1} \\ 0x0c & \emph{reserved} \\ 0x0d & \emph{reserved} \\ @@ -2482,11 +2475,11 @@ \subsubsection{Capability Exception Causes} 0x14 & \cappermLC Violation \\ 0x15 & \cappermSC Violation \\ 0x16 & \cappermSLC Violation \\ -0x17 & \cappermSeal Violation \\ +0x17 & \emph{reserved} \\ 0x18 & \cappermASR Violation \\ 0x19 & \cappermInvoke Violation \\ 0x1a & \emph{reserved} \\ -0x1b & \cappermUnseal Violation \\ +0x1b & \emph{reserved} \\ 0x1c & \cappermCid Violation \\ 0x1d & \emph{reserved} \\ 0x1e & \emph{reserved} \\ @@ -2545,9 +2538,7 @@ \subsubsection{Capability Exception Priority} 2 & Tag Violation \\ 3 & Seal Violation \\ 4 & Type Violation \\ -5 & \cappermSeal Violation \\ - & \cappermInvoke Violation \\ - & \cappermUnseal Violation \\ +5 & \cappermInvoke Violation \\ & \cappermCid Violation \\ 6 & \cappermX Violation \\ 7 & \cappermL Violation \\ @@ -2557,8 +2548,7 @@ \subsubsection{Capability Exception Priority} 9 & \cappermSLC Violation \\ 10 & \cappermG Violation \\ 11 & Length Violation \\ -12 & Requested bounds cannot be represented exactly \\ -13 & Software-defined Permission Violation \\ +12 & Software-defined Permission Violation \\ \bottomrule \end{tabular} \end{center} @@ -3002,10 +2992,7 @@ \section{Deep Versus Surface Design Choices} with the target ISA, including the specific blend of instructions and their encodings, whether the address embedded in a capability is physical or virtual, how to extend existing registers to hold capability values, - the specific number (or mix) of - capability registers, and whether violations of capability provenance or - monotonicity are prevented by an exception being thrown or the tag on the - target of an operation being cleared. + and the specific number (or mix) of capability registers. \end{description} Further, applications to an ISA are necessarily sensitive to existing choices @@ -3061,6 +3048,8 @@ \section{Deep Versus Surface Design Choices} additional permissions controlling the loading and storing of capabilities; \item That MMU-enforced permissions may clear tags or throw exceptions if violated (possibly as configurable option); +\item That operations violating guarded manipulation clear the tag and yield a + later exception on use, rather than triggering an immediate exception; \item C-language compatibility is maintained through definitions of NULL to be untagged, zero-filled memory, instructions to convert between capabilities and integer pointers, and instructions providing C-compatible @@ -3111,9 +3100,6 @@ \section{Deep Versus Surface Design Choices} \item How capability-related permissions on MMU pages are indicated; \item How capabilities representing escalated privilege for exception handlers are stored; -\item Whether specific capability-related failures (in particular, operations - violating guarded manipulation) lead to an immediate exception, or simply - clearing of the tag and a later exception on use; \item How tags are stored in the memory subsystem -- e.g., whether close to the DRAM they protect or in a partition of memory -- as long as they are presented with suitable protections and atomicity up the memory hierarchy; @@ -3206,40 +3192,6 @@ \section{Potential Future Changes to the CHERI Architecture} representation, the bounds of sealed capabilities have stronger alignment requirements than for unsealed capabilities. -\item - Add versions of \insnref{CSetOffset} and \insnref{CIncOffset} - that raise an exception, rather than clearing the tag bit, when the result - is not representable. This would assist in debugging, by causing an - exception to be raised at the point in the program when the capability - became unrepresentable, rather than later on when the capability is - dereferenced. - - An alternative implementation (rather than having separate trapping and - non-trapping instructions) would be to add a status register that enables - the trapping behavior. This is similar to floating point, where the - FCSR controls whether a floating point overflow results in an IEEE - infinity value or an exception being thrown. - - A cheap tag assertion instruction that can trigger a trap when a tag is lost - would allow special compilation modes to improve debuggability by detecting - unexpected tag loss sooner. - - If MIPS had a user status register, a tag-loss bit could be set implicitly - on tag clear, allowing intermittent conditional-branch instructions to detect - and handle loss. - \jhbnote{This all seems OBE by moving to tag-clearing semantics} - -\item - Add a version of \insnref{CUnseal} that returns NULL, rather than - raising an exception, if the security checks fail. A common use case - for \insnref{CUnseal} is that a protected subsystem is passed a sealed - capability by an untrusted (possibly malicious) caller, and the callee uses - \insnref{CUnseal} to unseal it. It would be quicker for the callee - to use a non-trapping \insnref{CUnseal} and then check that the result - is not NULL, rather than either (a) catching the exception in the case that - the untrusted caller has passed a bad capability; or (b) checking that - the capability is suitable for unsealing before attempting to unseal it. - \item Add instructions for copying non-capability data from a capability register into a general-purpose integer register. A use case is when a function is called diff --git a/chap-cheri-riscv.tex b/chap-cheri-riscv.tex index 87642faf..474e6490 100644 --- a/chap-cheri-riscv.tex +++ b/chap-cheri-riscv.tex @@ -180,6 +180,8 @@ \subsection{Common Architectural Features} \item Capability-related violations (such as loads/stores/fetches via untagged capabilities, out-of-bound accesses, and so on) trigger immediate precise exceptions. +\item Requests for non-monotonic capability transformations result in + the tag of the written back value being stripped. \item It is never left ambiguous as to whether a register index operand to a load or store instruction, or the register target of a jump instruction, is a capability and therefore must have a tag set. @@ -195,8 +197,6 @@ \subsection{Unique Architectural Features} The following changes are specific to CHERI-RISC-V: \begin{itemize} -\item Requests for non-monotonic capability transformations trigger - immediate precise exceptions. \item RISC-V exception handling -- including register banking, scratch registers, and cause mechanism -- is used. \item A new exception code, \riscvloadcappagefault{}, will be diff --git a/chap-intro.tex b/chap-intro.tex index a63e762d..0c167b88 100644 --- a/chap-intro.tex +++ b/chap-intro.tex @@ -469,7 +469,7 @@ \subsection{An Architecture-Specific Mapping into RISC-V} \item[Capability instructions] allow executing code to create, constrain (e.g., by reducing bounds or permissions), manage, and inspect capability register values. Both unsealed (memory) and sealed (object) capabilities can be loaded and stored via memory capability registers (i.e., dereferencing). Object capabilities can be invoked, via special instructions, allowing a transition between protection domains, but are {\em immutable} and {\em non-dereferenceable}, providing encapsulation of the code or data that they refer to. - Capability instructions implement {\em guarded manipulation}: invalid capability manipulations (e.g., to increase rights or length) and invalid capability dereferences (e.g., to access outside of a bounds-checked region) result in an exception that can be handled by the supervisor or language runtime. + Capability instructions implement {\em guarded manipulation}: invalid capability manipulations (e.g., to increase rights or length) produce a capability with a cleared tag that can no longer be dereferenced, and invalid capability dereferences (e.g., to access outside of a bounds-checked region) result in an exception that can be handled by the supervisor or language runtime. A key aspect of the instruction-set design is \textit{intentional use of capabilities}: explicit capability registers, rather than ambient authority, are used to indicate exactly which rights should be exercised, to @@ -557,14 +557,6 @@ \subsection{CHERI-x86-64 and Arm Morello} We have ported our complete CHERI software stack to Morello. \end{description} -Even when targeting a specific architecture, there are multiple ways to -express CHERI's higher-level memory-protection and security-model goals. -For example, -CHERI provenance validity and monotonicity properties can be maintained by -throwing an exception on attempted violation (e.g., an attempt to broaden -bounds), or by clearing the tag and allowing a future attempted dereference -to throw an exception. - There is a high degree of source-level compatibility between software across all CHERI architectures. Compilers and low-level operating-system components necessarily have modest diff --git a/chap-isaref-riscv.tex b/chap-isaref-riscv.tex index 37ae61bb..d05b50c0 100644 --- a/chap-isaref-riscv.tex +++ b/chap-isaref-riscv.tex @@ -226,7 +226,6 @@ \subsection*{Functions for manipulating capabilities} \sailRISCVval{unsealCap} \sailRISCVval{isCapSealed} \sailRISCVval{hasReservedOType} -\sailRISCVval{invalidateCap} \noindent Capability permissions and flags are accessed using the following functions: diff --git a/chap-model.tex b/chap-model.tex index 5384a915..2f896e8b 100644 --- a/chap-model.tex +++ b/chap-model.tex @@ -536,22 +536,18 @@ \subsection{Capability Monotonicity via Guarded Manipulation} For example, permissions on capabilities are modified using a bitwise `and' operation, and hence cannot express an increase in permissions. -\item[Exceptions on monotonicity violation] Some instructions are able to +\item[Stripping the tag in register write-back] Some instructions are able to represent non-monotonic operations, but attempts to use them - non-monotonically will lead to an exception being delivered. - For example, an attempt to broaden bounds on a capability might throw an - exception without writing back the non-monotonically modified capability. - Throwing an exception at the point of violation may ease debugging close to - the point of violation. - -\item[Stripping the tag in register write-back] As an alternative to throwing - an exception, a non-monotonic operation might succeed in writing back a new - capability -- but with the tag bit cleared, preventing future dereference. + non-monotonically will write back a capability with the tag bit + cleared, preventing future dereference. Clearing the tag allows the failure to be discovered by an explicit software check, or on the next attempt to dereference. - This may make debugging more expensive (if additional checks are introduced, - perhaps with help from the compiler) or more tricky (if loss of the tag is - only discovered substantially later). + +\item[Exceptions on monotonicity violation] As an alternative to stripping + the tag, attempts to use instructions non-monotonically could lead to an + exception being delivered. + We generally avoid this approach in favour of stripping the tag for the + reasons discussed in Section~\ref{sec:rationale:tag-clear-vs-exception}. \item[Stripping the tag in memory store] Tagged memory ensures that direct modification of capabilities stored in memory using data store instructions @@ -642,9 +638,9 @@ \subsection{Sealed Capabilities} \label{sec:model-sealedcapabilities} Capability \textit{sealing} allows capabilities to be marked as -\textit{immutable} and \textit{non-deref\-erenceable}, causing hardware -exceptions to be thrown if attempts are made to modify, dereference, or jump -to them. +\textit{immutable} and \textit{non-deref\-erenceable}, causing the tag to be +cleared if attempts are made to modify them, and hardware exceptions to be +thrown if attempts are made to modify, dereference, or jump to them. This enables capabilities to be used as unforgeable tokens of authority for higher-level software constructs grounded in \textit{encapsulation}, while still allowing them to fit within the pointer-centric framework offered by CHERI @@ -1036,31 +1032,14 @@ \subsection{Failure Modes and Exceptions} protection model inevitably introduce the possibility of new ISA-visible failure modes when software violates rules imposed through capabilities (whether due to accident or malicious intent). -In general, in our prototyping, we have selected to deliver \textit{hardware -exceptions} as early as possible when such events occur; for example, on -attempts to perform disallowed load and store operations, to broaden bounds, -and so on. +We have selected to deliver failures as \textit{hardware exceptions}; for +example, on attempts to perform disallowed load and store operations. This allows the operating system (which in turn may delegate to the userspace language runtime or application) the ability to catch and handle failures in various ways -- such as by emulating disallowed accesses, converting to a language-visible exception, or performing some diagnostic or mitigation activity. -Different architectures express differing design philosophies for when -exceptions may be delivered, and there is flexibility in the CHERI model in -when exceptions might be delivered. -For example, while an attempt to broaden (rather than narrow) bounds could -generate an immediate exception (our prototyping choice), the operation could -instead generate a non-dereferenceable pointer as its output, in effect -deferring an exception until the time of an attempted load, store, or -instruction fetch. -The former offers slightly improved debuggability (by exposing the error -earlier), whereas the latter can offer microarchitectural benefits by -reducing the set of instructions that can throw exceptions. -Both of these implementations ensure monotonicity by preventing derived -pointers from improperly allowing increased access following guarded -manipulation, and are consistent with the model. - \subsection{Capability Revocation, Garbage Collection, and Flow Control} \label{sec:model-capability-revocation} diff --git a/chap-rationale.tex b/chap-rationale.tex index 6c138cfe..6bda7866 100644 --- a/chap-rationale.tex +++ b/chap-rationale.tex @@ -1413,4 +1413,56 @@ \section{Loading Multiple Tags Without Corresponding Data} % <<< Full details of the \insnref{CLoadTags} instruction may be found on \cpageref{\insnlabelname{cloadtags}}. +\section{Attempted Montonicity Violations Clear Tags} +\label{sec:rationale:tag-clear-vs-exception} + +To ensure pointer provenance, attempts to violate non-monotonicity, for example to broaden +(rather than narrow) bounds, must be forbidden. This can be achieved in several ways. +The instruction could throw a hardware exception, or generate a non-deferenceable pointer +as its output, in effect deferring the exception until the time of an attempted load, +store, or instruction fetch. +Both of these implementations ensure monotonicity by preventing derived +pointers from improperly allowing increased access following guarded +manipulation, and are consistent with the CHERI model. + +Initially, in our prototyping, we selected to deliver exceptions as early as +possible when such events occur. +However, all current CHERI ISA instantiations defer exceptions to the use +of a capability's authority, instead clearing the tag on operations that +would otherwise violate monotonicity. + +The early exception approach offers slightly improved debuggability +by exposing the error earlier. +Clearing the capability tag may make debugging more expensive (if additional checks are +introduced) or more tricky (if loss of the tag is only discovered substantially later). + +However, early exceptions limit compiler optimization as instructions that may +throw exceptions are restricted in how they can safely be reordered. +For example, this prevents a bounds restriction performed within a loop from +being hoisted outside the loop, unless that instruction is always executed. +If the loop is not always entered, this could turn a conditional execution +of a trapping instruction into an unconditional one.% +\footnote{This is not just a theoretical possibility -- we observed this + happening in the FreeBSD kernel and had to modify the compiler to avoid + hoisting any potentially-trapping CHERI instructions.} +In addition, code that manipulates untrusted capabilities is forced to branch +when the operation would be illegal, or risk being vulnerable to +denial-of-service attacks. +This may require it to recreate the hardware-performed checks in software. + +With a deferred-exception approach, as well as avoiding these issues, +microarchitecture is simplified by reducing the set of instructions that can +throw exceptions. +While it is initially tempting to delay performing the required checks, +forwarding the common-case value and later flushing the pipeline if a check +fails, this leads to exploitable speculative side channel attacks. +As such, in either approach, microarchitecture must perform the checks +before forwarding the result. + +Early exceptions can still be achieved if desired for debugging by +instrumenting potentially tag-clearing instructions with assertions about +the tag, either manually or in a compiler santitization pass. +The CHERI ISA instantiation can ensure these checks are cheap, for example by +providing an instruction to throw an exception based on the tag. + % >>>