Example: System class object capabiilties

The object type in user space is splited into two ranges:

  • non-system type numbers: [1, $2^{22}$ - 1 ];
  • system type numbers: [$2^{22}$, $2^{23}$ - 1 ];

while the object types in kernel space is [$2^{23}$, $2^{24}$ -1 ].

Cheri System class is the CHERI system type of the system library.

  • Object type: libcheri_system_type

Overview

IN file: lib/libcheri/libcheri_system.h:

The header defines the interface for the libcheri system class. Currently, it is a bit catch-all, and provides a few key service that make it easy to implement (and debug) sandboxed code. In the future, we anticipate the system class being an entry point to a number of other classes – e.g., providing an open() method that returns file-descriptor objects. We are definitely not yet at that point.

System sandbox type

// file
//  lib/libcheri/libcheri_system.h

/*
 * XXXRW: Probably should be library-private: the CHERI type of the system
 * library.
 */
extern void * __capability	libcheri_system_type;

// ??? but where it is assigned to a value?
Type allocation

Never called in current CHERIBSD source code

// file
//  lib/libcheri/libcheri_type.c

void * __capability
libcheri_system_type_alloc(void)
{

	return (libcheri_alloc_type_capability(&libcheri_system_type_next,
	    libcheri_system_type_max));
}

System sandbox creation/initialization

libcheri_system_new(...) creates a new CHERI system object for use with a specific sandbox object.

This is called during sandbox loading process.

int
libcheri_system_new(struct sandbox_object *sbop,
    struct sandbox_object **sbopp)
{
        void * __capability invoke_pcc;

        /*
         * Construct an object capability for the system-class instance that
         * will be passed into the sandbox.
         *
         * The private data pointer is to the sandbox object that this system
         * object serves.
         *
         * The code capability will simply be our $pcc.
         *
         * XXXRW: For now, we will populate $c0 with $pcc on invocation, so we
         * need to leave a full set of permissions on it.  Eventually, we
         * would prefer to limit this to LOAD and EXECUTE.
         *
         * XXXRW: We should do this once per class .. or even just once
         * globally, rather than on every object creation.
         *
         * XXXRW: Use cheri_codeptr() here in the future?
         *
         * XXXRW: Is this up-to-date?
         *
         * Set up vector pointer, remove sealing, point at tranpoline?
         */
        invoke_pcc = cheri_getpcc();
        invoke_pcc = cheri_setaddress(
            invoke_pcc, (register_t)LIBCHERI_CLASS_ENTRY(libcheri_system));

        return (sandbox_object_new_system_object(
            (__cheri_tocap void * __capability)(void *)sbop, invoke_pcc,
            libcheri_system_vtable, sbopp));
}

System sandbox inner Methods

// file
//  lib/libcheri/libcheri_system.h/c

/*
 * Just a test function.
 */
int libcheri_system_helloworld(void);

/*
 * Implementation of puts(), but with a capability argument.  No persistent
 * state, so no recovery required if an exception is thrown due to a bad
 * capability being passed in.
 */
int libcheri_system_puts(const char * __capability str);

int libcheri_system_putchar(int c);
int libcheri_system_clock_gettime(clockid_t clock_id, struct timespec * __capability tp);
int libcheri_system_calloc(size_t number, size_t size, void * __capability * __capability ptrp);
int libcheri_system_free(void * __capability ptr);

/*
 * Call a legacy user function.
 */
int libcheri_system_user_call_fn(register_t methodnum,
		register_t a0, register_t a1, register_t a2,
		register_t a3, register_t a4, register_t a5,
		register_t a6,
		void * __capability c3, void * __capability c4,
		void * __capability c5, void * __capability c6,
		void * __capability c7);

/*
 * Allow the application to register its own methods.
 */
void
libcheri_system_user_register_fn(libcheri_system_user_fn_t fn_ptr);
  • Global Data:

System sandbox vtable

LLM: ??? it looks like every sandbox will have this libcheri_system_vtable re-initialized upon sandbox initialization in sandbox_program_init(); However, if this vtable is a global variable and shared as the same for all sandboxes, will this be a conflict between all the sandboxes that are using this vtable?

Declare as extern in libcheri_system.h

// file:
//  lib/libcheri/libcheri_system.h

/*
 * Vtable for cheri_system methods.
 */
extern vm_offset_t * __capability	libcheri_system_vtable;

Defined and used in libcheri_sandbox.c:

