-
Notifications
You must be signed in to change notification settings - Fork 96
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
Add CHERIoT support #156
Add CHERIoT support #156
Conversation
impl/random/cheriot.h
Outdated
while (ebits < 256) { | ||
uint32_t r = rand_32(); | ||
|
||
//delay(10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this delay necessary, or is that leftover debugging code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good spot - not needed, I'll take it out
@@ -14,6 +14,10 @@ static int errno; | |||
# include <string.h> | |||
#endif | |||
|
|||
#if defined (__CHERIOT__) | |||
static int errno; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How come <errno.h>
exists (since you didn't add checks around its inclusion and usage of constants such as EINTR
) but doesn't define errno
? Isn't it available as a global?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see why that would be confusing. CHERIoT is designed to have a very strong compartment model where each compartment is in effect a separate memory domain. When running in a compartment a thread can access only the globals and stack space of that compartment. When making a call from one compartment to another all data has to be explicitly passed in and returned via the stack, and the called compartment has no access to stack of the compartment that called it. If there is a failure inside a compartment, such as an invalid memory access, then the impacts of that are guaranteed to be fully contained to the compartment that failed, and everything in the calling compartment is safe. This lets us, for example, wrap libhydrogen in a compartment and be sure without having to inspect the code, that even if there was some path that could lead to buffer overrun it could never affect anything else in the system. We still have an errno.h because we use some of the enumeration values as return values from cross-compartment calls, but don't have a system wide errno var as that would break the memory mode. Declaring errno it here in effect creates a global just within each compartment that includes libhydrogen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. libhydrogen
only sets errno
in codecs, and applications usually just check the return value of the functions anyway. So, not a big deal.
To add a bit more context: CHERIoT splits a firmware image into compartments, which can invoke others with function calls but which define a hard security boundary (the caller and callee share state only when it’s explicitly passed as an argument or returned, the callee has access to a truncated stack, the callee can validate pointers, the caller can enforce bounds and permissions on passed pointers). Compartments are stateful. They have code and both mutable and immutable global state. The expose zero or more functions for other compartments to call and import zero or more functions from others. All of this is visible in an audit log. For code reuse we also have a notion of a shared library. Shared libraries are stateless: they have no mutable global state and so their invocations happen in the security context of the caller. Invoking a library function is equivalent, from a security perspective, to copying and pasting it into your compartment, but if two compartments do this the code is shared. Almost all of libhydrogen fits the model of a shared library. The only exception is the random number generation. For an ideal integration, we’d like to be able to either build the random parts as a compartment and the rest as a shared library, or provide the random number state as an explicit argument to things that need it and build the whole thing as a shared library and then wrap the random-number code in a compartment that maintained a protected state. Would a refactoring to enable either of these use cases be acceptable? For a lot of use cases, we’d also want to wrap the encryption code in a compartment that validated arguments and handled keys as sealed types (so the caller has no access to them and so that they show up in the audit logs) but that doesn’t require any modification to libhydrogen itself. |
I'd rather avoid breaking API changes as much as possible, especially when they would make usage more complicated, while not providing benefits to other platforms. |
I wouldn't expect usage for other platforms to be more complicated and I would think that other platforms would benefit from separating the stateful and stateless parts, but perhaps I'm just optimistic. |
This PR adds support for CHERIoT, an RTOS designed to provide hardware based memory safety on embedded systems using Capability Hardware Enhanced RISC Instructions
It was developed by Configured Things with funding from the Digital Security by Design program.