-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multi-root capability systems vs. The Infinite Cap and CSR initialization #391
Comments
Some background: CHERIoT made a choice to have separate W and X roots because any code that requires both needs porting to handle the new ISA and so adding a requirement for two pointers (one to write, one to execute) is fine. CHERIv8 did not make this choice because POSIX and Win32 both have APIs ( I am personally of the opinion that we should fix POSIX for CHERI (as Brooks proposes), any code actually doing this kind of thing needs porting and most JITs already hold multiple pointers so that they can have a writeable mapping and an executable mapping in different places. It’s one bit of additional friction for adoption though, so it’s high risk. Note that none of this affects hybrid mode. In hybrid mode, stores are indirected via DDC and jumps via PCC, so a read-write DDC and a read-execute PCC provides the same semantics as non-CHERI systems. CHERIoT also makes the sealing root distinct. We wanted to do this for Morello, but didn’t in the end because Morello is a superset architecture. It’s easy for a first-stage bootloader to separate out a sealing root for experimentation in a single-rooted hierarchy, it’s not possible to combine the two in a multi-routed hierarchy. When we started designing the CHERIoT permission compression system, we created a table of all combinations and marked them as essential, desirable, unlikely to be useful, and actively harmful. The actively harmful list included things like permit-seal and permit-store in the same capability. These are harmful because the permissions refer to distinct namespaces and so a single capability that holds both is a type confusion exploit waiting to happen. I would strongly encourage any system that supports sealing to also maintain this distinction. It permits some compression in the permission encoding (none of the memory permissions are required on the sealing root), though this is not required. Even if the encoding is orthogonal, maintaining the ‘no permissions authorising actions on disjoint namespaces’ rule is probably a good idea. I would suggest that most of these SCRs should be initialised to null or to a capability with a disjoint root. In addition to execute, write, and seal, I would eventually like to add an SCR / CSR permission, which generalises ASR and allows delegating permission to access specific system registers. There is a RISC-V proposal to allow indirect access to CSRs and this could be generalised to take a capability operand. If PCC has ASR, you can access everything (necessary for bootstrapping) but without ASR you have a mechanism for authorising individual CSRs / SCRs. |
@rmn30 points out, over on CHERIoT-Platform/cheriot-sail#21, that CHERIoT requires
|
While I have proposed a replacement for the mmap interface that would support W^X better (see https://people.freebsd.org/~brooks/talks/bsdcan2018-mmap/is-it-time-to-replace-mmap.pdf), I've since been able to overcome most of the issues we had with mmap except for W^X at the pointer level. Even Arm's "always return RWX caps" solution works well enough in practice. I do suspect we could come up with a solution for JITs that is both sound and usable, but we'd need to have a solid collection of examples to convince ourselves that we aren't breaking any "common" use cases. (I'm currently pondering some sort of |
Problem Statement
At present, the Zcheripurecap draft presumes the existence of a single all-permissive Infinite cap (§2.3.2). This is incompatible with multi-root capability encodings (CHERIoT is once again the motivating example). This could have just been a nuisance, as in many cases the specification is careful to test relevant permissions or phrase certain comparisons as "ha[ving] infinite bounds" or similar, but then...
The spec requires that the following CSRs can initialize to this Infinite capability:
pcc
(§3.2.1),mtvecc
(§3.7.3),mepcc
(§3.7.7),stvecc
(§3.8.2, if S),sepcc
(§3.8.6, if S),dinfc
(§3.14.9, if Sdext),ddc
(§5.8.7, if Zcherihybrid),vstvecc
(§6.7, if H),vsepcc
(§6.11, if H).In Zcherihybrid and with Sdext,
ddc
becomes Infinite on entry to debug mode, with the new CSRdddc
holding the old value (§5.6).There is some provision for multiple roots in an informative note in §3.14.9:
However, I think some more broadly-scoped verbiage is appropriate, and in particular, there should be provision for other initialization behaviors. A hypothetical Zcheriot would like something slightly tweaked from CHERIoT's initialization, say...
pcc
initializes to the executable memory root (with cursor address set to the boot offset; the Infinite-like form, withcursor = base
, can be obtained with anAUIPC 0; GCBASE; SCADDR
sequence).mtvecc
initializes to the read-write memory rootmepcc
initializes to the sealing type rootStraw proposal
I think I'd like to have §2.3.2 define Root Capabilities and The Infinite Capability, when it exists, something like this:
We can then require CSR initialization to root capabilities:
In §3.2.1,
For
mtvecc
(§3.7.3) andmepcc
(§3.7.7), at least, and possibly all the rest,The text was updated successfully, but these errors were encountered: