Sandbox Methods

sandbox_provided_classes

No two binaries can provide the same class as vtable offsets would be inconsistant.

/*
 * List of classes provided by a sandbox binary.  Each binary can
 * support one or more classes.  No two binaries can provide the same
 * class as vtable offsets would be inconsistant.
 */
struct sandbox_provided_classes {
	struct sandbox_provided_methods	**spcs_classes;	/* Class pointers */
	size_t				  spcs_nclasses; /* Number of methods */
	size_t				  spcs_maxclasses; /* Array size */
	size_t				  spcs_nmethods; /* Total methods */
	vm_offset_t			  spcs_base;	/* Base of vtable */
};

sandbox_required_method

/*
 * Description of a method required by a sandbox to be called by ccall.
 */
struct sandbox_required_method {
	char		*srm_class;		/* Class name */
	char		*srm_method;		/* Method name */
	vm_offset_t	 srm_index_offset;	/* Offset of caller variable */
	vm_offset_t	 srm_vtable_offset;	/* Method number */
	bool		 srm_resolved;		/* Resolved? */
};

sandbox_make_vtable

// file:
//  lib/libcheri/libcheri_sandbox_methods.c

vm_offset_t * __capability
sandbox_make_vtable(void *dataptr, const char *class,
    struct sandbox_provided_classes *provided_classes)
{
        vm_offset_t * __capability vtable;
        vm_offset_t *cheri_ccallee_base;
        size_t i, index, length, m;
        struct sandbox_provided_method *pm;
        struct sandbox_provided_methods *pms;

        if (provided_classes->spcs_nclasses == 0)
                return (NULL);

        if ((vtable = calloc_c(provided_classes->spcs_nmethods,
            sizeof(*vtable))) == NULL) {
                warnx("%s: calloc", __func__);
                return (NULL);
        }
#ifdef __CHERI_PURE_CAPABILITY__
        /*
         * XXXRW: For system classes, a NULL dataptr is passed in, signifying
         * that bases are relative to virtual address 0x0.  This isn't really
         * the right thing for CheriABI, where we should instead pass in the
         * default capability with an offset of zero.  For now, handle that
         * here, but probably the caller should do that instead.
         */
        if (dataptr == NULL)
                dataptr = cheri_clearperm(
                    cheri_setoffset(cheri_getpcc(), 0), CHERI_PERM_EXECUTE);

#endif
        cheri_ccallee_base = (vm_offset_t *)dataptr + provided_classes->spcs_base
            / sizeof(vm_offset_t);
        length = provided_classes->spcs_nmethods * sizeof(*vtable);
        assert(cheri_getlen(vtable) >= length);
#ifdef DEBUG
        printf("%s(%s): spcs_nmethods = %zd, length = %zd\n", __func__, class,
            provided_classes->spcs_nmethods, length);
#endif

        if (class == NULL) {
#ifdef DEBUG
                printf("%s: class == NULL -> copying whole table\n", __func__);
#endif
                memcpy_c_tocap(vtable, cheri_ccallee_base, length);
                return (cheri_andperm(vtable, CHERI_PERM_LOAD));
        }

        for (i = 0; i < provided_classes->spcs_nclasses; i++) {
                pms = provided_classes->spcs_classes[i];
#ifdef DEBUG
                printf("%s: provided_classes[%zd]='%s', want '%s'\n", __func__,
                    i, pms->spms_class, class);
#endif
                if (strcmp(pms->spms_class, class) != 0)
                        continue;

                for (m = 0; m < pms->spms_nmethods; m++) {
                        pm = pms->spms_methods + m;
                        index = (pm->spm_index_offset -
                            provided_classes->spcs_base) / sizeof(*vtable);
#if defined(DEBUG) && DEBUG > 1
                        printf("%s: provided_classes[%zd] method[%zd] is '%s'."
                               " index = %zd\n",
                            __func__, i, m, pm->spm_method, index);
#endif
                        assert(vtable[index] == 0);
                        vtable[index] = cheri_ccallee_base[index];
                }
#ifdef DEBUG
                printf("%s: added [%zd] methods to vtable for %s\n", __func__,
                    m, pms->spms_class);
#endif
                /* TODO: set bounds on vtable up to last index? */
                return (cheri_andperm(vtable, CHERI_PERM_LOAD));
        }
        free_c(vtable);
        return (NULL);
}
Created Sep 5, 2019 // Last Updated Sep 5, 2019

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

... what would you change?