From ed756c1b18744b5f6fdd30359e12bdb12f784440 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Sat, 30 Dec 2023 15:34:20 +0900 Subject: [PATCH] agent: Support composite events CRYPTO_AUDITING_*_DATA defines a single USDT probe point for each invocation. This causes multiple context switches to happen if they are writen in series. This adds a new macro, CRYPTO_AUDITING_DATA and CRYPTO_AUDITING_DATAV, which take an array of events to limit the number of context switches. Signed-off-by: Daiki Ueno --- agent/src/bpf/audit.bpf.c | 131 ++++++++++++++++++++++++++++++++++++++ agent/src/main.rs | 18 ++++++ dist/audit.h | 48 ++++++++++++++ 3 files changed, 197 insertions(+) diff --git a/agent/src/bpf/audit.bpf.c b/agent/src/bpf/audit.bpf.c index a6b12b9..5e63cde 100644 --- a/agent/src/bpf/audit.bpf.c +++ b/agent/src/bpf/audit.bpf.c @@ -10,6 +10,12 @@ bpf_trace_printk ("%s: " format, sizeof("%s: " format), \ __PRETTY_FUNCTION__, __VA_ARGS__) +struct crypto_auditing_data { + char *key_ptr; + void *value_ptr; + long value_size; +}; + struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 4096 /* one page */); @@ -226,6 +232,114 @@ record_blob_data (struct pt_regs *ctx, long context, const char *key_ptr) return err; } +/* This is similar to record_blob_data but always assumes VALUE_PTR is + * present. + */ +static __always_inline int +record_blob_data_explicit (struct pt_regs *ctx, long context, const char *key_ptr, + const void *value_ptr, long value_size) +{ + int err; + + struct audit_blob_data_event_st *event = + bpf_ringbuf_reserve (&ringbuf, + sizeof(struct audit_blob_data_event_st), + 0); + if (!event) + { + DEBUG ("unable to allocate ringbuf entry: %ld\n", -ENOMEM); + return -ENOMEM; + } + + populate_event_header (&event->base.header, + AUDIT_EVENT_DATA, + sizeof(*event), + context); + + event->base.type = AUDIT_DATA_BLOB; + err = bpf_probe_read_user_str (event->base.key, KEY_SIZE, (void *)key_ptr); + if (err < 0) + { + DEBUG ("unable to read event key: %ld\n", err); + goto error; + } + + if (value_size > 0) + { + value_size &= (VALUE_SIZE - 1); + err = bpf_probe_read_user (event->value, value_size, (void *)value_ptr); + if (err < 0) + { + DEBUG ("unable to read event data: %ld\n", err); + goto error; + } + } + + event->size = value_size; + + bpf_ringbuf_submit (event, 0); + return 0; + + error: + bpf_ringbuf_discard (event, 0); + return err; +} + +static __always_inline int +record_data (struct pt_regs *ctx, long context, + struct crypto_auditing_data *array_ptr, + long array_size) +{ + int err = 0; + + for (long i = 0; i < array_size; i++) + { + switch (array_ptr[i].value_size) + { + case -2: + err = record_word_data (ctx, context, + array_ptr[i].key_ptr, + (long) array_ptr[i].value_ptr); + if (err < 0) + DEBUG ("unable to process word data: %ld\n", err); + break; + + case -1: + err = record_string_data (ctx, context, + array_ptr[i].key_ptr, + (const char *) array_ptr[i].value_ptr); + if (err < 0) + DEBUG ("unable to process string data: %ld\n", err); + break; + + default: + err = record_blob_data_explicit (ctx, context, + array_ptr[i].key_ptr, + array_ptr[i].value_ptr, + array_ptr[i].value_size); + if (err < 0) + DEBUG ("unable to process blob data: %ld\n", err); + break; + } + } + + return err; +} + +static __always_inline int +record_new_context_with_data (struct pt_regs *ctx, long context, long parent, + struct crypto_auditing_data *array_ptr, + long array_size) +{ + int err; + + err = record_new_context (ctx, context, parent); + if (err < 0) + return err; + + return record_data (ctx, context, array_ptr, array_size); +} + SEC("usdt") int BPF_USDT(new_context, long context, long parent) @@ -255,4 +369,21 @@ BPF_USDT(blob_data, long context, const char *key_ptr) return record_blob_data(ctx, context, key_ptr); } +SEC("usdt") +int +BPF_USDT(data, long context, struct crypto_auditing_data *array_ptr, + long array_size) +{ + return record_data(ctx, context, array_ptr, array_size); +} + +SEC("usdt") +int +BPF_USDT(new_context_with_data, long context, long parent, + struct crypto_auditing_data *array_ptr, long array_size) +{ + return record_new_context_with_data(ctx, context, parent, array_ptr, + array_size); +} + char LICENSE[] SEC("license") = "GPL"; diff --git a/agent/src/main.rs b/agent/src/main.rs index 85c46c6..4618c77 100644 --- a/agent/src/main.rs +++ b/agent/src/main.rs @@ -146,6 +146,24 @@ fn main() -> Result<(), Box> { ) { links.push(link); } + let prog = progs.data(); + if let Ok(link) = prog.attach_usdt( + -1, // any process + library, + "crypto_auditing", + "data", + ) { + links.push(link); + } + let prog = progs.new_context_with_data(); + if let Ok(link) = prog.attach_usdt( + -1, // any process + library, + "crypto_auditing", + "new_context_with_data", + ) { + links.push(link); + } } let cipher = Cipher::aes_128_ecb(); diff --git a/dist/audit.h b/dist/audit.h index 1906c2c..036bfe5 100644 --- a/dist/audit.h +++ b/dist/audit.h @@ -33,11 +33,59 @@ # define CRYPTO_AUDITING_BLOB_DATA(context, key_ptr, value_ptr, value_size) \ DTRACE_PROBE4(crypto_auditing, blob_data, context, key_ptr, value_ptr, value_size) +struct crypto_auditing_data { + char *key_ptr; + void *value_ptr; + long value_size; +}; + +# define CRYPTO_AUDITING_WORD(key_ptr, value_ptr) \ + { key_ptr, (void *)value_ptr, -2 } +# define CRYPTO_AUDITING_STRING(key_ptr, value_ptr) \ + { key_ptr, value_ptr, -1 } +# define CRYPTO_AUDITING_BLOB(key_ptr, value_ptr, value_size) \ + { key_ptr, value_ptr, value_size } + +/* Assert multiple events at once as a typed array. The VALUE_SIZE + * field indicates the type of event: -2 means a word, -1 means a + * NUL-terminated string, and any other value means a blob with the + * length of VALUE_SIZE. + */ +# define CRYPTO_AUDITING_DATA(context, array_ptr, array_size) \ + DTRACE_PROBE3(crypto_auditing, data, context, array_ptr, array_size) + +# define CRYPTO_AUDITING_DATAV(context, ...) ({ \ + struct crypto_auditing_data __crypto_auditing_events[] = { __VA_ARGS__ }; \ + CRYPTO_AUDITING_DATA(context, \ + __crypto_auditing_events, \ + sizeof (__crypto_auditing_events) / sizeof (__crypto_auditing_events[0])); \ +}) + +/* Introduce a new context CONTEXT, derived from PARENT, as well as + * assert multiple events. + */ +# define CRYPTO_AUDITING_NEW_CONTEXT_WITH_DATA(context, parent, array_ptr, array_size) \ + DTRACE_PROBE4(crypto_auditing, new_context_with_data, context, parent, array_ptr, array_size) + +# define CRYPTO_AUDITING_NEW_CONTEXT_WITH_DATAV(context, parent, ...) ({ \ + struct crypto_auditing_data __crypto_auditing_events[] = { __VA_ARGS__ }; \ + CRYPTO_AUDITING_NEW_CONTEXT_WITH_DATA(context, parent, \ + __crypto_auditing_events, \ + sizeof (__crypto_auditing_events) / sizeof (__crypto_auditing_events[0])); \ +}) + #else # define CRYPTO_AUDITING_NEW_CONTEXT(context, parent) # define CRYPTO_AUDITING_WORD_DATA(context, key_ptr, value_ptr) # define CRYPTO_AUDITING_STRING_DATA(context, key_ptr, value_ptr) # define CRYPTO_AUDITING_BLOB_DATA(context, key_ptr, value_ptr, value_size) +# define CRYPTO_AUDITING_WORD(key_ptr, value_ptr) +# define CRYPTO_AUDITING_STRING(key_ptr, value_ptr) +# define CRYPTO_AUDITING_BLOB(key_ptr, value_ptr, value_size) +# define CRYPTO_AUDITING_DATA(context, array_ptr, array_size) +# define CRYPTO_AUDITING_DATAV(context, ...) +# define CRYPTO_AUDITING_NEW_CONTEXT_WITH_DATA(context, parent, array_ptr, array_size) +# define CRYPTO_AUDITING_NEW_CONTEXT_WITH_DATAV(context, parent, ...) #endif /* ENABLE_CRYPTO_AUDITING */