static int invoke_cap_fault(register_t op) { char buffer[N], ch; __capability char *cap; cap = cheri_ptrperm(buffer, sizeof(buffer), CHERI_PERM_LOAD); switch (op) { case CHERITEST_HELPER_OP_CP2_BOUND: ch = cap[N]; return (ch); case CHERITEST_HELPER_OP_CP2_PERM: cap[0] = 0; break; case CHERITEST_HELPER_OP_CP2_TAG: cap = cheri_zerocap(); ch = cap[0]; return (ch); case CHERITEST_HELPER_OP_CP2_SEAL: cap = cheri_sealcode(cap); ch = cap[0]; return (ch); } return (0); }
int sandbox_object_load(struct sandbox_class *sbcp, struct sandbox_object *sbop) { __capability void *basecap, *sbcap; struct sandbox_metadata *sbm; size_t length; int saved_errno; uint8_t *base; /* * Perform an initial reservation of space for the sandbox, but using * anonymous memory that is neither readable nor writable. This * ensures there is space for all the various segments we will be * installing later. * * The rough sandbox memory map is as follows: * * K + 0x1000 [stack] * K [guard page] * J + 0x1000 [heap] * J [guard page] * 0x8000 [memory mapped binary] (SANDBOX_ENTRY) * 0x2000 [guard page] * 0x1000 [read-only sandbox metadata page] * 0x0000 [guard page] * * Address constants in sandbox.h must be synchronised with the layout * implemented here. Location and contents of sandbox metadata is * part of the ABI. */ length = sbcp->sbc_sandboxlen; base = sbop->sbo_mem = mmap(NULL, length, 0, MAP_ANON, -1, 0); if (sbop->sbo_mem == MAP_FAILED) { saved_errno = errno; warn("%s: mmap region", __func__); goto error; } /* * Skip guard page(s) to the base of the metadata structure. */ base += SANDBOX_METADATA_BASE; length -= SANDBOX_METADATA_BASE; /* * Map metadata structure -- but can't fill it out until we have * calculated all the other addresses involved. */ if ((sbm = mmap(base, METADATA_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_FIXED, -1, 0)) == MAP_FAILED) { saved_errno = errno; warn("%s: mmap metadata", __func__); goto error; } /* * Skip forward to the mapping location for the binary -- in case we * add more metadata in the future. Assert that we didn't bump into * the sandbox entry address. This address is hard to change as it is * the address used in static linking for sandboxed code. */ assert((register_t)base - (register_t)sbop->sbo_mem < SANDBOX_ENTRY); base = (void *)((register_t)sbop->sbo_mem + SANDBOX_ENTRY); length = sbcp->sbc_sandboxlen - SANDBOX_ENTRY; /* * Map program binary. */ if (mmap(base, sbcp->sbc_stat.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, sbcp->sbc_fd, 0) == MAP_FAILED) { saved_errno = errno; warn("%s: mmap %s", __func__, sbcp->sbc_path); goto error; } base += roundup2(sbcp->sbc_stat.st_size, PAGE_SIZE); length += roundup2(sbcp->sbc_stat.st_size, PAGE_SIZE); /* * Skip guard page. */ base += GUARD_PAGE_SIZE; length -= GUARD_PAGE_SIZE; /* * Heap. */ sbop->sbo_heapbase = (register_t)base - (register_t)sbop->sbo_mem; sbop->sbo_heaplen = length - (GUARD_PAGE_SIZE + STACK_SIZE); if (mmap(base, sbop->sbo_heaplen, PROT_READ | PROT_WRITE, MAP_ANON | MAP_FIXED, -1, 0) == MAP_FAILED) { saved_errno = errno; warn("%s: mmap heap", __func__); goto error; } memset(base, 0, sbop->sbo_heaplen); base += sbop->sbo_heaplen; length -= sbop->sbo_heaplen; /* * Skip guard page. */ base += GUARD_PAGE_SIZE; length -= GUARD_PAGE_SIZE; /* * Stack. */ if (mmap(base, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_FIXED, -1, 0) == MAP_FAILED) { saved_errno = errno; warn("%s: mmap stack", __func__); goto error; } memset(base, 0, length); base += STACK_SIZE; length -= STACK_SIZE; /* * There should not be too much, nor too little space remaining. 0 * is our Goldilocks number. */ assert(length == 0); /* * Now that addresses are known, write out metadata for in-sandbox * use; then mprotect() so that it can't be modified by the sandbox. */ sbm->sbm_heapbase = sbop->sbo_heapbase; sbm->sbm_heaplen = sbop->sbo_heaplen; if (mprotect(base, METADATA_SIZE, PROT_READ) < 0) { saved_errno = errno; warn("%s: mprotect metadata", __func__); goto error; } if (sbcp->sbc_sandbox_class_statp != NULL) { (void)sandbox_stat_object_register( &sbop->sbo_sandbox_object_statp, sbcp->sbc_sandbox_class_statp, SANDBOX_OBJECT_TYPE_POINTER, (uintptr_t)sbop->sbo_mem); SANDBOX_CLASS_ALLOC(sbcp->sbc_sandbox_class_statp); } /* * Construct a generic capability that describes the combined * data/code segment that we will seal. */ basecap = cheri_ptrtype(sbop->sbo_mem, sbcp->sbc_sandboxlen, SANDBOX_ENTRY); /* Construct sealed code capability. */ sbcap = cheri_andperm(basecap, CHERI_PERM_EXECUTE | CHERI_PERM_LOAD | CHERI_PERM_SEAL); sbop->sbo_cheri_object.co_codecap = cheri_sealcode(sbcap); /* Construct sealed data capability. */ sbcap = cheri_andperm(basecap, CHERI_PERM_LOAD | CHERI_PERM_STORE | CHERI_PERM_LOAD_CAP | CHERI_PERM_STORE_CAP | CHERI_PERM_STORE_EPHEM_CAP); sbop->sbo_cheri_object.co_datacap = cheri_sealdata(sbcap, basecap); /* * Construct an object capability for the system class instance that * will be passed into the sandbox. Its code capability is just our * $c0; the data capability is to the sandbox structure itself, which * allows the system class to identify which sandbox a request is * being issued from. * * Note that $c0 in the 'sandbox' will be set from $pcc, so leave a * full set of write/etc permissions on the code capability. */ basecap = cheri_settype(cheri_getdefault(), (register_t)CHERI_CLASS_ENTRY(libcheri_system)); sbop->sbo_cheri_system_object.co_codecap = cheri_sealcode(basecap); sbcap = cheri_ptr(sbop, sizeof(*sbop)); sbcap = cheri_andperm(sbcap, CHERI_PERM_LOAD | CHERI_PERM_STORE | CHERI_PERM_LOAD_CAP | CHERI_PERM_STORE_CAP | CHERI_PERM_STORE_EPHEM_CAP); sbop->sbo_cheri_system_object.co_datacap = cheri_sealdata(sbcap, basecap); return (0); error: if (sbop->sbo_mem != NULL) munmap(sbop->sbo_mem, sbcp->sbc_sandboxlen); errno = saved_errno; return (-1); }