Exemplo n.º 1
0
/*
 * Print out the trusted stack for the current thread, starting at the top.
 *
 * XXXRW: Would be nice to take a tid/pid argument rather than always use
 * curthread.
 */
DB_SHOW_COMMAND(cheristack, ddb_dump_cheristack)
{
	struct chericap c;
	struct cheri_stack_frame *csfp;
	struct pcb *pcb = curthread->td_pcb;
	u_int ctag;
	int i;

	db_printf("Trusted stack for TID %d; TSP 0x%016jx\n",
	    curthread->td_tid, (uintmax_t)pcb->pcb_cheristack.cs_tsp);
	for (i = CHERI_STACK_DEPTH - 1; i >= 0; i--) {
	    /* i > (pcb->pcb_cheristack.cs_tsp / CHERI_FRAME_SIZE); i--) { */
		csfp = &pcb->pcb_cheristack.cs_frames[i];

		db_printf("  Frame %d%c\n", i,
		    (i >= (pcb->pcb_cheristack.cs_tsp / CHERI_FRAME_SIZE)) ?
		    '*' : ' ');
		CHERI_CLC(CHERI_CR_CTEMP, CHERI_CR_KDC, &csfp->csf_idc, 0);
		CHERI_CGETTAG(ctag, CHERI_CR_CTEMP);

		c = csfp->csf_idc;
		db_printf("\tIDC: t: %u u: %u perms 0x%04jx otype 0x%016jx\n",
		    ctag, c.c_unsealed, (uintmax_t)c.c_perms,
		    (uintmax_t)c.c_otype);
		db_printf("\t\tbase 0x%016jx length 0x%016jx\n",
		    (uintmax_t)c.c_base, (uintmax_t)c.c_length);

		CHERI_CLC(CHERI_CR_CTEMP, CHERI_CR_KDC, &csfp->csf_pcc, 0);
		CHERI_CGETTAG(ctag, CHERI_CR_CTEMP);

		c = csfp->csf_pcc;
		db_printf("\tPCC: t: %u u: %u perms 0x%04jx otype 0x%016jx\n",
		    ctag, c.c_unsealed, (uintmax_t)c.c_perms,
		    (uintmax_t)c.c_otype);
		db_printf("\t\tbase 0x%016jx length 0x%016jx\n",
		    (uintmax_t)c.c_base, (uintmax_t)c.c_length);

		db_printf("\tPC: %p SP: %p\n", (void *)csfp->csf_pc,
		    (void *)csfp->csf_sp);
	}
}
Exemplo n.º 2
0
/*
 * Build a new capabilty derived from $kdc with the contents of the passed
 * flattened representation.  Only unsealed capabilities are supported;
 * capabilities must be separately sealed if required.
 *
 * XXXRW: It's not yet clear how important ordering is here -- try to do the
 * privilege downgrade in a way that will work when doing an "in place"
 * downgrade, with permissions last.
 *
 * XXXRW: In the new world order of CSetBounds, it's not clear that taking
 * explicit base/length/offset arguments is quite the right thing.
 */
void
cheri_capability_set(struct chericap *cp, uint32_t perms, void *basep,
                     size_t length, off_t off)
{
#ifdef INVARIANTS
    register_t r;
#endif

    /* 'basep' is relative to $kdc. */
    CHERI_CINCOFFSET(CHERI_CR_CTEMP0, CHERI_CR_KDC, (register_t)basep);
    CHERI_CSETBOUNDS(CHERI_CR_CTEMP0, CHERI_CR_CTEMP0,
                     (register_t)length);
    CHERI_CANDPERM(CHERI_CR_CTEMP0, CHERI_CR_CTEMP0, (register_t)perms);
    CHERI_CINCOFFSET(CHERI_CR_CTEMP0, CHERI_CR_CTEMP0, (register_t)off);

    /*
     * NB: With imprecise bounds, we want to assert that the results will
     * be 'as requested' -- i.e., that the kernel always request bounds
     * that can be represented precisly.
     *
     * XXXRW: Given these assupmtions, we actually don't need to do the
     * '+= off' above.
     */
#ifdef INVARIANTS
    CHERI_CGETTAG(r, CHERI_CR_CTEMP0);
    KASSERT(r != 0, ("%s: capability untagged", __func__));
    CHERI_CGETPERM(r, CHERI_CR_CTEMP0);
    KASSERT(r == (register_t)perms,
            ("%s: permissions 0x%x rather than 0x%x", __func__,
             (unsigned int)r, perms));
    CHERI_CGETBASE(r, CHERI_CR_CTEMP0);
    KASSERT(r == (register_t)basep,
            ("%s: base %p rather than %p", __func__, (void *)r, basep));
    CHERI_CGETLEN(r, CHERI_CR_CTEMP0);
    KASSERT(r == (register_t)length,
            ("%s: length 0x%x rather than %p", __func__,
             (unsigned int)r, (void *)length));
    CHERI_CGETOFFSET(r, CHERI_CR_CTEMP0);
    KASSERT(r == (register_t)off,
            ("%s: offset %p rather than %p", __func__, (void *)r,
             (void *)off));
#if 0
    CHERI_CGETTYPE(r, CHERI_CR_CTEMP0);
    KASSERT(r == (register_t)otypep,
            ("%s: otype %p rather than %p", __func__, (void *)r, otypep));
#endif
#endif
    CHERI_CSC(CHERI_CR_CTEMP0, CHERI_CR_KDC, (register_t)cp, 0);
}
Exemplo n.º 3
0
/*
 * When thr_new() creates a new thread, we might need to lift properties from
 * the capability state in the parent thread.  This is our opportunity to do
 * so.
 */
