From 7eea9afe64de9c73da27372aeb2ce049392016cf Mon Sep 17 00:00:00 2001 From: "Robert N. M. Watson" Date: Thu, 19 Dec 2024 02:06:10 +0000 Subject: [PATCH] First cut at a "procstat compartments" command, to list c18n compartments. --- lib/libprocstat/Symbol.map | 1 + lib/libprocstat/libprocstat.3 | 50 +++++++- lib/libprocstat/libprocstat.c | 54 ++++++++ lib/libprocstat/libprocstat.h | 3 + libexec/rtld-elf/rtld_c18n.c | 23 +++- libexec/rtld-elf/rtld_c18n.h | 1 + sys/cheri/c18n.h | 31 ++++- sys/kern/kern_proc.c | 157 ++++++++++++++++++++++- sys/sys/sysctl.h | 1 + usr.bin/procstat/Makefile | 1 + usr.bin/procstat/procstat.1 | 19 +++ usr.bin/procstat/procstat.c | 2 + usr.bin/procstat/procstat.h | 2 + usr.bin/procstat/procstat_compartments.c | 77 +++++++++++ 14 files changed, 409 insertions(+), 13 deletions(-) create mode 100644 usr.bin/procstat/procstat_compartments.c diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 569884fd6240..51f61026e94b 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -51,4 +51,5 @@ FBSD_1.7 { procstat_get_revoker_epoch; procstat_get_revoker_state; procstat_getc18n; + procstat_getcompartments; }; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 2617a8827a6d..68ad085d1338 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -1,6 +1,12 @@ +.\" Copyright (c) 2024 Capabilities Limited .\" Copyright (c) 2011 Sergey Kandaurov .\" All rights reserved. .\" +.\" This software was developed by SRI International, the University of +.\" Cambridge Computer Laboratory (Department of Computer Science and +.\" Technology), and Capabilities Limited under Defense Advanced Research +.\" Projects Agency (DARPA) Contract No. FA8750-24-C-B047 ("DEC"). +.\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: @@ -22,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 3, 2022 +.Dd December 5, 2024 .Dt LIBPROCSTAT 3 .Os .Sh NAME @@ -47,6 +53,8 @@ .Nm procstat_getargv , .Nm procstat_getauxv , .Nm procstat_getenvv , +.Nm procstat_getc18n , +.Nm procstat_getcompartments , .Nm procstat_getfiles , .Nm procstat_getgroups , .Nm procstat_getkstack , @@ -67,6 +75,7 @@ .In sys/param.h .In sys/queue.h .In sys/socket.h +.In cheri/c18n.h .In libprocstat.h .Ft void .Fn procstat_close "struct procstat *procstat" @@ -170,6 +179,19 @@ .Fa "struct kinfo_proc *kp" .Fa "unsigned int *count" .Fc +.Ft "int" +.Fo procstat_getc18n +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "struct rtld_c18n_stats *stats" +.Fc +.Ft "int" +.Fo procstat_getcompartments +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "struct cheri_c18n_compart *comparts" +.Fa "u_int *ncompartsp" +.Fc .Ft "char **" .Fo procstat_getenvv .Fa "struct procstat *procstat" @@ -570,6 +592,28 @@ argument indicates an actual error message in case of failure. .It Li PS_FST_TYPE_SHM .Nm procstat_get_shm_info .El +.Pp +The +.Fn procstat_getc18n +function retrieves +compartmentalization (\c +.Xr c18n ) +statistics for a target process, including its number of intra-process +compartments, instantiated trampolines, and other values. +The +.Fn procstat_getcompartments +function retrieves a compartment list for target process. +The +.Fa comparts +argument is a pointer to a caller-allocated array of +.Ft struct cheri_c18n_compart +entries of size +.Fa *ncompartsp +passed by reference. +On return, the compartment list is terminated with a compartment ID of +.Dv CHERI_C18N_COMPART_LAST . +If a terminating entry is not found in the returned array, then there was +insufficient space, and the caller should allocate a larger array and retry. .Sh SEE ALSO .Xr fstat 1 , .Xr fuser 1 , @@ -583,6 +627,7 @@ argument indicates an actual error message in case of failure. .Xr sysctl 3 , .Xr pts 4 , .Xr core 5 , +.Xr c18n 7 , .Xr vnode 9 .Sh HISTORY The @@ -595,6 +640,9 @@ The .Nm libprocstat library was written by .An Stanislav Sedov Aq Mt stas@FreeBSD.org . +.Xr c18n 3 -related +monitoring APIs were added by +.An Robert N. M. Watson Aq Mt rwatson@FreeBSD.org . .Pp This manual page was written by .An Sergey Kandaurov Aq Mt pluknet@FreeBSD.org . diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 94b163430a90..2856d747f3d2 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -1,11 +1,17 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * + * Copyright (c) 2024 Capabilities Limited * Copyright (c) 2017 Dell EMC * Copyright (c) 2009 Stanislav Sedov * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * + * This software was developed by SRI International, the University of + * Cambridge Computer Laboratory (Department of Computer Science and + * Technology), and Capabilities Limited under Defense Advanced Research + * Projects Agency (DARPA) Contract No. FA8750-24-C-B047 ("DEC"). + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -399,6 +405,54 @@ procstat_getc18n(struct procstat *procstat, struct kinfo_proc *kp, return (-1); } +/* Caller-allocated compartment list buffer. */ +int +procstat_getcompartments(struct procstat *procstat, struct kinfo_proc *kp, + struct cheri_c18n_compart *comparts, u_int *ncompartsp) +{ + int name[4]; + size_t size; + + if (comparts == NULL || ncompartsp == 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_COMPARTS; + name[3] = kp->ki_pid; + size = *ncompartsp * sizeof(*comparts); + if (sysctl(name, nitems(name), comparts, &size, NULL, 0) != 0) { + if (errno != ESRCH && errno != EPERM && errno != ENOEXEC) + warn("sysctl(kern.proc.c18n_compartments)"); + goto out; + } + if (size % sizeof(*comparts) != 0) + goto out; + *ncompartsp = size / sizeof(*comparts); + return (0); + +out: + *ncompartsp = 0; + return (-1); +} + struct filestat_list * procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) { diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index bb43ef88496d..60d771d5097e 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -217,6 +217,9 @@ void procstat_freevmmap(struct procstat *procstat, struct advlock_list *procstat_getadvlock(struct procstat *procstat); int procstat_getc18n(struct procstat *procstat, struct kinfo_proc *kp, struct rtld_c18n_stats *stats); +int procstat_getcompartments(struct procstat *procstat, + struct kinfo_proc *kp, struct cheri_c18n_compart *comparts, + u_int *ncomparts); struct filestat_list *procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped); struct kinfo_proc *procstat_getprocs(struct procstat *procstat, diff --git a/libexec/rtld-elf/rtld_c18n.c b/libexec/rtld-elf/rtld_c18n.c index 5913178ebddf..08f37e60e711 100644 --- a/libexec/rtld-elf/rtld_c18n.c +++ b/libexec/rtld-elf/rtld_c18n.c @@ -149,6 +149,7 @@ const char *ld_compartment_stats; const char *ld_compartment_switch_count; struct rtld_c18n_stats *c18n_stats; +struct cheri_c18n_info *c18n_info; /* From ELF auxiliary arguments. */ #define INC_NUM_COMPART (c18n_stats->rcs_compart++, comparts.size++) #define INC_NUM_BYTES(n) \ @@ -242,7 +243,8 @@ string_base_search(const struct string_base *sb, const char *str) struct compart { /* - * Name of the compartment + * Name of the compartment. Must be the first field to enable kernel + * access to compartment information. */ const char *name; /* @@ -296,9 +298,16 @@ expand_comparts_data(compart_id_t capacity) { struct compart *data; + /* + * XXXRW: There's an annoying race to close here .. made harder to + * resolve by realloc(). We sort of want a "realloc and don't free + * if you copy, so you can free the old one later". + */ data = c18n_realloc(comparts.data, sizeof(*data) * capacity); comparts.data = r_debug.r_comparts = data; comparts.capacity = capacity; + c18n_info->comparts = comparts.data; + c18n_info->capacity = capacity; } static struct compart * @@ -1583,7 +1592,6 @@ c18n_init(Obj_Entry *obj_rtld, Elf_Auxinfo *aux_info[]) int fd; char *file; struct stat st; - struct cheri_c18n_info *info; /* * Create memory mapping for compartmentalisation statistics. @@ -1609,13 +1617,14 @@ c18n_init(Obj_Entry *obj_rtld, Elf_Auxinfo *aux_info[]) 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) { + c18n_info = aux_info[AT_CHERI_C18N]->a_un.a_ptr; + *c18n_info = (struct cheri_c18n_info) { .stats_size = sizeof(*c18n_stats), - .stats = c18n_stats + .stats = c18n_stats, + .compart_size = sizeof(struct compart), }; - atomic_store_explicit(&info->version, CHERI_C18N_INFO_VERSION, - memory_order_release); + atomic_store_explicit(&c18n_info->version, + CHERI_C18N_INFO_VERSION, memory_order_release); } /* diff --git a/libexec/rtld-elf/rtld_c18n.h b/libexec/rtld-elf/rtld_c18n.h index b7c2d34366c9..5968ab56c472 100644 --- a/libexec/rtld-elf/rtld_c18n.h +++ b/libexec/rtld-elf/rtld_c18n.h @@ -43,6 +43,7 @@ extern const char *ld_compartment_unwind; extern const char *ld_compartment_stats; extern const char *ld_compartment_switch_count; extern struct rtld_c18n_stats *c18n_stats; +extern struct cheri_c18n_info *c18n_info; /* * Policies diff --git a/sys/cheri/c18n.h b/sys/cheri/c18n.h index 69ae14c4c986..f6ea686268cc 100644 --- a/sys/cheri/c18n.h +++ b/sys/cheri/c18n.h @@ -2,6 +2,12 @@ * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2024 Dapeng Gao + * Copyright (c) 2024 Capabilities Limited + * + * This software was developed by SRI International, the University of + * Cambridge Computer Laboratory (Department of Computer Science and + * Technology), and Capabilities Limited under Defense Advanced Research + * Projects Agency (DARPA) Contract No. FA8750-24-C-B047 ("DEC"). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +41,7 @@ #define _Atomic(t) t #endif -#define RTLD_C18N_STATS_VERSION 1 +#define RTLD_C18N_STATS_VERSION 2 #define RTLD_C18N_STATS_MAX_SIZE 256 /* @@ -58,12 +64,33 @@ struct rtld_c18n_stats { * 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 +#define CHERI_C18N_INFO_VERSION 2 struct cheri_c18n_info { _Atomic(uint8_t) version; size_t stats_size; struct rtld_c18n_stats * __kerncap stats; + + /* + * Access to the compartment-list array. Currently, racy to the point + * of sadness. Ideally we might use a generation field so that races + * could be masked by the kernel. We don't do this yet. + */ + size_t compart_size; /* Size of compartment array entries. */ + size_t capacity; /* Number of compartment array entries. */ + void * __kerncap comparts; +}; + +/* + * The interface provided by the kernel via sysctl for compartmentalization + * monitoring tools such as procstat. + */ +#define CHERI_C18N_COMPART_MAXNAME 64 +#define CHERI_C18N_COMPART_LAST -1 +struct cheri_c18n_compart { + int ccc_id; + char ccc_name[CHERI_C18N_COMPART_MAXNAME]; + u_char _ccc_pad[60]; /* Shrink as new fields added above. */ }; #ifndef IN_RTLD diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index c22b547f366b..dca6d7bd24cb 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -2538,9 +2538,12 @@ sysctl_kern_proc_c18n(SYSCTL_HANDLER_ARGS) 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) { + info.stats_size > RTLD_C18N_STATS_MAX_SIZE) { + error = ENOEXEC; + goto out; + } + if (!cheri_can_access(info.stats, CHERI_PERM_LOAD, + cheri_getaddress(info.stats), info.stats_size)) { error = ENOEXEC; goto out; } @@ -2559,6 +2562,150 @@ sysctl_kern_proc_c18n(SYSCTL_HANDLER_ARGS) PRELE(p); return (error); } + +/* + * The implementation of proc_read_string() above does not stop at nul + * terminators, which we would like to do. Return -1 on failure (e.g., + * fault), and otherwise the number of bytes read and a properly terminated + * (albeit possible truncated) string via 'buf'. + */ +static int +proc_read_string_properly(struct thread *td, struct proc *p, + const char * __capability sptr, char *buf, size_t len) +{ + ssize_t readlen; + size_t n; + + KASSERT(len >= 1, ("%s: Buffer too short", __func__)); + if (len < 1) + return (-1); + for (n = 0; n < len - 1; n++) { + if (!cheri_can_access(sptr + n, CHERI_PERM_LOAD, + cheri_getaddress(sptr), 1)) + return (-1); + readlen = proc_readmem(td, p, + (__cheri_addr vm_offset_t)(sptr + n), buf + n, 1); + if (readlen < 0 || readlen != 1) + return (-1); + if (buf[n] == '\0') + break; + } + /* Unconditionally enforce termination. */ + buf[n] = '\0'; + return (n + 1); +} + +/* + * If usefully accessible, return a c18n compartment list from the target + * process. This involves an unhealthy degree of spelunking, and we give up + * early rather than push to the point of insanity. Buyer beware. + */ +static int +sysctl_kern_proc_c18n_compartments(SYSCTL_HANDLER_ARGS) +{ + struct cheri_c18n_compart c18n_compart; /* ... quite big... */ + struct cheri_c18n_info c18n_info; + struct proc *p; + char * __capability compartmentnamep; + uintcap_t compartmentnamepp; + size_t len; + int error, n, *name = (int *)arg1; + u_int namelen = arg2; + + 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; + + /* + * First, retrieve the statistics block, which includes a pointer to + * the current location of the compartment array, the length of the + * array, and the length of each array field. + */ + len = proc_readmem_cap(curthread, p, (vm_offset_t)p->p_c18n_info, + &c18n_info, sizeof(c18n_info)); + + /* + * If there is a version mismatch or the statistics block is oversized, + * error out. + */ + if (len != sizeof(c18n_info) || + c18n_info.version != CHERI_C18N_INFO_VERSION || + c18n_info.stats_size == 0 || + c18n_info.stats_size > RTLD_C18N_STATS_MAX_SIZE) { + error = ENOEXEC; + goto out; + } + if (!cheri_can_access(c18n_info.stats, + CHERI_PERM_LOAD | CHERI_PERM_LOAD_CAP, + cheri_getaddress(c18n_info.stats), c18n_info.stats_size)) { + error = ENOEXEC; + goto out; + } + + /* + * One by one, copy compartment names out of the target process's + * memory, and into a template struct that we copy out to userspace. + */ + for (n = 0; n < c18n_info.capacity; n++) { + /* Initialize userspace structure, including padding. */ + bzero(&c18n_compart, sizeof(c18n_compart)); + c18n_compart.ccc_id = n; + + compartmentnamepp = (uintcap_t)c18n_info.comparts; + compartmentnamepp += n * c18n_info.compart_size; + + if (!cheri_can_access((void * __capability)compartmentnamepp, + CHERI_PERM_LOAD | CHERI_PERM_LOAD_CAP, + cheri_getaddress(compartmentnamepp), + sizeof(compartmentnamep))) { + error = ENOEXEC; + goto out; + } + + /* Copy in next compartment-name string pointer. */ + len = proc_readmem_cap(curthread, p, + (vm_offset_t)compartmentnamepp, &compartmentnamep, + sizeof(compartmentnamep)); + /* ((vm_offset_t) c18n_info.comparts) + n * */ + if (len != sizeof(compartmentnamep)) { /* Implicitly also -1 */ + error = EFAULT; + goto out; + } + if (compartmentnamep == NULL) + break; /* Could make this continue? */ + + /* + * Copy in compartment name string. Capability access checks + * are performed by proc_read_string_properly(). + */ + len = proc_read_string_properly(curthread, p, + compartmentnamep, c18n_compart.ccc_name, + sizeof(c18n_compart.ccc_name)); + if (len == -1) { + error = EFAULT; + goto out; + } + + /* Copy out userspace structure. */ + error = SYSCTL_OUT(req, &c18n_compart, sizeof(c18n_compart)); + if (error != 0) + goto out; + } + + /* Copy out a last structure with ID terminating list. */ + bzero(&c18n_compart, sizeof(c18n_compart)); + c18n_compart.ccc_id = CHERI_C18N_COMPART_LAST; + error = SYSCTL_OUT(req, &c18n_compart, sizeof(c18n_compart)); +out: + PRELE(p); + return (error); +} #endif /* @@ -3745,6 +3892,10 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC_AUXV, auxv, CTLFLAG_RD | static SYSCTL_NODE(_kern_proc, KERN_PROC_C18N, c18n, CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc_c18n, "Compartmentalisation statistics"); + +static SYSCTL_NODE(_kern_proc, KERN_PROC_C18N_COMPARTS, c18n_compartments, + CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc_c18n_compartments, + "Compartment list"); #endif static SYSCTL_NODE(_kern_proc, KERN_PROC_PATHNAME, pathname, CTLFLAG_RD | diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index 5abf6dcc958c..7b161b877f72 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -1065,6 +1065,7 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry); #define KERN_PROC_REVOKER_STATE 47 /* revoker state */ #define KERN_PROC_REVOKER_EPOCH 48 /* revoker epoch */ #define KERN_PROC_C18N 49 /* compartmentalisation statistics */ +#define KERN_PROC_C18N_COMPARTS 50 /* compartment list */ /* * KERN_IPC identifiers diff --git a/usr.bin/procstat/Makefile b/usr.bin/procstat/Makefile index 6df0cba7d897..24556b8daf68 100644 --- a/usr.bin/procstat/Makefile +++ b/usr.bin/procstat/Makefile @@ -11,6 +11,7 @@ SRCS= procstat.c \ procstat_bin.c \ procstat_c18n.c \ procstat_cheri.c \ + procstat_compartments.c \ procstat_cred.c \ procstat_cs.c \ procstat_files.c \ diff --git a/usr.bin/procstat/procstat.1 b/usr.bin/procstat/procstat.1 index fc938dde6084..511ecc151876 100644 --- a/usr.bin/procstat/procstat.1 +++ b/usr.bin/procstat/procstat.1 @@ -176,6 +176,10 @@ Display CHERI-specific information about the process. If the .Fl v flag is passed then extra information is shown. +.It Ar compartments +Display information on +.Xr c18n 7 +compartments within the process. .It Ar environment | Fl e Display environment variables for the process. .Pp @@ -380,6 +384,21 @@ revoker initialized, epoch open .It closing revoker finishing an epoch .El +.Ss Compartment List +Display the list of +.Xr c18n 7 +compartments within a process: +.Pp +.Bl -tag -width CNAME -compact +.It PID +process ID +.It COMM +command +.It CID +compartment ID +.It CNAME +compartment name +.El .Ss Environment Variables Display the process ID, command, and environment variables: .Pp diff --git a/usr.bin/procstat/procstat.c b/usr.bin/procstat/procstat.c index c855e4407d03..54c29a3fce46 100644 --- a/usr.bin/procstat/procstat.c +++ b/usr.bin/procstat/procstat.c @@ -97,6 +97,8 @@ static const struct procstat_cmd cmd_table[] = { PS_CMP_NORMAL }, { "cheri", "cheri", "[-v]", &procstat_cheri, &cmdopt_verbose, PS_CMP_NORMAL }, + { "compartments", "compartments", NULL, &procstat_compartments, + cmdopt_none, PS_CMP_NORMAL }, { "cpuset", "cs", NULL, &procstat_cs, &cmdopt_cpuset, PS_CMP_NORMAL }, { "cs", "cs", NULL, &procstat_cs, &cmdopt_cpuset, PS_CMP_NORMAL }, { "credential", "credentials", NULL, &procstat_cred, &cmdopt_none, diff --git a/usr.bin/procstat/procstat.h b/usr.bin/procstat/procstat.h index 36738e24f7d2..aaf08e0549c1 100644 --- a/usr.bin/procstat/procstat.h +++ b/usr.bin/procstat/procstat.h @@ -62,6 +62,8 @@ 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_compartments(struct procstat *procstat, + struct kinfo_proc *kipp); void procstat_cred(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_cs(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_env(struct procstat *prstat, struct kinfo_proc *kipp); diff --git a/usr.bin/procstat/procstat_compartments.c b/usr.bin/procstat/procstat_compartments.c new file mode 100644 index 000000000000..0502144b33b7 --- /dev/null +++ b/usr.bin/procstat/procstat_compartments.c @@ -0,0 +1,77 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Capabilities Limited + * + * This software was developed by SRI International, the University of + * Cambridge Computer Laboratory (Department of Computer Science and + * Technology), and Capabilities Limited under Defense Advanced Research + * Projects Agency (DARPA) Contract No. FA8750-24-C-B047 ("DEC"). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +#include +#include + +#include "procstat.h" + +#define C18N_MAX_COMPARTS 1024 /* Horrible but functional, for now. */ +void +procstat_compartments(struct procstat *procstat __unused, + struct kinfo_proc *kipp) +{ + struct cheri_c18n_compart *cccp, *ccc_incp; + u_int i, ncomparts; + + ncomparts = C18N_MAX_COMPARTS; + cccp = malloc(ncomparts * sizeof(*cccp)); + if (cccp == NULL) { + warn("malloc"); + return; + } + if ((procstat_opts & PS_OPT_NOHEADER) == 0) + xo_emit("{T:/%5s %-19s %4s %-32s}\n", "PID", "COMM", "CID", + "CNAME"); + if (procstat_getcompartments(procstat, kipp, cccp, &ncomparts) != 0) { + if (errno != EPERM) + warn("procstat_getcomparts"); + goto out; + } + ccc_incp = cccp; + for (i = 0; i < ncomparts; i++, ccc_incp++) { + if (ccc_incp->ccc_id == CHERI_C18N_COMPART_LAST) + break; + xo_emit("{k:process_id/%5d/%d}", kipp->ki_pid); + xo_emit(" {:command/%-19s/%s}", kipp->ki_comm); + xo_emit(" {:cid/%4d/%d}", ccc_incp->ccc_id); + xo_emit(" {:cname/%-32s/%s}", ccc_incp->ccc_name); + xo_emit("\n"); + } +out: + free(cccp); +}