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? */
};
// 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);
}
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?