-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathchap-model.tex
1860 lines (1663 loc) · 98.3 KB
/
chap-model.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\chapter{The CHERI Protection Model}
\label{chap:model}
This chapter describes the portable \textit{CHERI protection model}, its use
in software, and its impact on potential software vulnerabilities; concrete
mappings into computer architecture are left to later chapters.
We consider a number of topics from a more abstract, software-facing
perspectives: the principles underlying the model, our goals for capabilities,
hybridization with conventional architectural designs, implications for
operating-system and language support and compatibility, and concerns around
microarchitectural side channels.
There are many potential concrete mappings of this abstract software-facing
protection model into specific Instruction-Set Architectures (ISAs), but most
key aspects of the model can be shared across target architectures, including
the capability protection model, composition with virtual memory, and tagged
memory.
Whether used for memory protection or compartmentalization, CHERI's properties
hold with considerable uniformity across underlying architectural
implementations (e.g., regardless of capability size, whether capabilities are
stored in their own register file or as extensions to general-purpose integer
registers, etc.), and support common (and portable) programming
models and approaches.
We describe the cross-architecture aspects of CHERI in
Chapter~\ref{chap:architecture}.
Collectively, our instantiations of the CHERI protection model in the
32- and 64-bit RISC-V
(Chapter~\ref{chap:cheri-riscv}) and 64-bit ARMv8-A
(Morello~\cite{arm-morello}) ISAs
demonstrate the portability of the model despite diverse underlying
architectural implementations.
\section{Underlying Principles}
The design of CHERI is influenced by two broad underlying principles that are
as much philosophical as architectural, but are key to all aspects of the
design:
\begin{description}
\item[\textit{The principle of least privilege}] It should be possible to
express and enforce a software design in which each program component can execute
with only the privileges it requires to perform its function.
This is expressed in terms of architectural privileges (e.g., by allowing
restrictions to be imposed in terms of bounds, permissions, etc.,
encapsulating a software-selected but hardware-defined set of rights) and at
higher levels of abstraction in software (e.g., by allowing sealed
capabilities to refer to encapsulated code and data incorporating both a
software-selected and software-defined set of rights).
\psnote{the ``architectural privileges'' vs ``higher levels of
abstraction'' conceptualization works a bit better here than on p.1,
but it still seems iffy if I try to nail it down: the sealed caps
are just as much in the ISA architecture as the first set}
This principle has a long history in the research literature, and has been
explored (with varying degrees of granularity) both in terms of the expression
of reduced privilege (i.e., through isolation and compartmentalization) and
the selection of those privileges (e.g., through hand separation, automated
analysis, and so on).
\item[\textit{The principle of intentional use}] When multiple rights
are available to a program, the selection of rights used to authorize work
on behalf of the program should be explicit, rather than implicit in the
architecture or another layer of software abstraction.
The effect of this principle is to avoid the accidental or unintended
exercise of rights that could lead to a violation of the intended policy.
It helps counter what are classically known as
`confused deputy' problems, in which a program will unintentionally exercise
a privilege that it holds legitimately, but on behalf of another program
that does not (and should not) exercise that privilege~\cite{Hardy1988}.
This principle, common to many capability systems but usually not explicitly
stated, has been applied throughout the CHERI design, from architectural
privileges (e.g., the requirement to explicitly identify capability
registers used for load or store) through to the sealed capability mechanism
that can be used to support object-capability models.
\end{description}
\noindent
These principles, which offer
substantial mitigations against
software vulnerabilities or malicious code, guide the integration
of a capability-system model with the general-purpose instruction set -- and
its exposure in the software model.
A more detailed exploration of the design principles embodied in and supported
by CHERI can be found in \textit{Fundamental Trustworthiness Principles in
CHERI}~\cite{neumann2017:cheri-principles}.
\section{CHERI Capabilities: Strong Protection for Pointers}
A key purpose of the CHERI protection model is to provide architectural
primitives to support strong protection for C and C++-language pointers.
Typically, language-level pointer types are implemented using architectural
integers in registers and in memory.
CHERI provides a new architectural data type, the \textit{capability}, which
software (such as a compiler) can use use instead when implementing pointers.
CHERI protections complement existing architectural protection mechanisms
such as virtual memory implemented by a Memory Management Unit (MMU) or
non-virtualized protection implemented by a Memory Protection Unit (MPU).
CHERI protections apply to the storage and manipulation of pointers, and also
accesses performed via pointers.
The rationale for this approach is two-fold:
\begin{enumerate}
\item A large number of vulnerabilities in Trusted Computing Bases (TCBs), and
many of the application exploit techniques, arise out of bugs involving
pointer manipulation, corruption, and use.
These occur in several ways, with bugs such as those permitting attackers to
coerce arbitrary integer values into dereferenced pointers, or leading to
undesirable arithmetic manipulation of pointers or buffer bounds.
These can have a broad variety of impacts -- including overwriting or leaking
sensitive data or program metadata, injection of malicious code, and attacks
on program control flow, which in turn allow attacker privilege escalation.
Virtual memory fails to address these problems as (a) it is concerned with
protecting data mapped at virtual addresses rather than being sensitive to
the context in which a pointer is used to reference the address -- and hence
fails to assist with misuse of pointers; and (b) it fails to provide
adequate \textit{granularity}, being limited to page granularity -- or even
more coarse-grained ``large pages'' as physical memory sizes grow.
\item Strong integrity protection, fine-grained bounds checking,
encapsulation, and monotonicity for pointers can be used to construct
efficient \textit{isolation} and \textit{controlled communication},
foundations on which we can build scalable and programmer-friendly
compartmentalization within address spaces.
This facilitates deploying scalable application sandboxing with greater
ubiquity, in turn mitigating a broad range of logical programming errors
higher in the software stack, as well as resisting future undiscovered
vulnerability classes and exploit techniques.
Virtual memory also fails to address these problems, as (a) it scales
poorly, paying a high performance penalty as the degree of
compartmentalization grows; and (b) it offers poor programmability,
as the medium for sharing is the virtual-memory page rather than the
pointer-based programming model used for code and data sharing within
processes.
\end{enumerate}
Consequently, \textit{CHERI capabilities} are designed to represent
language-level pointers with additional metadata to protect their integrity
and provenance, enforce bounds checks and permissions (and their
monotonicity), and hold additional fields supporting undereferenceable
(i.e., sealed) software-defined
pointers suitable to implement higher-level protection models such as
separation and efficient compartmentalization.
Unlike virtual memory, whose functions are intended to be managed only by
low-level operating-system components such as kernels, hypervisors, and system
libraries, CHERI capabilities are also targeted more broadly at compiler and
language-runtime use, allowing program structure and dynamic memory allocation
to direct their use.
%We anticipate CHERI being used within operating-system kernels, and also in
%userspace libraries and applications, for the purposes of both memory
%protection and compartmentalization.
Significant attention has gone into providing strong compatibility with the C
and C++ programming languages, widely used in off-the-shelf TCBs such as
OS kernels and language runtimes, and also with conventional MMUs and
virtual-memory models -- which see wide use today and continue to operate on
CHERI-enabled systems.
This is possible by virtue of CHERI having a \textit{hybrid capability model}
that
securely
composes a capability-system model with conventional architectural
features and programming-language pointer interpretation.
CHERI is designed to support incremental migration via selective recompilation
(e.g., transforming pointers into capabilities, as discussed below).
It provides several possible strategies for selectively deploying changes
into larger code bases -- constructively trading off source-code
compatibility, binary compatibility, performance, and protection.
Most source code can be recompiled to employ CHERI capabilities transparently
by virtue of existing pointer syntax and semantics, which the compiler can map
into capability use just as it currently maps that functionality into integer
address use -- while providing additional metadata to the architecture
allowing the implementation of stronger memory safety.
Code in which all pointers (and implied addresses) are implemented
solely using capabilities is referred to as \textit{pure-capability code}.
Capability use can also be driven selectively, albeit less transparently,
through annotation of C pointers and types to indicate that hybrid capability
code generation should be used when operating on those pointers -- referred to
as \textit{hybrid-capability code}.
It is also possible to imagine compilers making automatic policy-based
decisions about capability use on a case-by-case basis, based on trading off
compatibility, performance, and protection with only limited programmer
intervention.
It is further worth observing that, although the primary focus of CHERI has
been protecting pointers using capabilities, capabilities are a more
generalizable hardware data type that can be used to protect other types from
corruption and mis-manipulation.
\section{Architectural Capabilities}
\label{sec:architecturalcapabilities}
\psnote{Note to be associated with Figure~\ref{fig:fig-pointer-provenance}:
Suggest we explain here what the boxes and arrows are, and how they
illustrate those properties. Are the horizontal bars all
representations of the global (typically virtual) address space, with the
coloured regions capabilities? But then if the arrows are pointers
(occurrences of capabilities), I don't understand why multiple
arrows come from the same source? Do Load/Store and Execute refer
to the top-level bars, or are they just identifying the colours?}
\psnote{Also prompted by Figure~\ref{fig:fig-pointer-provenance}, but
more generally: the
text doesn't explain the terms used in its caption (provenance
validity etc.), and they're a
bit mysterious right now. The Glossary does, and has a lot of other
carefully considered good stuff besides, but it's 400 pages away and I guess few readers
are going to spontaneously consult it. We could (though I realise this might
need an unachievable level of editing) in-line Glossary entries
throughout the text where appropriate, while still (using latex
macros to avoid forking) accumulating them in the Glossary at the end?}
\begin{figure}[t]
\centering
\includegraphics[width=\columnwidth]{fig-pointer-provenance.pdf}
\caption{CHERI enforces strict \textit{integrity}, \textit{provenance
validity}, \textit{monotonicity}, \textit{bounds}, \textit{permissions}, and
\textit{encapsulation} on pointers, mitigating common vulnerabilities and
exploit techniques.}
\label{fig:fig-pointer-provenance}
\end{figure}
In current systems, software typically implements pointers as integer values
stored in two architectural forms: in integer registers, and in memory.
\textit{Architectural capabilities} are a new architectural data type likewise
stored in register and memory, and containing an integer value that will most
frequently be interpreted as an address.
Capabilities also contain a number of other fields that contain additional
metadata associated with the address, such as bounds and permissions, as well
as a tag protecting their integrity.
Compilers, toolchains, and runtimes implementing pointers in terms of
architectural capabilities can imbue pointers with those protections, enforced
in hardware, subject to appropriately managing that metadata.
Capabilities are 2$\times$ (plus 1 bit) the size of the architecture's
natural address size, with the metadata compressed to fit in the additional
space.
On 32-bit architectures, capabilities are 64 bits ($+$1 tag bit), and on
64-bit architectures, capabilities are 128 bits ($+$1 tag bit).
In many senses, architectural capabilities used to implement pointers act like
the integers they replace, being loaded or stored, loaded or stored via,
jumped to, and so on.
The operating system, compiler, linker, and language runtimes are able to use
them to implement fine-grained memory safety for C and C++, as well as for
other purposes such as in-address-space software compartmentalization.
The majority of the capability is stored in a register or in
addressable memory, as is the case
for current integer pointers, with additional metadata stored adjacent to the
integer address it protects.
However, there is also a 1-bit tag that may be
inspected via the instruction set, but is not visible via byte-wise loads and
stores.
This tag is used to record whether the capability is valid; it is
preserved by legal capability operations but cleared by other architectural
operations on that memory.
%
Some of CHERI's protections are for pointers themselves (e.g., their integrity
and provenance validity), whereas others are for the pointee data or code
referenced by pointers (e.g., bounds and permissions).
CHERI's sealing feature protects both a pointer (via immutability) and the
pointee (via non-dereferenceability).
Extending architectures with capability registers and suitable memory storage
naturally aligns with many current architectural and microarchitectural design
choices, as well as software-facing considerations such as compiler code
generation, stack layout, operating-system behavior, and so on.
However, the generalized CHERI protection model can be mapped into
architectures in many different forms.
While implementation choices will affect a variety of factors in the
architecture and microarchitecture, the resulting protection model can be
considered \textit{portable} in that common protection properties and usage
patterns can be mapped into various architectural instantiations.
These topics are considered further in Chapter~\ref{chap:architecture}.
In the remainder of this section, we describe the high-level protection
properties and other functionality that capabilities grant to pointers and
the execution environment (see Figure~\ref{fig:fig-pointer-provenance}):
\begin{itemize}
\item Capability tags for pointer integrity and provenance
(Section~\ref{sec:model-tags})
\item Capability bounds to limit the dereferenceable range of a pointer
(Section~\ref{sec:model-bounds})
\item Capability permissions to limit the use of a pointer
(Section~\ref{sec:model-permissions})
\item Capability monotonicity and guarded manipulation to prevent privilege
escalation (Section~\ref{sec:model-monotonicity})
\item Capability sealing to implement software encapsulation
(Section~\ref{sec:model-sealedcapabilities})
\item Capability object types to enable a software object-capability model
(Section~\ref{sec:model-object-types})
\item Sealed capability invocation to implement non-monotonic domain
transition (Section~\ref{sec:model-sealed-capability-invocation})
\item Capability control flow to limit pointer propagation
(Section~\ref{sec:model-capability-control-flow})
\item Capability compression to reduce the in-memory overhead of pointer
metadata (Section~\ref{sec:model-compression})
\item Hybridization with integer pointers
(Section~\ref{sec:model-hybridization-integer-pointers})
\item Hybridization with MMU-based virtual memory
(Section~\ref{sec:model-hybridization-virtual-addressing})
\item Hybridization with ring-based privilege
(Section~\ref{sec:model-hybridization-architectural-privilege})
\item Failure modes and exception delivery
(Section~\ref{sec:failuremodesandexceptions})
\item Capability revocation (Section~\ref{sec:model-capability-revocation})
\end{itemize}
\noindent
These features allow capabilities to be architectural primitives upon which
higher-level software protection and security models can be constructed (see
Section~\ref{sec:software-protection-using-cheri}).
\psnote{ perhaps the following subsections should be restructured to
partition the description of what a capability comprises -- currently
\ref{sec:model-tags}--\ref{sec:model-permissions} are basically doing
that, though object types come later -- from the description of
properties, which currently \ref{sec:model-monotonicity} onwards
mostly are? Or, if not, at least have a short bit here that briefly
says what the data of a capability is. Perhaps also with an
\emph{illustrative} bit layout, emphasising that different arch
instantiations will do things differently. Could be a bit more
specific about the permissions data, too.}
\subsection{Tags for Pointer Integrity and Provenance}
\label{sec:model-tags}
Each location that can hold a capability -- whether a capability register or a
capability-sized, capability-aligned word of memory -- has an associated 1-bit
tag that consistently and atomically tracks capability validity for the value
stored at that location:
\begin{description}
\item[Capability registers] each have a 1-bit tag tracking whether the
in-register value is a valid capability.
This bit will be set or cleared only as permitted by guarded manipulation.
\item[Capability-sized, capability-aligned words of memory] each have a 1-bit
tag associated with the location, which is not directly addressable via data
loads or stores: \textit{tagged memory}.
Depending on the ISA variant, this may be at 64-bit or 128-bit granularity.
The capability's address, as well as its other metadata such as
bounds and permissions, are stored within the capability in addressable
memory; these fields are protected by the corresponding unaddressable tag
bit.
If untagged memory exists in the system, the tags of capability values
stored to those locations are discarded, and all loaded capability values
will have the tag bit unset.
\end{description}
\noindent
Tags atomically follow capabilities into and out of capability registers when
their values are loaded from, or stored to, tagged memory.
Stores of other non-capability types -- e.g., of bytes or half words --
automatically and atomically clear the tag in the destination memory location.
This allows in-memory pointer corruption by data stores to be detected on next
attempted dereference -- for example, this prevents arbitrary data received
over the network from being directly dereferenced as a pointer.
The capability tag controls which operations can be performed using a
capability.
Attempting controlled operations on an untagged capability will cause a
precise exception.
Regardless of the value of the tag bit, capability register fields can be
accessed: they can be extracted and, subject to guarded manipulation,
modified.
Similarly, addressable portions of the capability can be read from memory
using ordinary data load and store instructions.
Capability values can also be loaded and stored via other valid capabilities
regardless of the validity of the loaded or stored capability.
An untagged capability value is simply data: allowing capability registers to
hold untagged values allows them to be used for capability-oblivious
operations.
For example, a region of memory can be copied via capability registers, including pointers within data structures, preserving the value of the
tag bit for each copied location.
However, other operations that \textit{dereference} or otherwise use a
capability require that the capability have its tag set -- i.e., be a
\textit{valid capability}.
Dereferencing refers to using the capability to load or store data or other
capabilities, or to fetch instructions.
This includes the implied dereference associated with the Default Data
Capability controlling legacy integer-relative loads and stores.
A valid tag is also required to use a capability to seal or unseal another
capability, to jump to that capability, to use it to set the architectural
compartment ID, or to call it for the purposes of domain transition.
Detailed information on which instructions require capabilities to have valid
tags, or operate on untagged capability values, may be found in the
instruction reference.
Valid capabilities can be constructed only by deriving them from existing
valid capabilities, which ensures \textit{pointer provenance}
(Figure~\ref{fig:fig-pointer-provenance}).
In almost all cases, a new capability value will be derived from a single
capability value -- e.g., as a result of reducing bounds or permissions.
In a few cases, a capability may derive from multiple other capability
values.
For example, a sealed capability is derived from both the authorizing sealing
capability and an original data capability.
Similarly, an explicitly unsealed capability is derived from both the sealed
capability and the capability that authorizes its unsealing.
Implementing C pointers as tagged capabilities allows them to be reliably
identified in the address space, which can help support techniques
such as garbage collection.
Our CHERI
prototypes implement tagged memory using partitioned memory, with tags and
associated capability-sized units linked close to the memory controller, and
propagated by the cache hierarchy in order to provide strong atomicity with
the data it protects.
However, it is also possible to imagine implementations in which DRAM --
e.g., alongside ECC metadata -- or
non-volatile memory is extended to store tags with capability-sized units as
well.
We similarly assume that DMA will clear tags when writing to memory, although
it is possible to imagine future DMA implementations that are able to
propagate tags (e.g., to maintain tags on capabilities in descriptor rings).
\subsection{Bounds on Capabilities}
\label{sec:model-bounds}
Capabilities contain lower and upper bounds for the memory they authorize
access to.
While a capability's address may move out of bounds (and perhaps back in
again), attempts to dereference (e.g., via a load, store, or instruction
fetch) an out-of-bounds capability will throw a hardware exception.
This prevents exploitation of buffer overflows on global variables, the heap,
and the stack, as well as out-of-bounds execution.
Allowing addresses to sometimes be out-of-bounds with respect to their
bounds -- without faulting -- is important for de-facto C-language
compatibility.
In an ideal world, addresses could be arbitrarily out of bounds.
However, our
bounds-compression scheme places restrictions on this property, as bounds
compression depends on redundancy between the address and bounds, which is
reduced when addresses are substantially outside of their bounds (see
Section~\ref{compression} for details).
Bounds originate in allocation and linking events.
The operating system is able to place bounds on pointers to initial
address-space
allocations during process startup (e.g., via the initial register file, and
ELF auxiliary arguments in memory), and on an ongoing basis as new address-space
mappings are made available (e.g., via \ccode{mmap} system calls).
In practice, most bounds originate in the userspace language runtime or
compiler-generated
code, including the run-time linker for function pointers and global data,
the heap allocator for pointers to heap allocations, and generated code for
pointers taken to stack allocations.
Programming languages may also offer explicit subsetting support to allow
software to impose its own expectations on suitable bounds for memory accesses
to complex objects (such as in-memory video streams) or in their own memory
allocators.
\subsection{Permissions on Capabilities}
\label{sec:model-permissions}
Capabilities additionally extend addresses with a permissions mask controlling how the
capability may be used.
For example, the run-time linker or compiler may set a capability's
permissions so that pointers to data cannot be reused for instruction fetch,
or so that pointers to code cannot be used to store data.
Further permissions control the ability to load and store capabilities
themselves, allowing the compiler to implement policies such as
\textit{dereferenceable code and data pointers cannot be loaded from character
strings.}
Permissions can also be made accessible to higher-level aspects of the
run-time and programmer model, offering dynamic enforcement of concepts
similar to \ccode{const}.\footnote{The C-language \ccode{const} qualifier
conflates several orthogonal properties and thus can not be enforced
automatically.
Our language extensions include more constrained \ccode{\_\_input} and
\ccode{\_\_output} qualifiers.}
Languages may provide further facilities to allow programmer-directed
refinement of permissions -- for example, for use in Just-in-Time (JIT)
compilers.
Permissions changes, as with bounds setting, are often linked to allocation
events.
Permissions on capabilities for initial memory memory mappings can be
introduced by the kernel during process startup; further capabilities returned
for new mappings will also have their permissions restricted based on intended
use.
Executable capabilities representing function pointers and return addresses
will be refined by the run-time linker.
Read-only and read-write capabilities referring to data will be refined by the
run-time linker, heap allocator, and stack allocator.
Permissions also control access to the sealing facility used for encapsulation
(see Section~\ref{sec:model-sealedcapabilities}).
While sealing permission could be granted with all data and code capabilities,
best practice in privilege minimization suggests that a separate hierarchy
of sealing pointers should be maintained instead.
Returning independent sealing capabilities via a dedicated system-call
interface reduces opportunities for arbitrary code and data capabilities being
used improperly for this purpose.
\subsection{Capability Monotonicity via Guarded Manipulation}
\label{sec:model-monotonicity}
\textit{Capability monotonicity} is a property of the CHERI protection model
ensuring that new capabilities must be derived
from existing capabilities only via valid manipulations that may narrow (but
never broaden) rights ascribed to the original capability.
This property prevents broadening the bounds on pointers, increasing the
permissions on pointers, and so on, eliminating many manipulation attacks and
inappropriate pointer reuses.
Monotonicity also underlies effective isolation for software
compartmentalization by ensuring that delegated capabilities cannot be used to
reach other resources despite further manipulation.
CHERI enforces capability monotonicity via four mechanisms:
%across the vast majority of its
%instructions\psnote{what does ``vast majority'' mean here? that it
% doesn't enforce c.m. for some instructions, or that for some it
% isn't by g.m., or what?}
%\knnote{The sealedness of a capability is not monotonic, but the
% bounds and permissions of a capability are monotonic. To avoid
% defining what ``vast majority'' means, \textit{capability
% monotonicity} could also be replaced by \textit{capability bounds
% monotonicity} and \textit{capability permission monotonicity}.}
%by
%\psnote{think we can just delete this: ``virtue of \textit{guarded manipulation}: they cannot
%represent non-monotonic transformations.
%This is accomplished via''. I don't see a need to introduce the
%``guarded manipulation'' concept, esp. if we're immediately
%eliminating it, and I don't know exactly what it means.}
% four mechanisms:
\begin{description}
\item[Limited expressivity] Some instructions are prevented, by design, from
expressing an increase of rights due to the expression of their operands and
implementation.
For example, permissions on capabilities are modified using a bitwise `and'
operation, and hence cannot express an increase in permissions.
\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 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.
\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
(whether non-monotonically or otherwise) will clear the tag on affected
in-memory capabilities.
This causes later attempts to dereference the capability to fail.
This ensures that attempts to modify capabilities cannot bypass guarded
manipulation.
\psnote{Add an analogous comment about debugging in this situation?
Are all such tag-clears indicative of bugs? (not necessarily, given
strong updates, but perhaps). Further to the
CHERI-as-perfect-sanitizer pitch, could we get eager detection here too,
by some combination of h/w and compiler support?}
\rwnote{No -- we frequently overwrite tagged values when storing a NULL,
initialising memory, writing via another type in a union, doing a COW onto
a page, etc. There are surely cases where clearing the tag is a bug, but
I suspect most cases are not.}
\end{description}
Selecting which enforcement mechanism to use will reflect the specific
operation being implemented, concerns about about ease of debugging, as well
as the context of the surrounding architecture. For example, in some
architectures, exceptions can be thrown on any instruction (e.g., MIPS), while
in others it is preferable for exceptions to be thrown only on memory
accesses (e.g., ARMv8-A).
As a result of these combined architectural features, guarded manipulation
implements \textit{non-bypassable capability monotonicity}.
\knnote{I don't know what ``non-bypassable'' means here: if the
sentence would read ``\ldots implements capability monotonicity''
would that already be enough? I also wonder whether this sentence
should repeat that capabilities are not always monotonic.}
Monotonicity allows reasoning about the set of reachable rights for executing
code, as they are limited to the rights in any capability registers, and
inductively, the set of any rights reachable from those capabilities -- but no
other rights, which would require a violation of monotonicity.
\knnote{But CHERI does violate monotonicity. Perhaps it would help to
introduce the exceptions to monotonicity first, and then discuss in
this paragraph why these exceptions are not a problem for
compartmentalization.}
Monotonicity is a key foundation for fine-grained compartmentalization, as it
prevents delegated rights from being used to gain access to other undelegated
areas of memory.
More broadly, monotonicity contributes to the implementation of the principle
of intentional use, in that capabilities not only cannot be used for
operations beyond those for which they are authorized, but also cannot
inadvertently be converted into capabilities describing more broad rights.
The two notable exceptions to strict monotonicity
\psnote{are these really exceptions to c.m. in the specific sense
defined above, about the construction of new capabilities? They
have more to do with the lack of monotonicity of the permissions of
the current hardware thread...}
are invocation of sealed
capabilities (see Section~\ref{sec:model-sealed-capability-invocation}) and
exception delivery (see Section~\ref{sec:failuremodesandexceptions}).
\knnote{Is unsealing capabilities with \textit{CUnseal} an exception to monotonicity?}
Where non-monotonicity is present, control is transferred to code trusted to
utilize a gain in rights appropriately -- for example, a trusted
message-passing routine in the userspace runtime, or an OS-provided exception
handler.
This non-monotonicity is required to support protection-domain transition from
one domain holding a limited set of rights to destination domain that holds
rights unavailable to the originating domain -- and is therefore also
a requirement for fine-grained compartmentalization (see
Section~\ref{sec:model-isolation-controlled-communication-compartmentalization}).
\subsection{Capability Flags}
\label{sec:model-flags}
Capabilities include a flags field that can be manipulated freely.
Unlike the permissions field, it does not determine privilege, i.e., the state
of this field is orthogonal to capability monotonicity.
%
That is, these flags are intended to affect the \emph{semantics} of access,
rather than impose access control.
%
Currently, there are only architecture-specific interpretations for this
field: CHERI-RISC-V uses it to control opcode interpretation on instruction
fetch.
In the future, other non-security behavioral flags relating to capabilities may
be placed here, such
as to hint as to cache interactions for shared-memory rings, or to control
the behavior of operations such as capability equality testing.
\subsection{Sealed Capabilities}
\label{sec:model-sealedcapabilities}
Capability \textit{sealing} allows capabilities to be marked as
\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
capabilities.
There are two forms of capability sealing: pairs of capabilities sealed
using a common \textit{object type}, and stand-alone \textit{sealed entry
capabilities} (sentry capabilities).
Sealed pairs are primarily designed to support the linking of a pair of code
and data capabilities for use together during domain transition.
A jump-like instruction, \insnref{CInvoke}, allows the two sealed
capabilities to be atomically unsealed as control flow transfers to the code
pointed to by the code capability, if their object types match.
This can be used to implement controlled privilege escalation for the purposes
of domain transition.
Sealed entry capabilities simply seal a single code capability, which likewise
can be jumped to leading to an atomic unsealing and control-flow transfer.
This can also be used to implement domain transition with privilege
escalation, but to date has primarily been used to strengthen control-flow
robustness within a single protection domain by preventing the undesired
manipulation and use of code pointers.
Jump-and-link instructions acting on sealed entry capabilities also generate
a sealed return capability.
Sealed capabilities can also be used to support other operating-system or
language robustness features, such as representing other sorts of delegated
(non-hardware-defined) rights, or ensuring that pointers are dereferenced only
by suitable code (e.g., in support of language-level memory or type safety).
\rwnote{The next few subsections feel a bit redundant, and could be
condensed.}
\subsection{Capability Object Types}
\label{sec:model-object-types}
Capabilities contain an additional piece of metadata, an \textit{object
type}\psnote{that sounds as if \emph{all} capabilities contain an
object type...}%
\nwfnote{They do, at least implicitly! \insnref{CGetType} returns
something, specifically $2^{64}-1$, for unsealed capabilities. I've tried
to make the ISA speak in terms of \emph{encoding} the architectural
\cotype{} into the bit patterns of a capability, rather than being exactly
those bits, so that we can uniformly treat CC's separate \cotype{} field
and C-128's \csealed{} flag and shared \cotype{} bits.}%
, updated when a capability undergoes (un)sealing.
Object types allow multiple sealed capabilities to be indelibly (and
indivisibly) linked, so that the kernel or language runtime can avoid
expensive checks (e.g., via table lookups) to confirm that they are intended
to be used together.
%
\nwfnote{I am not sure I like ``indivisibly'' or maybe ``linked'' above; the indivisibility is
only up to ${\sim}/\cotype{}$, but it almost sounds like it's specifically a
pair of capabilities that are linked. Perhaps ``associated''?}
%
For example, for object-oriented compartmentalization models,
pairs of sealed capabilities can represent
objects: one is the code capability for a class, and the other is a data
capability representing the data associated with a particular instance of an
object.
The object-type field is set when a capability is sealed based on a second
input capability authorizing use of the type space -- itself simply a
capability permission authorizing sealing within a range of values specified
by the capability's bounds.
A similar model authorizes \textit{unsealing}, which permits a sealed
capability to be restored to a mutable and dereferenceable state -- if a
suitable capability to have sealed it is held.
A similar model could be achieved without using an unsealing mechanism: a
suitably privileged component could inspect a sealed capability and rederive
its unsealed contents.
However, authorizing both sealing and unsealing based on type capabilities
allows the right to construct encapsulated pointers to be delegated, without
requiring recourse to a privileged software supervisor at the cost of
additional domain transitions -- or exercise of unnecessary privilege.
\subsection{Sealed Capability Invocation}
\label{sec:model-sealed-capability-invocation}
CHERI supports two forms of non-monotonicity\psnote{someone should
revisit this phrasing after the glossary for monotonicity is sorted
out: either that is only up to domain transitions, in which case
these aren't non-..., or not, in which case these are}: jump-like capability invocation,
and exception handling (see Section~\ref{sec:failuremodesandexceptions}).
The \insnref{CInvoke} instruction accepts a pair of sealed
capability operands on which various checks are performed (for example, that
they are valid, sealed, and have matching object types).
If all tests are passed, then additional capabilities become available to the
executing CPU context by virtue of unsealing of the operand
registers.
The destination execution environment has well-defined and
reliable properties, such as a controlled target program-counter capability
and additional data capability that can be used to authorize domain
transition.
\insnref{CInvoke} behaves much like a conventional jump to register, permitting an
in-address-space domain switch without changing rings.
The newly executing code has the ability to further manipulate
execution state, and impose semantics such as call-return secure function
invocation or secure asynchronous message passing,
which will likely be followed by a privilege de-escalation as a target domain
is entered (see
Section~\ref{sec:model-isolation-controlled-communication-compartmentalization}).
\subsubsection{Object-Capability Policies in CHERI}
Consider an execution environment having access to several capabilities
sealed with the same \texttt{otype}. The tests required by the
\insnref{CInvoke} mechanism describe a \emph{Cartesian product} of method
rights (indicated by the sealed code capability) and object rights (sealed data
capability) to this environment. Regardless of how the environment
came to have these sealed capabilities, it is free to pair any sealed code
capability with any sealed data capability and have the \insnref{CInvoke}
tests pass.
Non-Cartesian and/or stateful policies can be encoded by
indirection, using memory to store additional data to be checked by the
invoked subsystem on entry. The sealed data pointers given out by the
invoked subsystem now no longer directly reference objects; instead, they
reference ``data trampolines'' describing the pairing of object(s) \emph{and
remote agent(s)} with associated access rights information. Attenuation of
access rights is no longer necessarily an ambiently available action and
requires either the explicit construction of membranes (i.e., proxy objects)
or active cooperation of the invoked subsystem (or an agent acting on its
behalf) to create new data trampoline(s).
\subsection{Capability Protection for Non-Pointer Types}
While the design of CHERI capabilities is primarily focused on the protection
of pointers, the pointer interpretation of capabilities depends entirely on
a capability's permissions mask.
If the mask authorizes load, store, and fetch instructions, then the
capability has a pointer interpretation.
\psnote{recent discussion in WG14/21 makes me sensitive to this:
there's important code out there that relies on equality comparison
of pointers to objects after lifetime-end of those objects, and the
analogue of that in CHERI (with some temporal safety scheme) could
be capabilities with tags or permissions cleared -- in which case
they'd still have \emph{a} pointer interpretation, albeit a limited one}
Capabilities are not required to have those permissions set, however, allowing
capabilities to be used for other purposes -- for example, to protect other
critical data types from in-memory corruption (such as implementing UNIX file
descriptors or stack canaries), or to authorize access to system services
(such as authorizing use of specific system calls identified by the
capability).
Sealed capabilities and a set of software-defined permissions bits facilitate
these use cases by permitting non-architecture-defined capability
interpretations while retaining capability-based protections.
\subsection{Capability Flow Control}
\label{sec:model-capability-control-flow}
The CHERI capability model is designed to support the implementation of
language-level pointers: tagged memory allows capabilities to be stored in
memory, and in particular, embedded within software-managed data structures
such as objects or the stack.
CHERI is therefore particularly subject to a historic criticism of
capability-system models -- namely,
that capability propagation makes it difficult to track
down and revoke rights (or to garbage collect them).
To address this concern, CHERI has three mechanisms by which the flow of
capabilities can be constrained:
\begin{description}
\item[Capability PTE bits] extend the existing load and store
permissions on page-table entries with new permissions to authorize loading and storing
of capabilities.
This allows the operating system to maintain pages from which tagged
capabilities cannot be loaded (tags will be transparently stripped on load),
and to which capabilities cannot be stored (a hardware exception will be
thrown).
This can be used, for example, to prevent tagged capabilities from being
stored in memory-mapped file pages (as the underlying object might not
support tag storage), or to create regions of shared memory through which
capabilities cannot flow.
\item[Capability load and store permission bits] extend the load and store
permissions on capabilities themselves, similarly allowing a capability to
be used only for data access -- if suitably configured.
This can be used to create regions of shared memory within an address
space through which capabilities cannot flow.
For example, it can
prevent
two separated compartments from
delegating access to one another's memory regions, instead limiting
communication to data traffic via the single shared region.
%%%% THE ORIGINAL SENTENCE WAS CONVOLUTED, ALLOWING SOMETHING NOT TO HAPPEN
%%%% DID NOT MAKE ANY SENSE. ON THE OTHER HAND, I MAY HAVE GOTTEN THE FIX
%%%% BACKWARDS!
\item[Capability control-flow permissions] ``color'' capabilities to limit
propagation of specific types of capabilities via other capabilities.
This feature marks capabilities as \textit{global} or \textit{local} to
indicate how they can be propagated.
Global capabilities can be stored via any capability authorized for
capability store.
Local capabilities can be stored only via a capability specifically
authorized as \textit{store local}.
This can be used, for example, to prevent propagation of temporally
sensitive stack memory between compartments, while still allowing
garbage-collected heap memory references to be shared.
This feature remains under development, as we hope to generalize it to
further uses such as limiting the propagation of ephemeral DRAM references
in persistent-memory systems.
\end{description}
The decision to strip tags on load, but throw an exception on
store\psnote{this might be rather opaque to readers -- did it refer to
text that isn't there any more? maybe expand to
explain?}, reflects
pragmatic software utilization goals: language runtimes and system libraries
often need to implement \textit{capability-oblivious memory copying}, as the
programmer may not wish to specify whether a region of memory must (or must
not) contain capabilities.
By stripping tags rather than throwing an exception on load, a
capability-oblivious memory copy is safe to use against arbitrary
addresses and source capabilities -- without risk of throwing an exception.
Software that wishes to copy only data from a source capability (excluding tag
bits due to a non-propagation goal) can simply remove the load-capability
permission from the source capability before beginning a memory copy.
%%%% THIS only SEEMS TO BE IN THE RIGHT PLACE: only specific data,
%%%% RATHER THAN data only from a source capability!!!
On the other hand, it is often desirable to detect stripping of a capability on
store\psnote{this may also appear cryptic} via a hardware exception, to ease debugging.
For example, it is typically desirable to catch storing a tagged capability to
a file as early as possible in order to avoid debugging a later failed
dereference due to loss of a tag.
Similarly, storing a tagged capability to a virtual-memory page might be an
indicator to a garbage collector that it may now be necessary to scan that
page in search of capabilities.
This design point conserves PTE and permission bits; there is some argument
that completing the space (i.e., shifting to three or four bits
each\psnote{each what?}) would
offer functional improvements -- for example, the ability to avoid exceptions on
a capability-oblivious memory copy via a capability that does not authorize
capability store, or the ability to transparently strip tags on store to a
shared memory page.
However, we have not yet found these particular combinations valuable in our software experimentation,
\subsection{Capability Compression}
\label{sec:model-compression}
\psnote{confusing contrast between ``in-memory representation'' and
``implementation'' -- I suspect better to position these as
architectural alternates, rather than the latter as an
``implementation'' of the former}
\psnote{I suspect there needs to be some clarification across the
whole document about whether ``128-bit'' refers to the old 128-bit
scheme, or CHERI concentrate, or both? (and some particular version
of concentrate?)}
Architecturally, capability fields are exposed via a set of accessor
instructions that get or set field values, such as the address, upper bound,
lower bound, and permissions.
The in-register and in-memory formats for capability contents may differ
substantially, permitting a more efficient representation using compressed
capability bounds.
CHERI utilizes a floating-point-like \textit{fat-pointer compression
technique} that relies on redundancy between the address, lower bound, and
upper bound.
The compressed representation exchanges stronger alignment requirements
(proportional to object size) for a more compact representation.
The CHERI Concentrate compression model (see Section~\ref{compression}) maintains monotonicity:
no ISA manipulation of a
capability can grant increased rights, and when unrepresentable cases are
generated
(e.g., a pointer substantially out of bounds, or a very unaligned object),
the pointer becomes un-dereferenceable.
Memory allocators already implement alignment requirements for heap and stack
allocations (word, pointer, page, and superpage alignments), and these
algorithms require only minor extension to ensure fully accurate bounds for
large memory allocations. Small allocations require no additional
alignment, where the definition of `small' depends on the compression format used and might be from 4 kiB to 1 MiB.
Relative to a 64-bit pointer, the 128-bit design reduces per-pointer memory
overhead (with a strong influence on cache footprint for some software
designs) by roughly two thirds, compared to, for example, a 256-bit
representation as found in earlier CHERI versions.
\subsection{Hybridization with Integer Pointers}
\label{sec:model-hybridization-integer-pointers}
Processors implementing CHERI capabilities also support existing programs
compiled to use conventional integer pointers, rather than capability
pointers, using two special capability registers:
\begin{description}
\item[Default Data Capability (DDC)] DDC constrains legacy instructions that
load and store relative to integer addresses rather than capabilities.
\item[Program Counter Capability (PCC)] PCC extends the conventional program
counter with capability metadata, constraining instruction fetches.
\end{description}
Programs compiled to use capabilities to represent pointers (whether
implicitly or via explicit program annotations) will not use the default data
capability, instead employing capability registers and capability-based
instructions for pointer operations.
The program-counter capability will be used regardless of the code model
employed, although capability-aware code generation will employ constrained
program-counter bounds and permissions to implement control-flow robustness
rather than using a single large code segment.
Support for legacy loads and stores can be disabled by installing a
sufficiently constrained (e.g., untagged) default data capability.
Different compilation modes and ABIs provide differing levels of compatibility
with existing code -- but include the ability to run entirely unmodified
non-CHERI binaries, to execute non-CHERI code in sandboxes within CHERI-aware
applications, and CHERI-aware code in sandboxes within CHERI-unaware
applications.
\subsection{Hybridization with Virtual Addressing}
\label{sec:model-hybridization-virtual-addressing}
\begin{figure}[t]
\centering
\includegraphics[width=\columnwidth]{fig-cheri-high-level.pdf}
\caption{CHERI supports a wide range of operational software models including:
unmodified MMU-based operating systems; hybrid operating systems
utilizing the MMU to support a process model and/or virtualization while
using CHERI within virtual address spaces; and pure single-address-space
CHERI-based operating systems.}
\label{fig:fig-os-models}
\end{figure}
The above features\psnote{which? just those in the preceding
subsection, or all in this chapter?} compose naturally with, and complement, the Virtual-Memory (VM)
models commonly implemented using commodity Memory Management Units (MMUs) in
current OS designs (Figure~\ref{fig:fig-os-models}).
Capabilities are \textit{within} rather than \textit{between} address spaces;
they protect programmer references to data (pointers), and are intended to be
driven primarily by the compiler rather than by the operating system.
In-address-space compartmentalization complements process isolation by
providing fine-grained memory sharing and highly efficient domain switching
for use between compartments in the same application, rather than between
independent programs via the process model.
Operating-system kernels will also be able to use capabilities to improve the
safety of their access to user memory, as user pointers cannot be accidentally
used to reference kernel memory, or accidentally access memory outside of
user-provided buffers.
Finally, the operating system might choose to employ capabilities internally,
and even in its interactions with userspace, in referencing kernel data
structures and objects.
\subsection{Hybridization with Architectural Privilege}
\label{sec:model-hybridization-architectural-privilege}
Conventional architectures employ ring-based mechanisms to control use of
architectural privilege: only code executing in ``supervisor'' or ``kernel''
mode is permitted to access the virtual address space with supervisor rights,