\HeadingLevelC{Protection Against Subtle Attacks}
\label{sec:subtle_attack_protection}

Sanctum also protects enclaves from software attacks that attempt to exploit side
channels to obtain information indirectly. We focus on proving that Sanctum
protects against the attacks mentioned in \S~\ref{sec:related_work}, which
target the page fault address and cache timing side-channels.

The proof that Sanctum foils page fault attacks is centered around the claims
that each enclave's page fault handler and page tables and page fault handler
are isolated from all other software entities on the computer. First, all
the page faults inside an enclave's EVRANGE are reported to the enclave's fault
handler, so the OS cannot observe the virtual addresses associated with the
faults. Second, page table isolation implies that the OS cannot access an
enclave's page tables and read the access and dirty bits to learn memory access
patterns.

Page table isolation is a direct consequence of the claim that Sanctum
correctly protects enclaves against direct attacks, which was covered above.
Each enclave's page tables are stored in DRAM regions allocated to the
enclave, so no software outside the enclave can access these page tables.

The proof behind Sanctum's cache isolation is straightforward but tedious, as there are
many aspects involved. We start by peeling off the easier cases, and
tackle the most difficult step of the proof at the end of the section. Sanctum
assumes the presence of both per-core caches and a shared LLC, and each
cache type requires a separate correctness argument. Per-core cache isolation
is achieved simply by flushing core-private caches at every transition between
enclave and non-enclave mode. The cores' microarchitectural state containing private information --- TLB (\S~\ref{sec:direct_attack_protection}), and branch history table --- is likewise sanitized by the security monitor.
DRAM controller timing is sanitized by implementing a controller with constant expected access latency
(or by refusing trust in enclaves that aren't granted DRAM regions covering entire DRAM banks).
To prove the correctness of LLC isolation, we first show that enclaves do not
share LLC lines with outside software, and then we show that the OS cannot
indirectly reach into an enclave's LLC lines via the security monitor.

The two invariants outlined below show that per-core caches are never shared
between an enclave and any other software, effectively proving the correctness
of per-core cache isolation.

\begin{enumerate}
\item At all times when a core is not executing enclave code, its private
  caches only contain data accessed by the OS (and other non-enclave software).

\item At all times when a core is executing enclave code, its private caches
  only contain data accessed by the currently running enclave.
\end{enumerate}

Due to the private nature of the per-core caches, the two invariants can be
proven independently for every core, by induction over the sequence of
instructions executed by the core. The base case occurs when the security
monitor hands off the computer's control to the OS, at which point there is no
enclave, so all caches contain OS data. The induction step has two cases --
transitions between the OS and an enclave flush the per-core caches, while all
the other instructions trivially follow the invariants.

Showing that enclaves do not share LLC lines with outside software can be
accomplished by proving a stronger invariant that states at all times, any LLC
line that can potentially cache a location in an enclave's memory cannot cache
any location outside that enclave's memory. In steady state, this follows
directly from the LLC isolation scheme in \S~\ref{sec:dram_regions}, because
the security monitor guarantees that each DRAM region is assigned to exactly
one enclave or to the OS.

The situations where a DRAM region changes ownership, outlined below, can be
reasoned case by case.

\begin{enumerate}
\item DRAM regions allocated to un-initialized enclaves can be indirectly
  accessed by the OS, using the monitor APIs for loading enclaves. It follows
  that the OS can influence the state of the enclave's LLC lines at the moment
  when the enclave starts. Each enclave's initialization code is expected to
  read enough memory in each DRAM region to get the LLC lines assigned to the
  enclave's memory in a known state. This way, the OS cannot influence the
  timing of the enclave's memory accesses, by adjusting the way it loads the
  enclave's pages.

\item When an enclave starts using a DRAM region allocated by the OS after the
  enclave was initialized, it must follow the same process outlined above to
  drive the LLC lines mapping the DRAM region into a pre-determined state.
  Otherwise, the OS can influence the timing of the enclave's memory accesses,
  as reasoned above.

\item When an enclave blocks a DRAM region in order to free it for OS use, the
  enclave is responsible for cleaning up the DRAM region's contents and getting
  the associated LLC lines in a state that does not leak secrets. Enclave
  runtimes that implement DRAM region management can accomplish both tasks by
  zeroing the DRAM region before blocking it.

\item DRAM regions released when the OS terminates an enclave are zeroed by the
  security monitor. This removes secret data from the DRAM regions, and also
  places the associated LLC lines in a pre-determined state. Thus, the OS
  cannot use probing to learn about the state of the LLC lines that mapped the
  enclave's DRAM regions.
\end{enumerate}

The implementation for the measures outlined above belongs in the enclave
runtime (e.g., a modified libc), so enclave application developers do not need
to be aware of this security argument.

Last, we focus on the security monitor, because it is the only piece of
software outside an enclave that can access the enclave's DRAM regions. In
order to claim that an enclave's LLC lines are isolated from outside software,
we must prove that the OS cannot use the security monitor's API to indirectly
modify the state of the enclave's LLC lines. This proof is accomplished by
considering each function exposed by the monitor API, as well as the monitor's
hardware fault handler. The latter is considered to be under OS control because
in a worst case scenario, a malicious OS could program peripherals to cause
interrupts as needed to mount a cache timing attack.

First, we ignore all API functions that do not directly operate on enclave
memory, such as the APIs that manage DRAM regions. The ignored functions
include many APIs that manage enclave-related structures, such as mailbox
APIs~(\S~\ref{sec:mailboxes}) and most thread
APIs~(\S~\ref{sec:monitor_enclave_lifecycle}), because they only operate on
enclave metadata stored in dedicated metadata DRAM regions. In fact, the sole
purpose of metadata DRAM regions is being able to ignore most APIs in this
security argument.

Second, we ignore the API calls that operate on un-initialized enclaves,
because each enclave is expected to drive its LLC lines into a known state
during initialization.

The remaining API call is \textit{enter enclave}, which causes the current core
to start executing enclave code. All enclave code must be stored in the
enclave's DRAM regions, so it can receive integrity guarantees. It follows that
the OS can use \textit{enter enclave} to cause specific enclave LLC lines to be
fetched. This API does not contradict our security argument because
\textit{enter enclave} is the Sanctum-provided method for outside software to
call into the enclave, so it is effectively a part of the enclave's interface.

We note that enclaves have means to control \textit{enter enclave}'s behavior.
The API call will only access enclave memory if the thread
metadata~(\S~\ref{sec:monitor_enclave_entry}) passed to it is available.
Furthermore, code execution starts at an entry point defined by the enclave.

Last, we analyze the security monitor's handling of hardware exceptions. We
discuss faults (such as division by zero and page faults) and interrupts
caused by peripherals separately, as they are handled differently.

When a core starts executing enclave code, the security monitor configures it
to route faults to an enclave-defined handler. On RISC-V, this is done without
executing any non-enclave code. On architectures where the fault handler is
always invoked with monitor privileges, the security monitor must copy its
fault handler inside each enclave's DRAM regions, and configure the
\texttt{eparbase} and \texttt{eparmask} registers~(\S~\ref{sec:pmh_walker}) to
prevent the enclave from modifying the handler code. Faults must not be handled
by the security monitor code stored in OS DRAM regions, because that would give
a malicious OS an opportunity to learn when enclaves incur faults, via cache
probing.

Sanctum's security monitor handles interrupts received during enclave execution
by performing an AEX~(\S~\ref{sec:programming_model}). The AEX implementation
only accesses information in metadata DRAM regions, and writes the core's
execution state to a metadata DRAM region. Since the AEX does not access the
enclave's DRAM regions, its code can be safely stored in OS DRAM regions, along
with the rest of the security monitor. The OS can observe AEXes by probing the
LLC lines storing the AEX handler. However, this leaks no information, because
each AEX results OS code execution.
