Process

e.g. PCC initialization

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_BASE (sys/mips/include/cherireg.h):
    • 0x000000
  • CHERI_CAP_USER_CODE_LENGTH (sys/mips/include/cherireg.h):
    • (VM_MAXUSER_ADDRESS - VM_MINUSER_ADDRESS) = 0x0000,0080,0000,0000 = 2^39
    • see tracking code below.
  • 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);
}
Created Sep 18, 2019 // Last Updated Apr 30, 2020

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?