From 97df9be7de0806cd9b763f7c5b75e8b34f37e09a Mon Sep 17 00:00:00 2001 From: Dapeng Gao Date: Fri, 26 Apr 2024 17:59:18 +0100 Subject: [PATCH] c18n: Option to export compartment switch counts --- libexec/rtld-elf/aarch64/rtld_c18n_asm.S | 11 +++++++ libexec/rtld-elf/aarch64/rtld_c18n_machdep.c | 33 ++++++++++++++++---- libexec/rtld-elf/rtld.c | 3 ++ libexec/rtld-elf/rtld_c18n.c | 3 ++ libexec/rtld-elf/rtld_c18n.h | 1 + sys/cheri/c18n.h | 1 + usr.bin/procstat/procstat.1 | 2 ++ usr.bin/procstat/procstat_c18n.c | 8 +++-- 8 files changed, 54 insertions(+), 8 deletions(-) diff --git a/libexec/rtld-elf/aarch64/rtld_c18n_asm.S b/libexec/rtld-elf/aarch64/rtld_c18n_asm.S index 19753a55f127..22e5d8c2884d 100644 --- a/libexec/rtld-elf/aarch64/rtld_c18n_asm.S +++ b/libexec/rtld-elf/aarch64/rtld_c18n_asm.S @@ -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] +TRAMPEND(tramp_count_entry) + +PATCH_POINT(tramp_count_entry, counter, 1b) + TRAMP(tramp_call_hook) 1: ldr c12, #0 /* To be patched at runtime */ @@ -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 diff --git a/libexec/rtld-elf/aarch64/rtld_c18n_machdep.c b/libexec/rtld-elf/aarch64/rtld_c18n_machdep.c index a27d69cd018f..729b1b5facb8 100644 --- a/libexec/rtld-elf/aarch64/rtld_c18n_machdep.c +++ b/libexec/rtld-elf/aarch64/rtld_c18n_machdep.c @@ -30,6 +30,8 @@ #include #include +#include + #include #include "debug.h" @@ -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, \ @@ -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, @@ -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); @@ -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); diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 587821d66f0c..8590ea58ffbb 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -405,6 +405,7 @@ enum { LD_COMPARTMENT_SIG, LD_COMPARTMENT_UNWIND, LD_COMPARTMENT_STATS, + LD_COMPARTMENT_SWITCH_COUNT, #endif }; @@ -454,6 +455,7 @@ static struct ld_env_var_desc ld_env_vars[] = { 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 }; @@ -859,6 +861,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) 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. */ diff --git a/libexec/rtld-elf/rtld_c18n.c b/libexec/rtld-elf/rtld_c18n.c index 84bed26b1fa5..3f69634170bf 100644 --- a/libexec/rtld-elf/rtld_c18n.c +++ b/libexec/rtld-elf/rtld_c18n.c @@ -146,6 +146,9 @@ const char *ld_compartment_unwind; /* Export compartmentalisation statistics to a file */ const char *ld_compartment_stats; +/* Export count of compartment switches to statistics */ +const char *ld_compartment_switch_count; + struct rtld_c18n_stats *c18n_stats; #define INC_NUM_COMPART (c18n_stats->rcs_compart++, comparts.size++) diff --git a/libexec/rtld-elf/rtld_c18n.h b/libexec/rtld-elf/rtld_c18n.h index ae3ad0870139..7557919a5efd 100644 --- a/libexec/rtld-elf/rtld_c18n.h +++ b/libexec/rtld-elf/rtld_c18n.h @@ -41,6 +41,7 @@ extern const char *ld_compartment_overhead; extern const char *ld_compartment_sig; 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; /* diff --git a/sys/cheri/c18n.h b/sys/cheri/c18n.h index 47264cd33b2f..69ae14c4c986 100644 --- a/sys/cheri/c18n.h +++ b/sys/cheri/c18n.h @@ -50,6 +50,7 @@ struct rtld_c18n_stats { _Atomic(size_t) rcs_tramp; _Atomic(size_t) rcs_tramp_page; _Atomic(size_t) rcs_bytes_total; + _Atomic(size_t) rcs_switch; }; /* diff --git a/usr.bin/procstat/procstat.1 b/usr.bin/procstat/procstat.1 index ba6ac87f9f5f..fc938dde6084 100644 --- a/usr.bin/procstat/procstat.1 +++ b/usr.bin/procstat/procstat.1 @@ -321,6 +321,8 @@ 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) +.It SWTCH +number of compartment switches performed so far .El .Ss CHERI information Display the process ID, command, and CHERI-specific information: diff --git a/usr.bin/procstat/procstat_c18n.c b/usr.bin/procstat/procstat_c18n.c index 890c9b7d38ad..bdf2e9a3a840 100644 --- a/usr.bin/procstat/procstat_c18n.c +++ b/usr.bin/procstat/procstat_c18n.c @@ -46,8 +46,9 @@ procstat_c18n(struct procstat *procstat, struct kinfo_proc *kipp) struct rtld_c18n_stats rcs; if ((procstat_opts & PS_OPT_NOHEADER) == 0) - xo_emit("{T:/%5s %-19s %5s %5s %6s %5s %5s}\n", - "PID", "COMM", "COMP", "STKS", "TRMPS", "TRPGS", "MEM"); + xo_emit("{T:/%5s %-19s %5s %5s %6s %5s %5s %5s}\n", + "PID", "COMM", "COMP", "STKS", "TRMPS", "TRPGS", "MEM", + "SWTCH"); xo_emit("{k:process_id/%5d/%d}", kipp->ki_pid); xo_emit(" {:command/%-19s/%s}", kipp->ki_comm); @@ -58,6 +59,7 @@ procstat_c18n(struct procstat *procstat, struct kinfo_proc *kipp) xo_emit(" {:trampolines/%6s/%s}", "-"); xo_emit(" {:tramppages/%5s/%s}", "-"); xo_emit(" {:memory/%5s/%s}", "-"); + xo_emit(" {:switches/%5s/%s}", "-"); } else { xo_emit(" {:compartments/%5zu/%zu}", rcs.rcs_compart); xo_emit(" {:stacks/%5zu/%zu}", rcs.rcs_ustack); @@ -65,6 +67,8 @@ procstat_c18n(struct procstat *procstat, struct kinfo_proc *kipp) xo_emit(" {:tramppages/%5zu/%zu}", rcs.rcs_tramp_page); xo_emit(" {[:5}{h,hn-decimal:memory/%zu/%zu}{]:}", rcs.rcs_bytes_total); + xo_emit(" {[:5}{h,hn-decimal,hn-1000:switches/%zu/%zu}{]:}", + rcs.rcs_switch); } xo_emit("\n"); }