CheriBSD Context Switch


References:

[1] CHERI programmer’s guide, chapter 8.2, UCAM-CL-TR-877, 2015.


Capability state save/restore for each thread and domain inside.

CheriBSD extends the kernel’s support for context management and switching to provide each user thread with its own capability-register file. This allows each thread to have its own complete capability state, compatible with the idea that capabilities are compiler-managed.

Context switching to kernel in 3 ways:

  • an initial saving of the userspace $PCC and C0 performed by the hardware and low-level exception handling code;
  • a more complete capability register context save and restore when transitioning from a low-level exception handler to kernel C code;
  • finally, saving and restoring of a capability-register-file subset during voluntary kernel context switches.

PCB struct extended with CHERI state

Extends thread control block, pcb, with four new fields:

  • pcb_cheriframe: userspace CHERI registers;
  • pcb_cheristack: the CHERI trusted stack;
  • pcb_cheri_signal: signal handling context to install when a signal is delivered within a sandbox;
  • pcb_cherik_frame: caller-save registers across a kernel voluntary context switch.

Kernel state – no capability

2015 programmer’s guide:

  • Kernel itself makes only minor use of capabilities;
  • Kernel is not currently compiled with a capability-aware compiler;
  • kernel threads do not have full capability-register-file state in their own PCBs.

Currently, CheriBSD maintains a ‘full’ CHERI capability-register context only for userspace, not the kernel, as the kernel is compiled by a CHERI-unaware compiler. Instead, the kernel uses fixed global values for C0 and PCC, and its context switches maintain two capability registers for use in setting up userspace state, performing capability-aware memory copies, etc: C11 and C12.

Context-switching philosophy

Fast-exception handlers for exception delivery -> full userspace context saving for a full C function execution.

MIPS: use (K0, K1) as reserved exception handling registers;

CHERI: saves the userspace C0 in KR2C; then installs the kernel’s own C0.

Lazy context-switching of capability-coprocessor is not currently implemented, requiring a full save and restore of the capability register file when entering kernel C code.

PCB setup and state changes

PCB CHERI state initialization: execve -> exec_setregs ->

  • cheri_exec_setregs: sets up the first thread’s live and signal-handling C0, C11 (stack), IDC, and PCC registers for ambient authority;
  • cheri_stack_init: initialize an empty trusted stack.

MIPS machine dependent state for a new thread: cpu_set_upcall ->

  • cheri_context_copy: register context;
  • literal cheri_signal_copy: signal delivery context;
  • cheri_stack_copy: copy the current trusted stack the the new thread. Desiable or should get a fresh new trusted stack?

fork system call, implemented in MIPS machine depedent cpu_fork-> cheri_context_copy; cheri_signal_copy; cheri_stack_copy.

4 types of context switches

  • Low-level exception enter/return. CHERI_EXCEPTION_ETNER, CHERI_EXCEPTION_RETURN;

  • User-to-kernel switch: SAVE_U_PCB_CHERIFRAME, RESTORE_U_PCB_CHERIFRAME. This occurs if an excecption deliverd to user code cannot be satisfied without entering C code – e.g. to process a full VM fault rather than just a TLB miss that a low-level assembly handler can resolve.

  • Kernel involuntary switch: an exception preempts the kernel istelf (e.g. a kernel TLB miss or interrupt), the full MIPS general-purpose state will be saved by MipsKernGenException, but only C11 and C12 will be preserved, as the kernel currently use only these capability registers. In the future, this code will need to preserve a full kernel CHERI frame.

  • Kernel voluntary switch: If a kernel thread sleeps (perhaps due to blocking on a mutex or waiting on I/O), then a voluntary context switch via cpu_switch, which in turn will call SAVE_U_PCB_CHERIKFRAME and RESTORE_U_PCB_CHERIKFRAME to save and restore callersave registers in the PCB.


Questions/Proposals

compiler-manged capabilities: for compiler to be able to manage capabilities, each thread must have its own complete capability state. Extending this idea, if compiler could manage all the context switching states of a thread, we don’t need an operating system anymore, yes? So if entire system, all applications, resides in the same address space, then, we can get ride of operating system to do context switching and all work will be done by compilers, automatically. Reasonable?

kernel code compilation: To use capability inside kernel, we must use capability-aware compiler to compile kernel code. However, currently not done yet (2015, programmer’s guide). What is the main challenge here?


Created Jul 14, 2019 // Last Updated Oct 27, 2019

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

... what would you change?