Kernel object manipulation is mainly defined in sys/cheri/cheri_otype.c
.
A global sealing capability kernel_sealcap
is used throughout the kernel; it is initiliazed in _start()
.
kernel_sealcap
is initialized to have PCC with offset CHERI_SEALCAP_KERNEL_BASE
, bounds CHERI_SEALCAP_KERNEL_LENGTH
, perms CHERI_SEALCAP_KERNEL_PERMS
.
See more on Cheri kernel booting
A struct unrhdr *cheri_otypes
is used to maintain a unit number space for type value allocations.
The unit number space is created as a set of all possible type values for allocation. The unit number space is named cheri_otypes
, which is defined as:
static struct unrhdr *cheri_otypes;
unit number space: It is a number space described by the unit number space header as below:
// file:
// sys/sys/_unrhdr.h
/* Header element for a unr number space. */
struct unrhdr {
TAILQ_HEAD(unrhd,unr) head;
u_int low; /* Lowest item */
u_int high; /* Highest item */
u_int busy; /* Count of allocated items */
u_int alloc; /* Count of memory allocations */
u_int first; /* items in allocated from start */
u_int last; /* items free at end */
struct mtx *mtx;
TAILQ_HEAD(unrfr,unr) ppfree; /* Items to be freed after mtx
lock dropped */
};
Basically, it maintains a set of unit numbers from low
to high
, while keeping track of the number of allocated items, the items allocated, etc.
The unit numeber space is initialized by creating a struct unrhdr
which represents a set of numbers in [CHERI_OTYPE_KERN_MIN, CHERI_OTYPE_KERN_MAX], with a lock cheri_otype_lock
, which is used to lock the set internally evey time the unit number is allocated/freed from the set.
// file:
// sys/cheri/cheri_otype.c
static void cheri_otype_init(void *dummy __unused)
{
mtx_init(&cheri_otype_lock, "CHERI object type lock", NULL, MTX_DEF);
cheri_otypes = new_unrhdr(CHERI_OTYPE_KERN_MIN,
CHERI_OTYPE_KERN_MAX, &cheri_otype_lock);
}
SYSINIT(cheri_otype_init, SI_SUB_LOCK, SI_ORDER_FIRST, cheri_otype_init, NULL);
This function is called during system startup via registeration of SYSINT
macro above.
A type is allocated via cheri_otype_alloc()
. It returns an otype_t
, which is defined as a capability type:
// file
// sys/sys/types.h
typedef void * __capability otype_t;
cheri_otype_alloc
use a global sealing capability, kernel_sealcap
, to create a capability with a new type. Type value is generated by alloc_unr()
which allocates a unit number from unit number space cheri_otype
.
kenrel_sealcap
is initialized during boot.
// file:
// sys/cheri/cheri_otype.c
otype_t cheri_otype_alloc(void)
{
u_int type;
type = alloc_unr(cheri_otypes);
if (type == -1)
return (NULL);
return (cheri_maketype(kernel_sealcap,
type - CHERI_SEALCAP_KERNEL_BASE));
}
cheri_otype_free
is used to return a type to the pool. Ideally we would ensure that no capablities of this type remain in memory, but that would be VERY expensive.
In practice, most consumers will never free a type.
// file:
// sys/cheri/cheri_otype.c
void cheri_otype_free(otype_t cap)
{
u_int type;
type = cheri_getbase(cap);
free_unr(cheri_otypes, type);
}
Until CheriBSD commit (e430b100ab1e8408ec92655ad26786bb5ec23ef1) on Aug 29, there is no call to ‘cheri_otype_free()’ from any place in the entire cheribsd source code (master branch).
Until CheriBSD commit (e430b100ab1e8408ec92655ad26786bb5ec23ef1) on Aug 29, there is no call to ‘cheri_otype_alloc()’ from any place in the entire cheribsd source code (master branch).
However, cheri_otype_init
is called during system boot.
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?