Skip to content

Commit

Permalink
procstat: Enable procstat to access c18n statistics
Browse files Browse the repository at this point in the history
Co-authored-by: Dapeng Gao <[email protected]>
  • Loading branch information
rwatson and dpgao committed Jun 4, 2024
1 parent d22b6db commit b7e170a
Show file tree
Hide file tree
Showing 21 changed files with 304 additions and 8 deletions.
2 changes: 2 additions & 0 deletions lib/libprocstat/Symbol.map
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@ FBSD_1.7 {
procstat_getquarantining;
procstat_get_revoker_epoch;
procstat_get_revoker_state;
procstat_freec18n;
procstat_getc18n;
};
46 changes: 46 additions & 0 deletions lib/libprocstat/libprocstat.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,52 @@ procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
p = NULL;
}

int
procstat_getc18n(struct procstat *procstat, struct kinfo_proc *kp,
struct rtld_c18n_stats *stats)
{
int name[4];
size_t len = RTLD_C18N_STATS_MAX_SIZE;
_Alignas(struct rtld_c18n_stats) char buf[RTLD_C18N_STATS_MAX_SIZE];
struct rtld_c18n_stats *rcs = (struct rtld_c18n_stats *)buf;

if (stats == NULL)
goto out;

switch (procstat->type) {
case PROCSTAT_KVM:
warnx("kvm method is not supported");
goto out;

case PROCSTAT_SYSCTL:
break;

case PROCSTAT_CORE:
warnx("core method is not supported");
goto out;

default:
warnx("unknown access method: %d", procstat->type);
goto out;
}

name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_C18N;
name[3] = kp->ki_pid;
if (sysctl(name, nitems(name), buf, &len, NULL, 0) != 0) {
if (errno != ESRCH && errno != EPERM && errno != ENOEXEC)
warn("sysctl(kern.proc.c18n)");
goto out;
}
if (len < sizeof(*stats) || rcs->version != RTLD_C18N_STATS_VERSION)
goto out;
*stats = *rcs;
return (0);
out:
return (-1);
}

