Skip to content
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 example showing inter-compartment switch #53

Merged
merged 1 commit into from
Dec 6, 2021

Conversation

0152la
Copy link
Contributor

@0152la 0152la commented Dec 3, 2021

This example adds a second compartment, and shows a possible design to
achieve inter-compartment switching without (much) privilege escalation.
In this file, we setup compartment information within array comps
(main.c:84). This information will be used by the assembly function
switch_compartment. Further, we save a capability to
switch_compartment() in a register (main.c:102), to be able to call
it from a bounded-PCC context, as well as a capability defining the area
of memory with compartment information (main.c:101). These could be
added to the memory area of each created compartment for better
security, as well as sealed.

Our two compartments provide one entry point each, comp_f_fn
(shared.S:93), and comp_g_fn (shared.S:109). The design is that
compartment f will perform a switch to compartment g, which performs
some observable action (in this instance, sets a specific memory
location to a specific integer value). The switching process in (almost)
entirely bound within switch_compartment, on the execution side, and
the memory area with compartment information, for memory access. We note
almost, as the executable area is approximated (main.c:96).

void* __capability comps_addr = (void* __capability) &comps;
comps_addr = cheri_bounds_set(comps_addr, COMP_COUNT * COMP_SIZE);

asm("mov c19, %w0\n\t"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there might be a mix of tabs and spaces here? Let's use all spaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, well, this will be fixed by the subsequent clang-format process (which I haven't applied for the PR at this point). I prefer spaces myself, but clang-format seems to put tabs.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it? Ye gods! In general, it's best to do clang-format before opening a PR. And then if it does mix tabs and spaces we'll just have to live with it (we can still grumble about it though :)).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For ease, I've just ran one now [1]. In the future, I will run one at the point of making the PR, and the point of merging (until I hopefully am able to do the hooks thing).

[1] 5ae74cf

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@ltratt
Copy link
Collaborator

ltratt commented Dec 3, 2021

You're going to have to spell out a few things in more details so that idiots like me can understand what's going on :) For example, what does "shows a possible design to achieve inter-compartment switching without (much) privilege escalation" mean? I guess this PR is still subject to the same "any compartment can get access to another compartments DDC and read/write to its heap" as the previous PR?

@0152la
Copy link
Contributor Author

0152la commented Dec 3, 2021

I guess this PR is still subject to the same "any compartment can get access to another compartments DDC and read/write to its heap" as the previous PR?

Yes, however I briefly mention [1]:

These could be added to the memory area of each created compartment for better security, as well as sealed.

This might be a good direction for a future PR, or even this one, to make it slightly meatier.

You're going to have to spell out a few things in more details so that idiots like me can understand what's going on

The top-level comment is a high-level view, so it's kept intentionally less exact (to not be overly verbose with detail), while the steps are more spelled out in the in-line comments. Do those not help?

[1] https://github.com/capablevms/cheri-examples/pull/53/files#diff-bd3f0e982085d3f24aabff1a3429bddce60c0605c9d6047f8354c515a685b477R8

@0152la
Copy link
Contributor Author

0152la commented Dec 3, 2021

I forgot to mention in the leading comment, there are a things I'd like to improve. Primarily, the PCC bounds on switch_compartment are approximate and manual [1], as well as the bounds on the compartment functions [2]. However, I am unaware of how to derive these in code (C or asm), without doing something similar as ELF inspection that the Android example does.

And the security can (and should) be tightened further, primarily via sealing capabilities for the compartment switcher (DDC/PCC) and copying them in memory for each specific compartment. I have an idea of how to do that as well in here, and could integrate it in this PR, or a separate "security strengthening" pass.

[1] https://github.com/capablevms/cheri-examples/pull/53/files#diff-bd3f0e982085d3f24aabff1a3429bddce60c0605c9d6047f8354c515a685b477R96
[2] https://github.com/capablevms/cheri-examples/pull/53/files#diff-bd3f0e982085d3f24aabff1a3429bddce60c0605c9d6047f8354c515a685b477R128

@ltratt
Copy link
Collaborator

ltratt commented Dec 3, 2021

These could be added to the memory area of each created compartment for better security, as well as sealed.

This might be a good direction for a future PR, or even this one, to make it slightly meatier.

My guess is that the easiest way of handling this is for the compartment switcher to keep these things private to itself. But we can handle that in a later PR.

I have an idea of how to do that as well in here, and could integrate it in this PR, or a separate "security strengthening" pass.

Sounds like a good idea for the next PR :)

void executive_switch(struct comp c)
{
void *__capability switch_cap = (void *__capability) switch_compartment;
switch_cap = cheri_bounds_set(switch_cap, 80 * 4);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, are these used as PCC bounds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, hardcoded approximate bounds so things can execute, since I'm unaware of a way to compute this at compile-time, if it is possible. They would potentially be handled by the linker, an an actual implementation. Could maybe use labels, to mark start/end?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question -- I have no idea! Certainly it should be possible via ELF but it might be possible some other way, though I doubt that it's portable either way. I'm fine with punting on that for this PR. Maybe add an issue to this repo "How to calculate a function's length at runtime" as we'll then be able to ask Edd for suggestions (he knows more about such things than I do!).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #54 to at least start a conversation maybe.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

new_comp.ddc = comp_ddc;

void *__capability comp_fn = (void *__capability) _comp_fn;
comp_fn = cheri_bounds_set(comp_fn, 40);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess these are also PCC bounds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, bounds as well.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I suggest we use pcc somewhere in the var name? Maybe something like comp_pcc or similar? Failing that, a comment will help readers like me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a comment which helpfully clarifies things.

At this point, I think the following is a rather core property of CHERI, and maybe we should make it obvious somewhere: creating a capability which has the value field the address of a function, then calling (or jumping to) that capability implies installing that capability as the PCC.

@ltratt
Copy link
Collaborator

ltratt commented Dec 6, 2021

Please squash.

This example adds a second compartment, and shows a possible design to
achieve inter-compartment switching without (much) privilege escalation.
In this file, we setup compartment information within array `comps`
(`main.c:84`). This information will be used by the assembly function
`switch_compartment`. Further, we save a capability to
`switch_compartment()` in a register (`main.c:102`), to be able to call
it from a bounded-PCC context, as well as a capability defining the area
of memory with compartment information (`main.c:101`). These could be
added to the memory area of each created compartment for better
security, as well as sealed.

Our two compartments provide one entry point each, `comp_f_fn`
(`shared.S:93`), and `comp_g_fn` (`shared.S:109`). The design is that
compartment `f` will perform a switch to compartment `g`, which performs
some observable action (in this instance, sets a specific memory
location to a specific integer value). The switching process in (almost)
entirely bound within `switch_compartment`, on the execution side, and
the memory area with compartment information, for memory access. We note
almost, as the executable area is approximated (`main.c:96`).
@0152la 0152la force-pushed the intra_comp_switch branch from a30278b to 07f387e Compare December 6, 2021 14:22
@0152la
Copy link
Contributor Author

0152la commented Dec 6, 2021

Squashed.

@ltratt
Copy link
Collaborator

ltratt commented Dec 6, 2021

bors r+

@bors
Copy link
Contributor

bors bot commented Dec 6, 2021

Build succeeded:

@bors bors bot merged commit fcf29cc into capablevms:master Dec 6, 2021
@0152la 0152la deleted the intra_comp_switch branch December 6, 2021 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants