Every userspace PCC get default bound as 2^39.
hybridabi_capability_set_user_entry()
creates the code capability with entry
address. The PCC base is default as CHERI_CAP_USER_CODE_BASE
, length is CHERI_CAP_USER_CODE_LENGTH
, perm is CHERI_CAP_USER_CODE_PERMS
.
CHERI_CAP_USER_CODE_PERMS (sys/mips/include/cherireg.h):
CHERI_PERMS_USERSPACE | CHERI_PERM_EXECUTE
#define CHERI_PERMS_USERSPACE \
(CHERI_PERM_GLOBAL | CHERI_PERM_LOAD | CHERI_PERM_LOAD_CAP | \
CHERI_PERM_CCALL | (CHERI_PERMS_SWALL & ~CHERI_PERM_CHERIABI_VMMAP))
// file
// sys/mips/include/vmparam.h
#define VM_MINUSER_ADDRESS ((vm_offset_t)0x00000000)
#ifdef __mips_n64
#define VM_MAXUSER_ADDRESS (VM_MINUSER_ADDRESS + (NPDEPG * NBSEG)) // 8 byte entry: 512 * 2^30 = 2^39 = 0x0000,0080,0000,0000
// 256-bit/32 byte entry: 128 * 2^30 = 0x0000,0020,0000,0000
#else
#define VM_MAXUSER_ADDRESS ((vm_offset_t)0x80000000)
#endif
// file
// sys/mips/include/param.h
#define NPTEPG (PAGE_SIZE/(sizeof (pt_entry_t))) // 512 for 8 byte ptrs
#define NPDEPG (PAGE_SIZE/(sizeof (pd_entry_t)))
#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */
#if defined(__mips_n32) || defined(__mips_n64) /* PHYSADDR_64_BIT */
#define NPTEPGSHIFT 9 /* LOG2(NPTEPG) */
#else
#define NPTEPGSHIFT 10 /* LOG2(NPTEPG) */
#endif
#ifdef __mips_n64
#define NPDEPGSHIFT 9 /* LOG2(NPTEPG) */
#define SEGSHIFT (PAGE_SHIFT + NPTEPGSHIFT + NPDEPGSHIFT) // 12 + 9 + 9 = 30
#define NBSEG (1ul << SEGSHIFT) // 2^30
#else
#define NPDEPGSHIFT 10 /* LOG2(NPTEPG) */
#define SEGSHIFT (PAGE_SHIFT + NPTEPGSHIFT)
#define NBSEG (1 << SEGSHIFT) /* bytes/segment */
#endif
// file:
// sys/mips/cheri/hybridabi_machdep.c
/*
* Common per-thread CHERI state initialisation across execve(2) and
* additional thread creation.
*/
static void
hybridabi_thread_init(struct thread *td, unsigned long entry_addr)
{
struct cheri_signal *csigp;
struct trapframe *frame;
/*
* We assume that the caller has initialised the trapframe to zeroes
* -- but do a quick assertion or two to catch programmer error. We
* might want to check this with a more thorough set of assertions in
* the future.
*/
frame = &td->td_pcb->pcb_regs;
KASSERT(*(uint64_t *)&frame->ddc == 0, ("%s: non-zero initial $ddc",
__func__));
KASSERT(*(uint64_t *)&frame->pcc == 0, ("%s: non-zero initial $epcc",
__func__));
/*
* XXXRW: Experimental CheriABI initialises $ddc with full user
* privilege, and all other user-accessible capability registers with
* no rights at all. The runtime linker/compiler/application can
* propagate around rights as required.
*/
hybridabi_capability_set_user_ddc(&frame->ddc);
hybridabi_capability_set_user_csp(&frame->csp);
hybridabi_capability_set_user_idc(&frame->idc);
hybridabi_capability_set_user_entry(&frame->pcc, entry_addr);
hybridabi_capability_set_user_entry(&frame->c12, entry_addr);
/*
* Initialise signal-handling state; this can't yet be modified
* by userspace, but the principle is that signal handlers should run
* with ambient authority unless given up by the userspace runtime
* explicitly.
*/
csigp = &td->td_pcb->pcb_cherisignal;
bzero(csigp, sizeof(*csigp));
hybridabi_capability_set_user_ddc(&csigp->csig_ddc);
hybridabi_capability_set_user_csp(&csigp->csig_csp);
hybridabi_capability_set_user_csp(&csigp->csig_default_stack);
hybridabi_capability_set_user_idc(&csigp->csig_idc);
hybridabi_capability_set_user_pcc(&csigp->csig_pcc);
csigp->csig_sigcode = cheri_sigcode_capability(td);
/*
* Set up root for the userspace object-type sealing capability tree.
* This can be queried using sysarch(2).
*/
cheri_capability_set_user_sealcap(&td->td_proc->p_md.md_cheri_sealcap);
}
}
static void
hybridabi_capability_set_user_entry(void * __capability *cp,
unsigned long entry_addr)
{
/*
* Set the jump target regigster for the pure capability calling
* convention.
*/
*cp = cheri_capability_build_user_code(CHERI_CAP_USER_CODE_PERMS,
CHERI_CAP_USER_CODE_BASE, CHERI_CAP_USER_CODE_LENGTH, entry_addr);
}
// for cheriabi:
// sys/mips/cheri/cheriabi_machdep.c
/*
* Common per-thread CHERI state initialisation across execve(2) and
* additional thread creation.
*/
void
cheriabi_newthread_init(struct thread *td)
{
struct cheri_signal *csigp;
struct trapframe *frame;
/*
* We assume that the caller has initialised the trapframe to zeroes
* and then set idc, and pcc appropriatly. We might want to check
* this with a more thorough set of assertions in the future.
*/
frame = &td->td_pcb->pcb_regs;
KASSERT(frame->pcc != NULL, ("%s: NULL $epcc", __func__));
/*
* Initialise signal-handling state; this can't yet be modified
* by userspace, but the principle is that signal handlers should run
* with ambient authority unless given up by the userspace runtime
* explicitly. The caller will initialise the stack fields.
*
* Note that some fields are overwritten later in
* exec_setregs() for the initial thread.
*/
csigp = &td->td_pcb->pcb_cherisignal;
bzero(csigp, sizeof(*csigp));
/* Note: csig_{ddc,idc,pcc} are set to NULL in the pure-capability abi */
csigp->csig_sigcode = cheri_sigcode_capability(td);
/*
* Set up root for the userspace object-type sealing capability tree.
* This can be queried using sysarch(2).
*/
cheri_capability_set_user_sealcap(&td->td_proc->p_md.md_cheri_sealcap);
}
cheri_capability_build_user_code(perms, basep, length, off)
is a macro mapped to _cheri_capability_build_user_code(perms, basep, length, off, __func__, __LINE__)
(in sys/cheri/cheri.h).
// file
// sys/mips/cheri/cheri.c
/*
* Build a new userspace capability derived from userspace_cap.
* The resulting capability may include both read and execute permissions,
* but not write.
*/
void * __capability
_cheri_capability_build_user_code(uint32_t perms, vaddr_t basep, size_t length,
off_t off, const char* func, int line)
{
KASSERT((perms & ~CHERI_CAP_USER_CODE_PERMS) == 0,
("%s:%d: perms %x has permission not in CHERI_CAP_USER_CODE_PERMS %x",
func, line, perms, CHERI_CAP_USER_CODE_PERMS));
return (_cheri_capability_build_user_rwx(
perms & CHERI_CAP_USER_CODE_PERMS, basep, length, off, func, line));
}
_cheri_capability_build_user_rwx
is defined as
// sys/cheri/cheri_usercap.c: 83
/*
* Build a new userspace capability derived from userspace_cap.
* The resulting capability may include read, write, and execute permissions.
*
* This function violates W^X and its use is discouraged and the reason for
* use should be documented in a comment when it is used.
*/
void * __capability
_cheri_capability_build_user_rwx(uint32_t perms, vaddr_t basep, size_t length,
off_t off, const char* func __unused, int line __unused)
{
void * __capability tmpcap;
tmpcap = cheri_setoffset(cheri_andperm(cheri_csetbounds(
cheri_setoffset(userspace_cap, basep), length), perms), off);
KASSERT(cheri_getlen(tmpcap) == length,
("%s:%d: Constructed capability has wrong length 0x%zx != 0x%zx: "
_CHERI_PRINTF_CAP_FMT, func, line, cheri_getlen(tmpcap), length,
_CHERI_PRINTF_CAP_ARG(tmpcap)));
return (tmpcap);
}
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?