/* * 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); } }
/* * 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); }
/* * 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, ¶m->ddc, 0); CHERI_CGETTAG(tag_set, CHERI_CR_CTEMP0); if (!tag_set) cheri_capability_copy(¶m->ddc, &parent_td->td_pcb->pcb_regs.ddc); }
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); }
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); }
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); }