Skip to content

Commit

Permalink
Move from exceptions to tag clearing for RISC-V
Browse files Browse the repository at this point in the history
* Initial text change towards tag-clearing

* Add detail on optimisations enabled by tag clearing

Co-authored-by: Alexander Richardson <[email protected]>

* 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 <[email protected]>
  • Loading branch information
PeterRugg and arichardson authored Dec 20, 2022
1 parent 9271dde commit 49eaa35
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 107 deletions.
72 changes: 12 additions & 60 deletions chap-architecture.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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} \\
Expand All @@ -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} \\
Expand Down Expand Up @@ -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 \\
Expand All @@ -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}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions chap-cheri-riscv.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
10 changes: 1 addition & 9 deletions chap-intro.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion chap-isaref-riscv.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
49 changes: 14 additions & 35 deletions chap-model.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}

Expand Down
52 changes: 52 additions & 0 deletions chap-rationale.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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.

% >>>

0 comments on commit 49eaa35

Please sign in to comment.