-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
834 additions
and
2 deletions.
There are no files selected for viewing
10 changes: 10 additions & 0 deletions
10
hybrid/compartment_examples/inter_comp_call/base/Makefile.morello-hybrid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Copyright (c) 2021 The CapableVMs "CHERI Examples" Contributors. | ||
# SPDX-License-Identifier: MIT OR Apache-2.0 | ||
|
||
SHARED_SOURCES := shared.s | ||
CFILES := $(wildcard *.c) | ||
ROOTDIR=../../../.. | ||
|
||
include $(ROOTDIR)/build/Makefile.vars.morello-hybrid | ||
include $(ROOTDIR)/build/Makefile.vars.common | ||
include $(ROOTDIR)/build/Makefile.simple |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
10 changes: 10 additions & 0 deletions
10
hybrid/compartment_examples/inter_comp_call/secure-try_deref/Makefile.morello-hybrid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Copyright (c) 2021 The CapableVMs "CHERI Examples" Contributors. | ||
# SPDX-License-Identifier: MIT OR Apache-2.0 | ||
|
||
SHARED_SOURCES := shared_try_deref.s | ||
CFILES := $(wildcard *.c) | ||
ROOTDIR=../../../.. | ||
|
||
include $(ROOTDIR)/build/Makefile.vars.morello-hybrid | ||
include $(ROOTDIR)/build/Makefile.vars.common | ||
include $(ROOTDIR)/build/Makefile.simple |
203 changes: 203 additions & 0 deletions
203
hybrid/compartment_examples/inter_comp_call/secure-try_deref/main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
/* In this example, we tighten security even further, building on previous | ||
* examples [1]. We store the DDC and the PCC of `switch_compartment` | ||
* consecutively within its own bounds. Then, we create a capability pointing | ||
* to the DDC, which is sealed such that it can only be used in an `lpb`-type | ||
* call, and provide local copies of this capability to each compartment. Thus, | ||
* compartments are allowed to call `switch_compartment` via `ldpblr`, without | ||
* access to either its PCC or DDC (by nature of capabilities). | ||
* | ||
* The local copies are stored in the heap space of each compartment (as we do | ||
* not implement memory management at this point, this has no bearing at | ||
* present, but most likely will in the future). This could essentially be | ||
* considered a separate region of memory. Further, when using the local | ||
* capabilities to call `switch_compartment` from a compartment, the | ||
* destination register *must* be `c29`. | ||
* | ||
* Note that in the current design, each compartment has a single function it | ||
* executes when it is called. Allowing multiple entry points can be modelled | ||
* by having more capabilities be saved, in addition to the compartment | ||
* switching one, in each compartment's heap. Alternatively, we could, within | ||
* the compartment switcher, determine in which compartment we need to switch | ||
* to call a given function, based on PCC bounds for each compartment. | ||
* Additionally, we also changed the expected memory layout in the | ||
* compartments. In the absence of a custom memory allocator, we note that the | ||
* heap is not used, except for manually storing the local capability copy as | ||
* detailed above. Current compartment memory layout: | ||
* | ||
* ----------------- < DDC + total_comp_size | ||
* | switcher_call | | ||
* | | | ||
* | ^ | | ||
* | HEAP | | ||
* sp > |-----------------| < DDC + comp_stack_size | ||
* | STACK | | ||
* | v | | ||
* ----------------- < `DDC value` | ||
* | ||
* [1] | ||
https://github.com/capablevms/cheri-examples/tree/master/hybrid/compartment_examples/inter_comp_call | ||
*/ | ||
|
||
#include "../../../../include/common.h" | ||
#include "../../../include/utils.h" | ||
|
||
#include <assert.h> | ||
#include <stddef.h> | ||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/sysctl.h> | ||
|
||
#if !defined(__CHERI_CAPABILITY_WIDTH__) || defined(__CHERI_PURE_CAPABILITY__) | ||
#error "This example only works on CHERI hybrid mode" | ||
#endif | ||
|
||
/******************************************************************************* | ||
* Assembly Functions & Consts | ||
******************************************************************************/ | ||
|
||
extern void executive_switch(void *__capability); | ||
extern int switch_compartment(); | ||
extern void comp_f_fn(); | ||
extern void comp_g_fn(); | ||
extern void *comp_f_fn_end; | ||
extern void *comp_g_fn_end; | ||
|
||
/******************************************************************************* | ||
* Types & Consts | ||
******************************************************************************/ | ||
|
||
const size_t comp_stack_size = 2000; | ||
const size_t total_comp_size = 4992; | ||
size_t id = 0; | ||
|
||
/* Capabilities representing DDC and PCC of the switcher, stored in | ||
* `switcher_caps`. They are saved successively to facilitate calling via | ||
* `ldpblr`, with the first being the DDC, and the second, the PCC. | ||
*/ | ||
const size_t switcher_caps_count = 2; | ||
void *__capability switcher_caps[switcher_caps_count]; | ||
|
||
/* Capability required by compartments to call `switch_compartment` securely. | ||
* Duplicated in each compartment. */ | ||
void *__capability switcher_call; | ||
|
||
/* Abstract representation of a compartment. Within 80 bytes we represent: | ||
* - an id (8B) | ||
* - address to the start of the compartment memory area (also lowest address | ||
* of the stack) (8B) | ||
* - address to the start (highest address) of the compartment's stack | ||
* (corresponding to the lowest address of the heap) (8B) | ||
* the size of the stack (8B) | ||
* - address to the top (highest addressof the compartment's heap (8B) | ||
* the size of the heap (8B) | ||
* - alignment padding (8B) | ||
* - the ddc corresponding to the compartment (16B) | ||
* - the function within the compartment to be executed upon switching (16B) | ||
*/ | ||
struct comp | ||
{ | ||
size_t id; | ||
void *compartment_start; | ||
void *stack_addr; | ||
size_t stack_len; | ||
size_t heap_len; | ||
void *__capability ddc; | ||
void *__capability comp_fn; | ||
}; | ||
|
||
// ASM offsets, included here for validation | ||
#include "main.h" | ||
|
||
static_assert(COMP_SIZE == sizeof(struct comp), "Invalid `COMP_SIZE` provided"); | ||
static_assert(COMP_OFFSET_STK_ADDR == offsetof(struct comp, stack_addr), | ||
"Invalid `COMP_OFFSET_STK_ADDR` provided."); | ||
static_assert(COMP_OFFSET_STK_LEN == offsetof(struct comp, stack_len), | ||
"Invalid `COMP_OFFSET_STK_LEN` provided."); | ||
static_assert(COMP_OFFSET_DDC == offsetof(struct comp, ddc), "Invalid `COMP_OFFSET_DDC` provided."); | ||
static_assert(COMP_OFFSET_PCC == offsetof(struct comp, comp_fn), | ||
"Invalid `COMP_OFFSET_PCC` provided."); | ||
|
||
struct comp comps[COMP_COUNT]; | ||
|
||
/******************************************************************************* | ||
* Privileged Functions | ||
******************************************************************************/ | ||
|
||
/* Create and save required capabilities. Currently, this means: | ||
* - PCC of `switch_compartment` | ||
* - DDC of `switch_compartment` | ||
* - capability to allow compartments to call `switch_compartment` via `lpdblr` | ||
*/ | ||
void init_comps() | ||
{ | ||
void *__capability switch_cap = (void *__capability) switch_compartment; | ||
switch_cap = cheri_bounds_set(switch_cap, 80 * 4); | ||
switcher_caps[1] = switch_cap; | ||
|
||
void *__capability comps_addr = (void *__capability) &comps; | ||
comps_addr = cheri_bounds_set(comps_addr, COMP_COUNT * COMP_SIZE); | ||
switcher_caps[0] = comps_addr; | ||
|
||
switcher_call = (void *__capability) switcher_caps; | ||
// Seal this capability to be only used via a `lpb` type call | ||
asm("seal %w0, %w0, lpb" : "+r"(switcher_call) :); | ||
} | ||
|
||
void add_comp(uint8_t *_start_addr, void (*_comp_fn)(), void *_comp_fn_end) | ||
{ | ||
assert(id < COMP_COUNT); | ||
struct comp new_comp; | ||
new_comp.id = id; | ||
|
||
new_comp.compartment_start = (void *) _start_addr; | ||
new_comp.stack_addr = (void *) (_start_addr + comp_stack_size); | ||
new_comp.stack_len = comp_stack_size; | ||
new_comp.heap_len = total_comp_size - comp_stack_size; | ||
|
||
// Ensure 16-byte alignment throught the compartment bounds | ||
assert(((uintptr_t) new_comp.compartment_start) % 16 == 0); | ||
assert(((uintptr_t) new_comp.stack_addr) % 16 == 0); | ||
assert(total_comp_size % 16 == 0); | ||
|
||
// When creating a compartment, store a local copy of the capability which | ||
// will allow us to call `switch_compartment` in the heap of the compartment. | ||
void *heap_top = (void *) (_start_addr + total_comp_size - sizeof(void *__capability)); | ||
memcpy(heap_top, &switcher_call, sizeof(void *__capability)); | ||
|
||
void *__capability comp_ddc = (void *__capability) _start_addr; | ||
comp_ddc = cheri_bounds_set(comp_ddc, total_comp_size); | ||
new_comp.ddc = comp_ddc; | ||
|
||
// Set up a capability pointing to the function we want to call within the | ||
// compartment. This will be loaded as the PCC when the function is called. | ||
void *__capability comp_fn = (void *__capability) _comp_fn; | ||
// 40 is arbitary; meant to be the size of the executable function within | ||
// compartment | ||
size_t comp_fn_size = (uintptr_t) _comp_fn_end - (uintptr_t) _comp_fn; | ||
comp_fn = cheri_bounds_set(comp_fn, comp_fn_size); | ||
new_comp.comp_fn = comp_fn; | ||
|
||
comps[id] = new_comp; | ||
++id; | ||
} | ||
|
||
/******************************************************************************* | ||
* Main | ||
******************************************************************************/ | ||
|
||
int main() | ||
{ | ||
init_comps(); | ||
|
||
uint8_t *comp_f = malloc(total_comp_size); | ||
add_comp(comp_f, comp_f_fn, &comp_f_fn_end); | ||
uint8_t *comp_g = malloc(total_comp_size); | ||
add_comp(comp_g, comp_g_fn, &comp_g_fn_end); | ||
|
||
executive_switch(switcher_caps[0]); | ||
|
||
// Check compartment did indeed execute | ||
assert(comp_g[4000] == 42); | ||
} |
6 changes: 6 additions & 0 deletions
6
hybrid/compartment_examples/inter_comp_call/secure-try_deref/main.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#define COMP_COUNT 2 | ||
#define COMP_SIZE 80 | ||
#define COMP_OFFSET_STK_ADDR 16 | ||
#define COMP_OFFSET_STK_LEN 24 | ||
#define COMP_OFFSET_DDC 48 | ||
#define COMP_OFFSET_PCC 64 |
Oops, something went wrong.