Beispiel #1
0
/*
 * Variation that prints the saved userspace CHERI register frame for a
 * thread.
 */
DB_SHOW_COMMAND(cheriframe, ddb_dump_cheriframe)
{
	struct thread *td;
	struct cheri_frame *cfp;
	u_int i;

	if (have_addr)
		td = db_lookup_thread(addr, TRUE);
	else
		td = curthread;

	cfp = &td->td_pcb->pcb_cheriframe;
	db_printf("Thread %d at %p\n", td->td_tid, td);
	db_printf("CHERI frame at %p\n", cfp);

	/* Laboriously load and print each user capability. */
	for (i = 0; i < 27; i++) {
		cheri_capability_load(CHERI_CR_CTEMP0,
		    (struct chericap *)&cfp->cf_c0 + i);
		DB_CHERI_REG_PRINT(CHERI_CR_CTEMP0, i);
	}
	cheri_capability_load(CHERI_CR_CTEMP0,
	    (struct chericap *)&cfp->cf_c0 + CHERIFRAME_OFF_PCC);
	db_printf("PCC ");
	DB_CHERI_CAP_PRINT(CHERI_CR_CTEMP0);
}
Beispiel #2
0
/*
 * Because contexts contain tagged capabilities, we can't just use memcpy()
 * on the data structure.  Once the C compiler knows about capabilities, then
 * direct structure assignment should be plausible.  In the mean time, an
 * explicit capability context copy routine is required.
 *
 * XXXRW: Compiler should know how to do copies of tagged capabilities.
 *
 * XXXRW: Compiler should be providing us with the temporary register.
 */
void
cheri_capability_copy(struct chericap *cp_to, struct chericap *cp_from)
{

	cheri_capability_load(CHERI_CR_CTEMP0, cp_from);
	cheri_capability_store(CHERI_CR_CTEMP0, cp_to);
}
Beispiel #3
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);
}
Beispiel #4
0
/*
 * If a signal is delivered while in a sandbox, forceably unwind the trusted
 * stack simulating a CReturn.  Clear the regular and capability register
 * files.
 *
 * When a signal is thrown in a sandbox, one option is for the kernel to
 * forceably unwind the stack by a frame.
 *
 * Note that the callee has not had a chance to clean up the mess -- and
 * particular, can't clear the register file before returning.  We therefore
 * have to do that for the callee or information/rights may leak!.
 *
 * XXXRW: Really we want to delegate this to userspace via SIGSANDBOX or
 * similar, but in the mean time.
 *
 * XXXRW: We don't yet handle floating point.
 */
int
cheri_stack_sandboxexception(struct thread *td, struct trapframe *tf,
    int signum)
{
	struct cheri_stack_frame *csfp;
	struct pcb *pcb = td->td_pcb;
	register_t s, sr, badvaddr, cause;
	f_register_t fsr;

	if (pcb->pcb_cheristack.cs_tsp == CHERI_STACK_SIZE)
		return (0);

	printf("%s: processing sandbox exception signal %d, pid %d\n",
	    __func__, signum, td->td_proc->p_pid);

#if DDB
	if (security_cheri_debugger_on_sandbox_exception)
		kdb_enter(KDB_WHY_CHERI, "CHERI sandbox exception");
#endif

	/*
	 * XXXRW: It is my belief that the trap frame in a thread is always a
	 * pointer to the PCB.  Check this is true, however, because I rely on
	 * it.
	 */
	KASSERT(td->td_frame == &pcb->pcb_regs,
	    ("%s: td_frame != pcb_regs", __func__));
	KASSERT(td->td_frame == tf, ("%s: td_frame != tf", __func__));

	/*
	 * XXXRW: It would actually be quite nice to print out some exception
	 * information here.  Otherwise all the state required to debug the
	 * sandbox failure will be lost.
	 *
	 * XXXRW: Or, has it all been sent to printf?
	 *
	 * XXXRW: Or, maybe that is actually a bad thing, since printf is
	 * quite slow and noisy, and not something we want to do on every
	 * sandbox failure.
	 */

	/*
	 * Clear the regular and capability register files to ensure no state
	 * (information, rights) is returned to the caller that shouldn't be
	 * when the callee exits unexpectedly.  Save and restore kernel-side
	 * registers, however.
	 *
	 * XXXRW: What about floating-point registers?
	 */
	sr = pcb->pcb_regs.sr;
	badvaddr = pcb->pcb_regs.badvaddr;
	cause = pcb->pcb_regs.cause;
	fsr = pcb->pcb_regs.fsr;
	bzero(&pcb->pcb_regs, sizeof(pcb->pcb_regs));
	bzero(&pcb->pcb_cheriframe, sizeof(pcb->pcb_cheriframe));
	pcb->pcb_regs.sr = sr;
	pcb->pcb_regs.badvaddr = badvaddr;
	pcb->pcb_regs.cause = cause;
	pcb->pcb_regs.fsr = fsr;

	/*
	 * Reproduce CReturn.
	 */
	csfp = &pcb->pcb_cheristack.cs_frames[pcb->pcb_cheristack.cs_tsp /
	    CHERI_FRAME_SIZE];
	pcb->pcb_cheristack.cs_tsp += CHERI_FRAME_SIZE;

	/*
	 * Pop IDC, PCC.
	 */
	s = intr_disable();
	cheri_capability_load(CHERI_CR_CTEMP, &csfp->csf_idc);
	cheri_capability_store(CHERI_CR_CTEMP, &pcb->pcb_cheriframe.cf_idc);
	cheri_capability_load(CHERI_CR_CTEMP, &csfp->csf_pcc);
	cheri_capability_store(CHERI_CR_CTEMP, &pcb->pcb_cheriframe.cf_pcc);
	intr_restore(s);

	/*
	 * Pop SP, PC (+4 already done).
	 */
	pcb->pcb_regs.sp = csfp->csf_sp;
	pcb->pcb_regs.pc = csfp->csf_pc;

	/*
	 * Set 'v0' to -1, and 'v1' to the signal number so that the consumer
	 * of CCall can handle the error.
	 *
	 * XXXRW: That isn't really quite what we want, however.  What about
	 * CCall failures themselves, and what if CReturn returns a -1 -- how
	 * should the caller interpret that?
	 */
	pcb->pcb_regs.v0 = -1;
	pcb->pcb_regs.v1 = signum;
	return (1);
}