struct filestat_list *
procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
{
Expand Down
3 changes: 3 additions & 0 deletions lib/libprocstat/libprocstat.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <sys/elf.h>
#endif
#include <sys/caprights.h>
#include <cheri/c18n.h>

/*
* Vnode types.
Expand Down Expand Up @@ -215,6 +216,8 @@ void procstat_freeptlwpinfo(struct procstat *procstat,
void procstat_freevmmap(struct procstat *procstat,
struct kinfo_vmentry *vmmap);
struct advlock_list *procstat_getadvlock(struct procstat *procstat);
int procstat_getc18n(struct procstat *procstat, struct kinfo_proc *kp,
struct rtld_c18n_stats *stats);
struct filestat_list *procstat_getfiles(struct procstat *procstat,
struct kinfo_proc *kp, int mmapped);
struct kinfo_proc *procstat_getprocs(struct procstat *procstat,
Expand Down
2 changes: 1 addition & 1 deletion libexec/rtld-elf/rtld.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,7 +987,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)

#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
if (C18N_ENABLED) {
c18n_init(&obj_rtld);
c18n_init(&obj_rtld, aux_info);

/*
* Manually register the main object after the policy is loaded.
Expand Down
13 changes: 12 additions & 1 deletion libexec/rtld-elf/rtld_c18n.c
Original file line number Diff line number Diff line change
Expand Up @@ -1556,14 +1556,15 @@ tramp_reflect(const void *data)
#define C18N_FUNC_SIG_COUNT 72

void
c18n_init(Obj_Entry *obj_rtld)
c18n_init(Obj_Entry *obj_rtld, Elf_Auxinfo *aux_info[])
{
extern const char c18n_default_policy[];
extern const size_t c18n_default_policy_size;

int fd;
char *file;
struct stat st;
struct cheri_c18n_info *info;

/*
* Create memory mapping for compartmentalisation statistics.
Expand All @@ -1588,6 +1589,16 @@ c18n_init(Obj_Entry *obj_rtld)
atomic_store_explicit(&c18n_stats->version, RTLD_C18N_STATS_VERSION,
memory_order_release);

if (aux_info[AT_CHERI_C18N] != NULL) {
info = aux_info[AT_CHERI_C18N]->a_un.a_ptr;
*info = (struct cheri_c18n_info) {
.stats_size = sizeof(*c18n_stats),
.stats = c18n_stats
};
atomic_store_explicit(&info->version, CHERI_C18N_INFO_VERSION,
memory_order_release);
}

/*
* Initialise compartment table, add the RTLD compartment, load the
* default policy, and load the user-supplied policy.
Expand Down
2 changes: 1 addition & 1 deletion libexec/rtld-elf/rtld_c18n.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ void *_rtld_tlsdesc_static_c18n(void *);
void *_rtld_tlsdesc_undef_c18n(void *);
void *_rtld_tlsdesc_dynamic_c18n(void *);

void c18n_init(Obj_Entry *);
void c18n_init(Obj_Entry *, Elf_Auxinfo *[]);
void c18n_init2(void);

#include "rtld_c18n_machdep.h"
Expand Down
13 changes: 13 additions & 0 deletions sys/cheri/c18n.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ struct rtld_c18n_stats {
_Atomic(size_t) rcs_bytes_total;
};

/*
* The interface provided by the kernel for RTLD to supply compartmentalisation
* information. The version field doubles as a synchronisation flag where a
* non-zero value indicates that the other fields have been initialised.
*/
#define CHERI_C18N_INFO_VERSION 1

struct cheri_c18n_info {
_Atomic(uint8_t) version;
size_t stats_size;
struct rtld_c18n_stats * __kerncap stats;
};

#ifndef IN_RTLD
#undef _Atomic
#endif
Expand Down
1 change: 1 addition & 0 deletions sys/kern/imgact_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,7 @@ __elfN(freebsd_copyout_auxargs)(struct image_params *imgp, uintcap_t base)
AUXARGS_ENTRY(pos, AT_USRSTACKBASE, round_page(vmspace->vm_stacktop));
stacksz = imgp->proc->p_limit->pl_rlimit[RLIMIT_STACK].rlim_cur;
AUXARGS_ENTRY(pos, AT_USRSTACKLIM, stacksz);
AUXARGS_ENTRY_PTR(pos, AT_CHERI_C18N, imgp->c18n_info);
AUXARGS_ENTRY(pos, AT_NULL, 0);

free(imgp->auxargs, M_TEMP);
Expand Down
13 changes: 13 additions & 0 deletions sys/kern/kern_exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
#include <security/mac/mac_framework.h>

#if __has_feature(capabilities)
#include <cheri/c18n.h>
#include <cheri/cheri.h>
#include <cheri/cheric.h>
#include <cheri/cherireg.h>
Expand Down Expand Up @@ -1926,6 +1927,18 @@ exec_copyout_strings(struct image_params *imgp, uintcap_t *stack_base)
ustringp = destp;
#endif

#if __has_feature(capabilities)
/*
* Allocate the compartment statistics header.
*/
destp -= sizeof(*imgp->c18n_info);
destp = rounddown2(destp, sizeof(void * __capability));
imgp->c18n_info = (struct cheri_c18n_info * __kerncap)
cheri_setboundsexact(destp, sizeof(*imgp->c18n_info));
p->p_c18n_info =
(__cheri_fromcap struct cheri_c18n_info *)imgp->c18n_info;
#endif

if (imgp->auxargs) {
/*
* Allocate room on the stack for the ELF auxargs
Expand Down
66 changes: 66 additions & 0 deletions sys/kern/kern_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
#endif

#if __has_feature(capabilities)
#include <cheri/c18n.h>
#include <cheri/cheric.h>
#endif

Expand Down Expand Up @@ -2501,6 +2502,65 @@ sysctl_kern_proc_auxv(SYSCTL_HANDLER_ARGS)
return (error != 0 ? error : error2);
}

#if __has_feature(capabilities)
/*
* Return the c18n statistics block from the target process.
*/
static int
sysctl_kern_proc_c18n(SYSCTL_HANDLER_ARGS)
{
int *name = (int *)arg1;
u_int namelen = arg2;
struct proc *p;
struct cheri_c18n_info info;
int error;
void *buffer;
ssize_t n;

if (namelen != 1)
return (EINVAL);

error = pget((pid_t)name[0], PGET_WANTREAD, &p);
if (error != 0)
return (error);

if ((p->p_flag & P_SYSTEM) != 0 ||
SV_PROC_FLAG(p, SV_CHERI) == 0 ||
p->p_c18n_info == NULL)
goto out;

n = proc_readmem_cap(curthread, p, (vm_offset_t)p->p_c18n_info, &info,
sizeof(info));
/*
* If there is a version mismatch or the statistics block is oversized,
* error out.
*/
if (n != sizeof(info) ||
info.version != CHERI_C18N_INFO_VERSION ||
info.stats_size == 0 ||
info.stats_size > RTLD_C18N_STATS_MAX_SIZE ||
!__CAP_CHECK(info.stats, info.stats_size) ||
(cheri_getperm(info.stats) & CHERI_PERM_LOAD) == 0) {
error = ENOEXEC;
goto out;
}

buffer = malloc(info.stats_size, M_TEMP, M_WAITOK);
n = proc_readmem(curthread, p, (__cheri_addr vm_offset_t)info.stats,
buffer, info.stats_size);
if (n != info.stats_size) {
error = ENOMEM;
goto out_free;
}
error = SYSCTL_OUT(req, buffer, info.stats_size);
out_free:
free(buffer, M_TEMP);
out:
PRELE(p);
return (error);
}
#endif

/*
* Look up the canonical executable path running in the specified process.
* It tries to return the same hardlink name as was used for execve(2).
Expand Down Expand Up @@ -3681,6 +3741,12 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC_ENV, env, CTLFLAG_RD | CTLFLAG_MPSAFE,
static SYSCTL_NODE(_kern_proc, KERN_PROC_AUXV, auxv, CTLFLAG_RD |
CTLFLAG_MPSAFE, sysctl_kern_proc_auxv, "Process ELF auxiliary vector");

#if __has_feature(capabilities)
static SYSCTL_NODE(_kern_proc, KERN_PROC_C18N, c18n, CTLFLAG_RD |
CTLFLAG_MPSAFE, sysctl_kern_proc_c18n,
"Compartmentalisation statistics");
#endif

static SYSCTL_NODE(_kern_proc, KERN_PROC_PATHNAME, pathname, CTLFLAG_RD |
CTLFLAG_MPSAFE, sysctl_kern_proc_pathname, "Process executable path");

Expand Down
3 changes: 2 additions & 1 deletion sys/sys/elf_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -1011,8 +1011,9 @@ typedef struct {
#define AT_KPRELOAD 34 /* Base of vdso, preloaded by rtld */
#define AT_USRSTACKBASE 35 /* Top of user stack */
#define AT_USRSTACKLIM 36 /* Grow limit of user stack */
#define AT_CHERI_C18N 37 /* Compartment info block */

#define AT_COUNT 37 /* Count of defined aux entry types. */
#define AT_COUNT 38 /* Count of defined aux entry types. */

/*
* Relocation types.
Expand Down
1 change: 1 addition & 0 deletions sys/sys/imgact.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct image_params {
int canarylen;
void * __capability pagesizes;
int pagesizeslen;
struct cheri_c18n_info * __kerncap c18n_info;
void * __capability stack;
vm_prot_t stack_prot;
u_long stack_sz;
Expand Down
3 changes: 3 additions & 0 deletions sys/sys/proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,9 @@ struct proc {
non ELF binaries. */
sbintime_t p_umtx_min_timeout;
vm_offset_t p_psstrings;
#if __has_feature(capabilities)
struct cheri_c18n_info *p_c18n_info; /* (x) Compartment info block */
#endif
/* End area that is copied on creation. */
#define p_endcopy p_xexit

Expand Down
1 change: 1 addition & 0 deletions sys/sys/sysctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,7 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry);
#define KERN_PROC_QUARANTINING 46 /* is this process quarantining? */
#define KERN_PROC_REVOKER_STATE 47 /* revoker state */
#define KERN_PROC_REVOKER_EPOCH 48 /* revoker epoch */
#define KERN_PROC_C18N 49 /* compartmentalisation statistics */

/*
* KERN_IPC identifiers
Expand Down
1 change: 1 addition & 0 deletions usr.bin/procstat/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ SRCS= procstat.c \
procstat_auxv.c \
procstat_basic.c \
procstat_bin.c \
procstat_c18n.c \
procstat_cheri.c \
procstat_cred.c \
procstat_cs.c \
Expand Down
30 changes: 30 additions & 0 deletions usr.bin/procstat/procstat.1
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ Substring commands are accepted.
Display command line arguments for the process.
.Pp
Substring commands are accepted.
.It Ar c18n
Display CHERI compartmentalization information about a process.
.It Ar cheri
Display CHERI-specific information about the process.
If the
Expand Down Expand Up @@ -297,6 +299,29 @@ command
.It ARGS
command line arguments (if available)
.El
.Ss Compartmentalization information
Display CHERI compartmentalization information for a process (see
.Xr c18n 7 ) :
.Pp
.Bl -tag -width TRMPTBL -compact
.It PID
process ID
.It COMM
command
.It COMP
number of compartments
.It STKS
number of compartment stacks
.It TRMPS
number of initialized trampolines
.It TRPGS
number of pages mapped for trampolines
.It MEM
total size of
.Xr c18n 7
data structures (including stack lookup tables, trampoline lookup tables, etc.,
but excluding execution stacks and trampolines which have dedicated counters)
.El
.Ss CHERI information
Display the process ID, command, and CHERI-specific information:
.Pp
Expand All @@ -313,6 +338,10 @@ quarantining status
in-kernel revoker state
.It EPOCH
in-kernel revoker epoch
.It C18N
number of
.Xr c18n 7
compartments
.El
.Pp
The following values indicate the support for CHERI in the process ABI:
Expand Down Expand Up @@ -915,6 +944,7 @@ procstat: procstat_getprocs()
.Xr sctp 4 ,
.Xr tcp 4 ,
.Xr udp 4 ,
.Xr c18n 7 ,
.Xr stack 9
.Sh AUTHORS
.An Robert N M Watson Aq Mt [email protected] .
Expand Down
2 changes: 2 additions & 0 deletions usr.bin/procstat/procstat.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ static const struct procstat_cmd cmd_table[] = {
PS_CMP_NORMAL },
{ "binary", "binary", NULL, &procstat_bin, &cmdopt_none,
PS_CMP_SUBSTR },
{ "c18n", "c18n", NULL, &procstat_c18n, &cmdopt_none,
PS_CMP_NORMAL },
{ "cheri", "cheri", "[-v]", &procstat_cheri, &cmdopt_verbose,
PS_CMP_NORMAL },
{ "cpuset", "cs", NULL, &procstat_cs, &cmdopt_cpuset, PS_CMP_NORMAL },
Expand Down
1 change: 1 addition & 0 deletions usr.bin/procstat/procstat.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ void procstat_args(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_auxv(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_basic(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_bin(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_c18n(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_cheri(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_cred(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_cs(struct procstat *prstat, struct kinfo_proc *kipp);
Expand Down
Loading

0 comments on commit b7e170a

Please sign in to comment.