void
cheriabi_thr_new_md(struct thread *parent_td, struct thr_param_c *param)
{
	register_t tag_set;

	/*
	 * XXXRW: Currently, we'll install the parent's DDC in the child
	 * thread if there is (effectively) a NULL capability in the param
	 * structure for DDC.  Really, we should trigger this based on a flag
	 * set in the param, so that the parent thread can request a NULL DDC
	 * if it wants to.
	 */
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &param->ddc, 0);
	CHERI_CGETTAG(tag_set, CHERI_CR_CTEMP0);
	if (!tag_set)
		cheri_capability_copy(&param->ddc,
		    &parent_td->td_pcb->pcb_regs.ddc);
}
Exemplo n.º 4
0
void
cheri_serialize(struct cheri_serial *csp, struct chericap *cap)
{
	register_t	r;
	cheri_capability_load(CHERI_CR_CTEMP0, cap);

#if CHERICAP_SIZE == 16
	csp->cs_storage = 3;
	csp->cs_typebits = 16;
	csp->cs_permbits = 23;
#else /* CHERICAP_SIZE == 32 */
	csp->cs_storage = 4;
	csp->cs_typebits = 24;
	csp->cs_permbits = 31;
#endif

	KASSERT(csp != NULL, ("Can't serialize to a NULL pointer"));
	if (cap == NULL) {
		memset(csp, 0, sizeof(*csp));
		return;
	}

	CHERI_CGETTAG(r, CHERI_CR_CTEMP0);
	csp->cs_tag = r;
	if (csp->cs_tag) {
		CHERI_CGETTYPE(r, CHERI_CR_CTEMP0);
		csp->cs_type = r;
		CHERI_CGETPERM(r, CHERI_CR_CTEMP0);
		csp->cs_perms = r;
		CHERI_CGETSEALED(r, CHERI_CR_CTEMP0);
		csp->cs_sealed = r;
		CHERI_CGETBASE(r, CHERI_CR_CTEMP0);
		csp->cs_base = r;
		CHERI_CGETLEN(r, CHERI_CR_CTEMP0);
		csp->cs_length = r;
		CHERI_CGETOFFSET(r, CHERI_CR_CTEMP0);
		csp->cs_offset = r;
	} else
		memcpy(&csp->cs_data, cap, CHERICAP_SIZE);
}
Exemplo n.º 5
0
static int
cheriabi_set_mcontext(struct thread *td, mcontext_c_t *mcp)
{
	struct trapframe *tp;
	int tag;

	if (mcp->mc_regs[0] != UCONTEXT_MAGIC) {
		printf("mcp->mc_regs[0] != UCONTEXT_MAGIC\n");
		return (EINVAL);
	}

	tp = td->td_frame;
	cheri_trapframe_from_cheriframe(tp, &mcp->mc_cheriframe);
	bcopy((void *)&mcp->mc_regs, (void *)&td->td_frame->zero,
	    sizeof(mcp->mc_regs));
	td->td_md.md_flags = (mcp->mc_fpused & MDTD_FPUSED)
#ifdef CPU_QEMU_MALTA
	    | (td->td_md.md_flags & MDTD_QTRACE)
#endif
	    ;
	if (mcp->mc_fpused)
		bcopy((void *)&mcp->mc_fpregs, (void *)&td->td_frame->f0,
		    sizeof(mcp->mc_fpregs));
	td->td_frame->pc = mcp->mc_pc;
	td->td_frame->mullo = mcp->mullo;
	td->td_frame->mulhi = mcp->mulhi;

	cheri_capability_copy(&td->td_md.md_tls_cap, &mcp->mc_tls);
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &mcp->mc_tls, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(td->td_md.md_tls, CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		td->td_md.md_tls = NULL;

	/* Dont let user to set any bits in status and cause registers.  */

	return (0);
}
Exemplo n.º 6
0
static int
cheriabi_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
	struct trapframe *locr0 = td->td_frame;	 /* aka td->td_pcb->pcv_regs */
	struct sysentvec *se;
#ifdef OLD_ARG_HANDLING
	register_t intargs[8];
	uintptr_t ptrargs[8];
	u_int tag;
	int i, isaved, psaved, curint, curptr, nintargs, nptrargs;
#endif
	int error;

	error = 0;

	bzero(sa->args, sizeof(sa->args));

	/* compute next PC after syscall instruction */
	td->td_pcb->pcb_tpc = sa->trapframe->pc; /* Remember if restart */
	if (DELAYBRANCH(sa->trapframe->cause))	 /* Check BD bit */
		locr0->pc = MipsEmulateBranch(locr0, sa->trapframe->pc, 0, 0);
	else
		locr0->pc += sizeof(int);
	sa->code = locr0->v0;

	se = td->td_proc->p_sysent;
	if (se->sv_mask)
		sa->code &= se->sv_mask;

	if (sa->code >= se->sv_size)
		sa->callp = &se->sv_table[0];
	else
		sa->callp = &se->sv_table[sa->code];

	sa->narg = sa->callp->sy_narg;

#ifndef OLD_ARG_HANDLING
	error = cheriabi_dispatch_fill_uap(td, sa->code, sa->args);
#else

	intargs[0] = locr0->a0;
	intargs[1] = locr0->a1;
	intargs[2] = locr0->a2;
	intargs[3] = locr0->a3;
	intargs[4] = locr0->a4;
	intargs[5] = locr0->a5;
	intargs[6] = locr0->a6;
	intargs[7] = locr0->a7;
	isaved = 8;

#if defined(CPU_CHERI_CHERI0) || defined (CPU_CHERI_CHERI8) || defined(CPU_CHERI_CHERI16)
#error	CHERIABI does not support fewer than 8 argument registers
#endif
	/*
	 * XXXBD: We should ideally use a user capability rather than $kdc
	 * to generate the pointers, but then we have to answer: which one?
	 *
	 * XXXRW: The kernel cannot distinguish between pointers with tags vs.
	 * untagged (possible) integers, which is problematic when a
	 * system-call argument is an intptr_t.  We used to just use CToPtr
	 * here, but this caused untagged integer arguments to be lost.  Now
	 * we pick one of CToPtr and CToInt based on the tag -- but this is
	 * not really ideal.  Instead, we'd prefer that the kernel could
	 * differentiate between the two explicitly using tagged capabilities,
	 * which we're not yet ready to do.
	 */
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c3, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(ptrargs[0], CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		CHERI_CTOINT(ptrargs[0], CHERI_CR_CTEMP0);
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c4, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(ptrargs[1], CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		CHERI_CTOINT(ptrargs[1], CHERI_CR_CTEMP0);
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c5, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(ptrargs[2], CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		CHERI_CTOINT(ptrargs[2], CHERI_CR_CTEMP0);
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c6, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(ptrargs[3], CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		CHERI_CTOINT(ptrargs[3], CHERI_CR_CTEMP0);
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c7, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(ptrargs[4], CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		CHERI_CTOINT(ptrargs[4], CHERI_CR_CTEMP0);
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c8, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(ptrargs[5], CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		CHERI_CTOINT(ptrargs[5], CHERI_CR_CTEMP0);
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c9, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(ptrargs[6], CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		CHERI_CTOINT(ptrargs[6], CHERI_CR_CTEMP0);
	CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &locr0->c10, 0);
	CHERI_CGETTAG(tag, CHERI_CR_CTEMP0);
	if (tag)
		CHERI_CTOPTR(ptrargs[7], CHERI_CR_CTEMP0, CHERI_CR_KDC);
	else
		CHERI_CTOINT(ptrargs[7], CHERI_CR_CTEMP0);
	psaved = 8;

#ifdef TRAP_DEBUG
	if (trap_debug)
		printf("SYSCALL #%d pid:%u\n", sa->code, td->td_proc->p_pid);
#endif

	nptrargs = bitcount(CHERIABI_SYS_argmap[sa->code].sam_ptrmask);
	nintargs = sa->narg - nptrargs;
	KASSERT(nintargs <= isaved,
	    ("SYSCALL #%u pid:%u, nintargs (%u) > isaved (%u).\n",
	     sa->code, td->td_proc->p_pid, nintargs, isaved));
	KASSERT(nptrargs <= psaved,
	    ("SYSCALL #%u pid:%u, nptrargs (%u) > psaved (%u).\n",
	     sa->code, td->td_proc->p_pid, nptrargs, psaved));

	/*
	 * Check each argument to see if it is a pointer and pop an argument
	 * off the appropriate list.
	 */
	curint = curptr = 0;
	for (i = 0; i < sa->narg; i++)
		sa->args[i] =
		    (CHERIABI_SYS_argmap[sa->code].sam_ptrmask & 1 << i) ?
		    ptrargs[curptr++] : intargs[curint++];
#endif /* OLD_ARG_HANDLING */

	td->td_retval[0] = 0;
	td->td_retval[1] = locr0->v1;

	return (error);
}