Skip to content

Commit

Permalink
Fix switch_compartment PCC bounds
Browse files Browse the repository at this point in the history
A hardcoded value of the bounds over `switch_compartment` meant that the
bounds were much wider than expected. This meant two things:
- the `clean` function called within `switch_compartment` was reachable
  and executable;
- when deriving the `clr` within `switch_compartment`, we would derive
  with the larger bound, and return to a compartment with much more
  executable permissions than intended.

We now tightly bind the PCC to `switch_compartment`. This means moving
`clean` within these bounds (a better way would be to create
capabilities allowing this function to be called, and provide local
copies to each compartment, but that is beyond the scope of this
example, and an exercise in engineering), and not deriving `clr` within
`switch_compartment`, but just retaining the provided `clr`.

Additional small cleanups, such as code-base splitting, and
comment-fixing.
  • Loading branch information
0152la committed Jan 17, 2022
1 parent 5836ec3 commit 50d1cde
Show file tree
Hide file tree
Showing 9 changed files with 245 additions and 249 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (c) 2021 The CapableVMs "CHERI Examples" Contributors.
# SPDX-License-Identifier: MIT OR Apache-2.0

SHARED_SOURCES := shared_try_deref.s
SHARED_SOURCES := shared.S
CFILES := $(wildcard *.c)
ROOTDIR=../../../..

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* Compartment from which we call the switcher to perform inter-compartment
* transition. The call is via a capability, to update the PCC bounds
* appropriately to cover `switch_compartment`.
*/
comp_f_fn:
// Retrieve local capability containing switcher information
mrs c1, DDC
gclim x1, c1
sub x1, x1, #16
ldr c1, [x1]

// Try to dereference it to retrieve switcher DDC; this is expected to fail
// due to the local capability being sealed (`main.c:143`).
ldr c1, [c1]

ldr clr, [sp], #16

ret clr
comp_f_fn_end:

