{cheri_levels_ext_name} is an extension to {cheri_base_ext_name} that adds support for associating a level with capabilities and limiting the flow of capabilities to specific memory region subsets. This extension allows assigning a level to capabilities, which in conjunction with two new permissions allows enforcing invariants on capability propagation. For example, this can be used to ensure that a callee can only write a copy of the passed-in argument capability to specific locations in memory (e.g. the callee’s stack frame but not the heap). It can also be used to avoid sharing of compartment-local data (such as pointers to a stack object) between compartments.
Note
|
This specification only defines the architectural mechanics of this feature, for further information on how this can be used by software please refer to cite:[cheri-v9-spec]. |
The number of supported capability levels is implementation-defined, but this specification currently only requires supporting two levels (local and global).
{cheri_levels_ext_name} adds a new LVLBITS
-bit field to the capability encoding, the capability level.
It also adds two new permission fields, EL-permission and SL-permission.
-
For
MXLEN=64
capability encoding, the AP field is widened byLVLBITS+1
bits (i.e. 2 bits forLVLBITS=1
)
Note
|
The MXLEN=64 capability encoding diagram shows the layout for LVLBITS=1
|
-
For
MXLEN=32
the capability’s AP field is able to encode these permissions without increasing in size (provided that LVLBITS≤2).
Note
|
{cheri_levels_ext_name} requires that LVLBITS≥1 although LVLBITS>1 is considered an experimental enhancement of this extension. See Extending {cheri_levels_ext_name} to more than two levels for the mechanics when LVLBITS>1. |
The Capability Level (CL) is a new field added to the capability encoding, as shown in [section_cap_encoding].
With LVLBITS=1
, the Capability Level can hold two values: when set to 1 the capability is global (in general allowing it to be stored using any authorizing capability), and when set to 0 the capability is local, and can only be stored by authorizing capabilities with the SL-permission set.
Furthermore, the EL-permission can be used to restrict loading of global capabilities — causing the hardware to automatically set the level of loaded capabilities to local instead.
Note
|
The current specification only defines two levels, equivalent to local and global capabilities from CHERI v9, Morello and CHERIoT. |
As with permissions, the capability level can only be decreased but never increased (without deriving from a capability with a higher level). Therefore, the capability level is adjusted using the [ACPERM] instruction (see Changing capability levels and permissions) and are queried using [GCPERM].
{cheri_levels_ext_name} introduces two new capability permissions:
- Store Level Permission (SL)
-
This is a
LVLBITS
wide field that allows limiting the propagation of capabilities using the following logic: capabilities with a capability level less than the inverse of the authorizing capability’s SL-permission will be stored with the tag cleared. WithLVLBITS=1
there is a single bit comparison, so it behaves as follows:-
If this field (as well as [c_perm] and [w_perm]) is set to 1 then capabilities may be stored via this capability regardless of their associated capability level.
-
If this field is zero, then any capability with a capability level of zero (i.e. local), will be stored with the tag cleared.
-
Note
|
For LVLBITS=1 this permission is equivalent to StoreLocal in CHERI v9, Morello and CHERIoT.
|
- Elevate Level Permission (EL)
-
Any capability with its tag set to 1 that is loaded from memory has its EL-permission cleared and its capability level restricted to the authorizing capability’s capability level if the authorizing capability does not grant EL-permission. This permission is similar to the existing [lm_perm], but instead of applying to the [w_perm] on the loaded capability it restricts the CL field.
Bits[4:3] | R | W | C | LM | EL | SL | X | ASR | Mode1 | Notes |
---|---|---|---|---|---|---|---|---|---|---|
Quadrant 0: Non-capability data read/write |
||||||||||
bit[2] - write, bit[1] - reserved (0), bit[0] - read |
||||||||||
Reserved bits for future extensions are 0 so new permissions are not implicitly granted |
||||||||||
0 |
N/A |
No permissions |
||||||||
1 |
✔ |
N/A |
Data RO |
|||||||
2-3 |
reserved |
|||||||||
4 |
✔ |
N/A |
Data WO |
|||||||
5 |
✔ |
✔ |
N/A |
Data RW |
||||||
6-7 |
reserved |
|||||||||
Quadrant 1: Executable capabilities |
||||||||||
bit[0] - [m_bit] ({CAP_MODE_VALUE}-{cheri_cap_mode_name}, {INT_MODE_VALUE}-{cheri_int_mode_name}) |
||||||||||
Bits[4:3] |
R |
W |
C |
LM |
EL |
SL |
X |
ASR |
Mode1 |
|
0-1 |
✔ |
✔ |
✔ |
✔ |
✔ |
∞ |
✔ |
✔ |
Mode1 |
Execute + ASR (see [infinite-cap]) |
2-3 |
✔ |
✔ |
✔ |
✔ |
∞ |
Mode1 |
Execute + Data & Cap RO |
|||
4-5 |
✔ |
✔ |
✔ |
✔ |
✔ |
∞ |
✔ |
Mode1 |
Execute + Data & Cap RW |
|
6-7 |
✔ |
✔ |
N/A |
Mode1 |
Execute + Data RW |
|||||
Quadrant 2: Restricted capability data read/write |
||||||||||
bit[2] = write, bit[1:0] = store level. R and C implicitly granted, LM dependent on W permission. |
||||||||||
Bits[4:3] |
R |
W |
C |
LM |
EL |
SL |
X |
ASR |
Mode1 |
|
0-2 |
reserved |
|||||||||
3 |
✔ |
✔ |
N/A |
N/A |
Data & Cap R0 (without [lm_perm]) |
|||||
4 |
✔ |
✔ |
✔ |
✔ |
(3) |
N/A |
Reserved for |
|||
5 |
✔ |
✔ |
✔ |
✔ |
(2) |
N/A |
Reserved for |
|||
6 |
✔ |
✔ |
✔ |
✔ |
1 |
N/A |
Data & Cap RW (with store local, no EL-permission) |
|||
7 |
✔ |
✔ |
✔ |
✔ |
0 |
N/A |
Data & Cap RW (no store local, no EL-permission) |
|||
Quadrant 3: Capability data read/write |
||||||||||
bit[2] = write, bit[1:0] = store level. R and C implicitly granted. |
||||||||||
Reserved bits for future extensions must be 1 so they are implicitly granted |
||||||||||
Bits[4:3] |
R |
W |
C |
LM |
EL |
SL |
X |
ASR |
Mode1 |
|
0-2 |
reserved |
|||||||||
3 |
✔ |
✔ |
✔ |
✔ |
N/A |
N/A |
Data & Cap R0 |
|||
4 |
✔ |
✔ |
✔ |
✔ |
✔ |
(3) |
N/A |
Reserved for |
||
5 |
✔ |
✔ |
✔ |
✔ |
✔ |
(2) |
N/A |
Reserved for |
||
6 |
✔ |
✔ |
✔ |
✔ |
✔ |
1 |
N/A |
Data & Cap RW (with store local) |
||
7 |
✔ |
✔ |
✔ |
✔ |
✔ |
0 |
N/A |
Data & Cap RW (no store local) |
While capability levels (CL) are conceptually a label on the capability rather than a permission granted by the capability, they are adjusted using the [ACPERM] instruction. This avoids the need for a dedicated instruction and allows reducing the level and removing EL-permission in a single instruction.
LVLBITS=1
summary table for stored capabilities
Auth cap field | Data cap field | |||
---|---|---|---|---|
W |
C |
SL |
CL |
Notes |
1 |
1 |
1 |
X |
Store data capability unmodified |
0 |
1 |
Store data capability unmodified (CL ≥ ~SL) |
||
0 |
Store data capability with tag cleared (CL < ~SL) |
Note
|
if W=0 or C=0 then SL is irrelevant |
LVLBITS=1
summary table for loaded capabilities
Auth cap field | Data cap field | ||||
---|---|---|---|---|---|
R |
C |
EL |
CL |
Tag |
Action |
1 |
1 |
1 |
X |
X |
Load data capability unmodified |
0 |
1 |
X |
Load data capability unmodified |
||
0 |
1 |
Load data capability with CL=0,EL=0 |
|||
0 |
Load data capability unmodified |
Note
|
if R=0 or C=0 then EL and CL are irrelevant |
When LVLBITS>1
, the behaviour of [ACPERM] can no longer use masking to adjust the capability level or SL-permission, but instead must perform an integer minimum operation on those LVLBITS
-wide fields.
The CL field of the resulting capability is set to min(rs2[CL], cs1[CL])
(equivalent to rs2[CL] & cs1[CL]
for LVLBITS=1
).
Similarly, SL-permission is set to min(rs2[SL], cs1[SL])
(equivalent to rs2[SL] & cs1[SL]
for LVLBITS=1
).
When storing capabilities, the SL-permission checks need to perform a LVLBITS
-wide integer comparison instead of just testing a single bit.
Considering for an example LVLBITS=2
:
SL-permission | Permitted for levels | Resulting semantics |
---|---|---|
3 |
As low as |
Authorizes stores of capabilities with any level |
2 |
As low as |
Strip tag for level 0 (most local), keep for 1,2,3 |
1 |
As low as |
Strip tag for level 0&1, keep for 2&3 |
0 |
As low as |
Strip tag for level 0,1,2, i.e. only the most global can be stored |
Note
|
While this extra negation is non-intuitive, it is required such that [ACPERM] can use a monotonically decreasing operation for both CL SL-permission. |