// file:
//  lib/libcheri/libcheri_sandbox.c

/*
 * libcheri_system_vtable is defined here and not in libcheri_system.h to avoid
 * running into https://github.com/CTSRD-CHERI/cheribsd/issues/180
 */
vm_offset_t * __capability       libcheri_system_vtable;

...

int sandbox_program_init(void)
{
    ...
    /* XXXBD: cheri_system needs to do this. */
    libcheri_system_vtable = sandbox_make_vtable(NULL,
        "_libcheri_system_object", main_provided_classes);
    ...
}

sandbox_make_vtable will take the main_provided_classes parsed from the sandbox binary and create it

Exampl(e: execute hello world sandbox as a system class method

Invoke the sandbox inner methods

First path

test_sandbox_cs_helloworld() -> invoke_cheri_system_helloworld() -> libcheri_system_helloworld();

// The `invoke_cheri_system_helloworld()` will invoke hello world in a sandbox:

// file: bin/cheritest/cheritest_libcheri.c
void
test_sandbox_cs_helloworld(const struct cheri_test *ctp __unused)
{
	register_t v;

	v = invoke_cheri_system_helloworld();
	if (v < 0)
		cheritest_failure_errx("Sandbox returned %jd", (intmax_t)v);
	else
		cheritest_success();
}

The following is the declaration of the call gate of invoke_cheri_system_helloworld()

// file: libexec/cheritest-helper/cheritest-helper.h
struct cheri_object;

BEGIN_CAPABILITIES
//...
CHERITEST_CCALL int	invoke_cheri_system_helloworld(void);
//...
END_CAPABILITIES


// file: libexec/cheritest-helper/cheritest-helper.c
extern struct cheri_object cheritest;
#ifdef CHERITEST_INTERNAL
#define	CHERITEST_CCALL					\
    __attribute__((cheri_ccallee))			\
    __attribute__((cheri_method_class(cheritest)))
#else
#define	CHERITEST_CCALL					\
    __attribute__((cheri_ccall))			\
    __attribute__((cheri_method_suffix("_cap")))	\
    __attribute__((cheri_method_class(cheritest)))
#endif

int
invoke_cheri_system_helloworld(void)
{
        return (libcheri_system_helloworld());
}

The assembly code for test_sandbox_cs_helloworld():

/* file: cheritest.s , commit: def7a422bf */

000000000003c8a8 test_sandbox_cs_helloworld:
   3c8a8:       67 bd ff e0     daddiu  $sp, $sp, -32
   3c8ac:       ff bf 00 18     sd      $ra, 24($sp)
   3c8b0:       ff be 00 10     sd      $fp, 16($sp)
   3c8b4:       ff bc 00 08     sd      $gp, 8($sp)
   3c8b8:       03 a0 f0 25     move    $fp, $sp
   3c8bc:       3c 01 00 11     lui     $1, 17
   3c8c0:       00 39 08 2d     daddu   $1, $1, $25
   3c8c4:       64 3c f7 58     daddiu  $gp, $1, -2216
   3c8c8:       df 81 89 20     ld      $1, -30432($gp)
   3c8cc:       df 83 87 80     ld      $3, -30848($gp)
   3c8d0:       dc 22 00 00     ld      $2, 0($1)
   3c8d4:       d8 20 18 00     clc     $c1, $3, 0($ddc)
   3c8d8:       64 61 00 20     daddiu  $1, $3, 32
   3c8dc:       d8 40 08 00     clc     $c2, $1, 0($ddc)
   3c8e0:       df 99 87 88     ld      $25, -30840($gp)
   3c8e4:       48 03 02 bf     cgetnull        $c3
   3c8e8:       48 04 02 bf     cgetnull        $c4
   3c8ec:       48 05 02 bf     cgetnull        $c5
   3c8f0:       48 06 02 bf     cgetnull        $c6
   3c8f4:       48 07 02 bf     cgetnull        $c7
   3c8f8:       48 08 02 bf     cgetnull        $c8
   3c8fc:       48 09 02 bf     cgetnull        $c9
   3c900:       48 0a 02 bf     cgetnull        $c10
   3c904:       64 04 00 00     daddiu  $4, $zero, 0
   3c908:       64 05 00 00     daddiu  $5, $zero, 0
   3c90c:       64 06 00 00     daddiu  $6, $zero, 0
   3c910:       64 07 00 00     daddiu  $7, $zero, 0
   3c914:       64 08 00 00     daddiu  $8, $zero, 0
   3c918:       64 09 00 00     daddiu  $9, $zero, 0
   3c91c:       64 0a 00 00     daddiu  $10, $zero, 0
   3c920:       03 20 f8 09     jalr    $25
   3c924:       64 0b 00 00     daddiu  $11, $zero, 0
   3c928:       04 41 00 06     bgez    $2, 28 <test_sandbox_cs_helloworld+0x9c>
   3c92c:       00 00 00 00     nop
   3c930:       df 81 80 c8     ld      $1, -32568($gp)
   3c934:       00 02 28 00     sll     $5, $2, 0
   3c938:       df 99 84 90     ld      $25, -31600($gp)
   3c93c:       03 20 f8 09     jalr    $25
   3c940:       64 24 3b ce     daddiu  $4, $1, 15310
   3c944:       df 99 84 88     ld      $25, -31608($gp)
   3c948:       03 20 f8 09     jalr    $25
   3c94c:       00 00 00 00     nop

Another disassembly from cheriabitest:

/* file: cheriabitest.s, commit: def7a422bf*/
0000000120087310 test_sandbox_cs_helloworld:
120087310:      4a 6b 5f 80     cincoffset      $c11, $c11, -128
120087314:      fb 0b 00 06     csc     $c24, $zero, 96($c11)
120087318:      fa 4b 00 04     csc     $c18, $zero, 64($c11)
12008731c:      fa 2b 00 02     csc     $c17, $zero, 32($c11)
120087320:      48 18 58 11     cincoffset      $c24, $c11, $zero
120087324:      3c 01 00 14     lui     $1, 20
120087328:      64 21 e1 30     daddiu  $1, $1, -7888
12008732c:      48 12 60 51     cincoffset      $c18, $c12, $1
120087330:      74 32 08 60     clcbi   $c1, 34304($c18)
120087334:      74 52 03 5a     clcbi   $c2, 13728($c18)
120087338:      c8 41 00 03     cld     $2, $zero, 0($c1)
12008733c:      d8 22 00 00     clc     $c1, $zero, 0($c2)
120087340:      d8 42 00 02     clc     $c2, $zero, 32($c2)
120087344:      75 92 03 5c     clcbi   $c12, 13760($c18)
120087348:      48 03 02 bf     cgetnull        $c3
12008734c:      48 04 02 bf     cgetnull        $c4
120087350:      48 05 02 bf     cgetnull        $c5
120087354:      48 06 02 bf     cgetnull        $c6
120087358:      48 07 02 bf     cgetnull        $c7
12008735c:      48 08 02 bf     cgetnull        $c8
120087360:      48 09 02 bf     cgetnull        $c9
120087364:      48 0a 02 bf     cgetnull        $c10
120087368:      64 04 00 00     daddiu  $4, $zero, 0
12008736c:      64 05 00 00     daddiu  $5, $zero, 0
120087370:      64 06 00 00     daddiu  $6, $zero, 0
120087374:      64 07 00 00     daddiu  $7, $zero, 0
120087378:      64 08 00 00     daddiu  $8, $zero, 0
12008737c:      64 09 00 00     daddiu  $9, $zero, 0
120087380:      64 0a 00 00     daddiu  $10, $zero, 0
120087384:      48 11 63 3f     cjalr   $c12, $c17
120087388:      64 0b 00 00     daddiu  $11, $zero, 0
12008738c:      04 41 00 09     bgez    $2, 40 <test_sandbox_cs_helloworld+0xa4>
120087390:      00 00 00 00     nop
120087394:      00 02 08 00     sll     $1, $2, 0
120087398:      e8 2b 00 03     csd     $1, $zero, 0($c11)
12008739c:      4a 81 58 08     csetbounds      $c1, $c11, 8
1200873a0:      34 01 ff d7     ori     $1, $zero, 65495
1200873a4:      74 72 08 54     clcbi   $c3, 34112($c18)
1200873a8:      75 92 01 92     clcbi   $c12, 6432($c18)
1200873ac:      48 11 63 3f     cjalr   $c12, $c17
1200873b0:      48 0d 08 4d     candperm        $c13, $c1, $1
1200873b4:      75 92 01 8e     clcbi   $c12, 6368($c18)
1200873b8:      48 11 63 3f     cjalr   $c12, $c17
1200873bc:      00 00 00 00     nop

Example 3: libcheri sandboxes

Created Sep 1, 2019 // Last Updated Sep 9, 2019

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?