/* The function in this compartment just writes to some memory within its
* bounds, to ensure it is properly called.
*/
.type comp_g_fn, "function"
comp_g_fn:
mrs c10, DDC
mov x11, 42
str x11, [x10, #4000]

ret clr
comp_g_fn_end:
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ 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;
extern void comp_f_fn_end();
extern void comp_g_fn_end();
extern void switch_compartment_end();

/*******************************************************************************
* Types & Consts
Expand Down Expand Up @@ -133,7 +134,8 @@ struct comp comps[COMP_COUNT];
void init_comps()
{
void *__capability switch_cap = (void *__capability) switch_compartment;
switch_cap = cheri_bounds_set(switch_cap, 80 * 4);
size_t switcher_size = (uintptr_t) switch_compartment_end - (uintptr_t) switch_compartment;
switch_cap = cheri_bounds_set(switch_cap, switcher_size);
switcher_caps[1] = switch_cap;

void *__capability comps_addr = (void *__capability) &comps;
Expand Down Expand Up @@ -173,8 +175,6 @@ void add_comp(uint8_t *_start_addr, void (*_comp_fn)(), void *_comp_fn_end)
// 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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2021 The CapableVMs "CHERI Examples" Contributors.
// SPDX-License-Identifier: MIT OR Apache-2.0

#include "main.h"

// Compartment functions
.global comp_f_fn
.global comp_g_fn

// Labels for size computations
.global comp_f_fn_end
.global comp_g_fn_end
.global switch_compartment_end

.text
.balign 4

.global executive_switch
.type executive_switch, "function"
executive_switch:
mov c29, c0
mov x0, #0
cvtp clr, lr
b switch_compartment
ret clr

#include "switch_compartment.s"

#include "compartments-try_deref.s"
Original file line number Diff line number Diff line change
@@ -1,23 +1,3 @@
// Copyright (c) 2021 The CapableVMs "CHERI Examples" Contributors.
// SPDX-License-Identifier: MIT OR Apache-2.0

#include "main.h"

.global comp_f_fn
.global comp_g_fn
.global comp_f_fn_end
.global comp_g_fn_end

.text
.balign 4

.global executive_switch
.type executive_switch, "function"
executive_switch:
mov c29, c0
mov x0, #0
bl switch_compartment

/* The compartment switch function. Expects compartment information to be
* stored in memory (defined by the capability stored in register `c29`).
* Performs a compartment switch based on the id saved in `x0` (currently just
Expand Down Expand Up @@ -52,14 +32,11 @@ switch_compartment:
ldr x11, [x29, x11]
mov sp, x11

// Derive a new clr to restore PCC, and store it.
cvtp c11, lr

// Install compartment DDC
msr DDC, c1

// Save old DDC (c2), old SP (x12), old LR (c11) on stack
stp c2, c11, [sp, #-48]!
// Save old DDC (c2), old SP (x12), old LR (clr) on stack
stp c2, clr, [sp, #-48]!
str x12, [sp, #32]

// Stack layout at this point:
Expand Down Expand Up @@ -95,46 +72,6 @@ switch_compartment:

ret clr

.type get_comp_switcher_ref, "function"
get_comp_switcher_ref:
mov x1, #5000
sub x1, x1, #16
add c0, c0, x1
ret

/* Compartment from which we call the switcher to perform inter-compartment
* transition. The call is via a capability, to update the PCC bounds
* appropriately to cover `switch_compartment`.
*/
.type comp_f_fn, "function"
comp_f_fn:
// Retrieve local capability containing switcher information
mrs c1, DDC
gclim x1, c1
sub x1, x1, #16
ldr c1, [x1]

// Try to dereference it to retrieve switcher DDC; this is expected to fail
// due to the local capability being sealed (`main.c:143`).
ldr c1, [c1]

ldr clr, [sp], #16

ret clr
comp_f_fn_end:

/* The function in this compartment just writes to some memory within its
* bounds, to ensure it is properly called.
*/
.type comp_g_fn, "function"
comp_g_fn:
mrs c10, DDC
mov x11, 42
str x11, [x10, #4000]

ret clr
comp_g_fn_end:

// Inner helper for cleaning capabilities from registers, either side of an
// AAPCS64 function call where some level of distrust exists between caller
// and callee.
Expand Down Expand Up @@ -184,4 +121,5 @@ clean:
// We need LR (x30) to return. The call to this helper already cleaned it.
// Don't replace SP; this needs special handling by the caller anyway.
ret
switch_compartment_end:

38 changes: 38 additions & 0 deletions hybrid/compartment_examples/inter_comp_call/secure/compartments.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* Compartment from which we call the switcher to perform inter-compartment
* transition. The call is via a capability, to update the PCC bounds
* appropriately to cover `switch_compartment`.
*/
.type comp_f_fn, "function"
comp_f_fn:
// Set compartment ID we want to switch to
mov x0, #1

// Store the `clr` for exitting `comp_f_fn`; this is overwritten by
// `switch_compartment`.
str clr, [sp, #-16]!

// Retrieve local capability containing switcher information for `pdlblr`
// instruction (DDC is used as it contains the address where the capability
// is stored in this particular example)
mrs c1, DDC
gclim x1, c1
sub x1, x1, #16
ldr c1, [x1]
ldpblr c29, [c1]

ldr clr, [sp], #16

ret clr
comp_f_fn_end:

/* The function in this compartment just writes to some memory within its
* bounds, to ensure it is properly called.
*/
.type comp_g_fn, "function"
comp_g_fn:
mrs c10, DDC
mov x11, 42
str x11, [x10, #4000]

ret clr
comp_g_fn_end:
10 changes: 5 additions & 5 deletions hybrid/compartment_examples/inter_comp_call/secure/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ 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;
extern void comp_f_fn_end();
extern void comp_g_fn_end();
extern void switch_compartment_end();

/*******************************************************************************
* Types & Consts
Expand Down Expand Up @@ -133,7 +134,8 @@ struct comp comps[COMP_COUNT];
void init_comps()
{
void *__capability switch_cap = (void *__capability) switch_compartment;
switch_cap = cheri_bounds_set(switch_cap, 80 * 4);
size_t switcher_size = (uintptr_t) switch_compartment_end - (uintptr_t) switch_compartment;
switch_cap = cheri_bounds_set(switch_cap, switcher_size);
switcher_caps[1] = switch_cap;

void *__capability comps_addr = (void *__capability) &comps;
Expand Down Expand Up @@ -173,8 +175,6 @@ void add_comp(uint8_t *_start_addr, void (*_comp_fn)(), void *_comp_fn_end)
// 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;
Expand Down
Loading

0 comments on commit 50d1cde

Please sign in to comment.