/* * 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); }
/* * 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); }