Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

c18n: Export c18n statistics to procstat(1) and file (supersedes #2084) #2079

Merged
merged 4 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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];
brooksdavis marked this conversation as resolved.
Show resolved Hide resolved
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
11 changes: 11 additions & 0 deletions libexec/rtld-elf/aarch64/rtld_c18n_asm.S
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,13 @@ TRAMP(tramp_update_fp_untagged)
clrtag c29, TRUSTED_STACK_C
TRAMPEND(tramp_update_fp_untagged)

TRAMP(tramp_count_entry)
1: ldr c24, #0 /* To be patched at runtime */
stadd w25, [c24]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this w25 come from?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the gctag x25, c30 above and we can assume that it is always 1. This is done to save instructions and assumes that the program is well-behaved.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Firstly, these things have to be commented. There are so many of these implicit dependencies floating around within and across trampoline fragments that it's really hard to keep track of them all, and it's just asking for someone to break this in future by using a different register for the GCTAG (which would be reasonable, because who would expect it to be used many instructions later?). Secondly, having an untagged return capability seems a totally valid thing to do if you're making a call to a function that won't return. I don't think you can currently easily end up with it from a compiler, but I see no reason why it wouldn't be valid.

TRAMPEND(tramp_count_entry)

PATCH_POINT(tramp_count_entry, counter, 1b)

TRAMP(tramp_call_hook)
1: ldr c12, #0 /* To be patched at runtime */

Expand Down Expand Up @@ -453,6 +460,10 @@ TRAMP(tramp_invoke_res)
#endif
TRAMPEND(tramp_invoke_res)

TRAMP(tramp_count_return)
stadd w25, [c24]
TRAMPEND(tramp_count_return)

TRAMP(tramp_pop_frame)
mrs TRUSTED_STACK_C, TRUSTED_STACK

Expand Down
33 changes: 27 additions & 6 deletions libexec/rtld-elf/aarch64/rtld_c18n_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include <sys/param.h>
#include <sys/mman.h>

#include <cheri/c18n.h>

#include <stdlib.h>

#include "debug.h"
Expand All @@ -51,21 +53,32 @@ tramp_compile(char **entry, const struct tramp_data *data)
IMPORT(push_frame);
IMPORT(update_fp);
IMPORT(update_fp_untagged);
IMPORT(count_entry);
IMPORT(call_hook);
IMPORT(invoke_exe);
IMPORT(clear_mem_args);
IMPORT(clear_ret_args_indirect);
IMPORT(clear_ret_args);
IMPORT(invoke_res);
IMPORT(count_return);
IMPORT(pop_frame);

size_t size = 0;
char *buf = *entry;
size_t hook_off, header_off, target_off, landing_off, unused_regs;
size_t hook_off, count_off;
size_t header_off, target_off, landing_off, unused_regs;
bool executive = cheri_getperm(data->target) & CHERI_PERM_EXECUTIVE;
bool count = ld_compartment_switch_count != NULL;
bool hook = ld_compartment_utrace != NULL ||
ld_compartment_overhead != NULL;

#define COPY_VALUE(val) ({ \
size_t _old_size = size; \
*(typeof(val) *)(buf + size) = val; \
size += sizeof(val); \
_old_size; \
})

#define COPY(template) \
do { \
memcpy(buf + size, tramp_##template, \
Expand Down Expand Up @@ -113,11 +126,11 @@ tramp_compile(char **entry, const struct tramp_data *data)
*PATCH_INS(_offset) |= _value; \
} while (0)

if (hook) {
*(void **)(buf + size) = tramp_hook;
hook_off = size;
size += sizeof(void *);
}
if (hook)
hook_off = COPY_VALUE(&tramp_hook);

if (count)
count_off = COPY_VALUE(&c18n_stats->rcs_switch);

*(struct tramp_header *)(buf + size) = (struct tramp_header) {
.target = data->target,
Expand All @@ -143,6 +156,11 @@ tramp_compile(char **entry, const struct tramp_data *data)
else
COPY(update_fp_untagged);

if (count) {
COPY(count_entry);
PATCH_LDR_IMM(count_entry, counter, count_off);
}

if (hook) {
COPY(call_hook);
PATCH_LDR_IMM(call_hook, function, hook_off);
Expand Down Expand Up @@ -174,6 +192,9 @@ tramp_compile(char **entry, const struct tramp_data *data)
*/
PATCH_ADR(landing_off, size + 1);

if (count)
COPY(count_return);

if (hook) {
COPY(call_hook);
PATCH_LDR_IMM(call_hook, function, hook_off);
Expand Down
2 changes: 1 addition & 1 deletion libexec/rtld-elf/rtld-libc/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ _libc_other_objects=sigsetjmp lstat stat fstat fstatat fstatfs syscall \
_sigprocmask _write readlink __realpathat _setjmp setjmp setjmperr

.ifdef RTLD_SANDBOX
_libc_other_objects+=thr_exit _sigaction
_libc_other_objects+=thr_exit _sigaction ftruncate
.endif

# Finally add additional architecture-dependent libc dependencies
Expand Down
8 changes: 7 additions & 1 deletion libexec/rtld-elf/rtld.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ enum {
LD_COMPARTMENT_OVERHEAD,
LD_COMPARTMENT_SIG,
LD_COMPARTMENT_UNWIND,
LD_COMPARTMENT_STATS,
LD_COMPARTMENT_SWITCH_COUNT,
#endif
};

Expand Down Expand Up @@ -452,6 +454,8 @@ static struct ld_env_var_desc ld_env_vars[] = {
LD_ENV_DESC(COMPARTMENT_OVERHEAD, false),
LD_ENV_DESC(COMPARTMENT_SIG, false),
LD_ENV_DESC(COMPARTMENT_UNWIND, false),
LD_ENV_DESC(COMPARTMENT_STATS, false),
LD_ENV_DESC(COMPARTMENT_SWITCH_COUNT, false),
#endif
};

Expand Down Expand Up @@ -856,6 +860,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
ld_compartment_overhead = ld_get_env_var(LD_COMPARTMENT_OVERHEAD);
ld_compartment_sig = ld_get_env_var(LD_COMPARTMENT_SIG);
ld_compartment_unwind = ld_get_env_var(LD_COMPARTMENT_UNWIND);
ld_compartment_stats = ld_get_env_var(LD_COMPARTMENT_STATS);
ld_compartment_switch_count = ld_get_env_var(LD_COMPARTMENT_SWITCH_COUNT);
/*
* DISABLE takes precedence over ENABLE.
*/
Expand Down Expand Up @@ -984,7 +990,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
Loading
Loading