Example #1
0
/*
 * Allocate a new cheri_fd object for an already-open file descriptor.
 */
int
cheri_fd_new(int fd, struct cheri_object *cop)
{
	__capability void *codecap, *datacap;
	struct cheri_fd *cfp;

	cfp = calloc(1, sizeof(*cfp));
	if (cfp == NULL) {
		errno = ENOMEM;
		return (-1);
	}
	CHERI_SYSTEM_OBJECT_INIT(cfp, cheri_fd_vtable);
	cfp->cf_fd = fd;

	/*
	 * Construct a sealed code capability for the class.  This is just the
	 * ambient $pcc with the offset set to the entry address.
	 *
	 * XXXRW: For now, when invoked, we install $pcc into $c0, so this
	 * needs a full set of permissions rather than just LOAD/EXECUTE. In
	 * the future, we will want to preserve a copy of cheri_getdefault()
	 * in the struct cheri_fd to be reinstalled by the entry code.
	 *
	 * XXXRW: In the future, use cheri_codeptr() here?
	 */
	codecap = cheri_setoffset(cheri_getpcc(),
	    (register_t)CHERI_CLASS_ENTRY(cheri_fd));
	cop->co_codecap = cheri_seal(codecap, cheri_fd_type);

	/*
	 * Construct a sealed data capability for the class.  This describes
	 * the 'struct cheri_fd' for the specific file descriptor.  The $c0
	 * to reinstall later is the first field in the structure.
	 *
	 * XXXRW: Should we also do an explicit cheri_setoffset()?
	 */
	datacap = cheri_ptrperm(cfp, sizeof(*cfp), CHERI_PERM_GLOBAL |
	    CHERI_PERM_LOAD | CHERI_PERM_LOAD_CAP | CHERI_PERM_STORE |
	    CHERI_PERM_STORE_CAP);
	cop->co_datacap = cheri_seal(datacap, cheri_fd_type);
	return (0);
}
Example #2
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);
}