Skip to content

Commit

Permalink
agent: Support composite events
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
ueno committed Apr 9, 2024
1 parent e9b27f9 commit 1b20641
Show file tree
Hide file tree
Showing 4 changed files with 400 additions and 4 deletions.
169 changes: 165 additions & 4 deletions agent/src/bpf/audit.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@
bpf_trace_printk ("%s: " format, sizeof("%s: " format), \
__PRETTY_FUNCTION__, __VA_ARGS__)

#define MAX_EVENTS 16
#define DATA_TYPE_WORD (unsigned long)-2
#define DATA_TYPE_STRING (unsigned long)-1

struct crypto_auditing_data {
char *key_ptr;
void *value_ptr;
unsigned long value_size;
};

struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 4096 /* one page */);
Expand Down Expand Up @@ -231,33 +241,184 @@ 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, unsigned long value_size)
{
int err;

if (value_size > VALUE_SIZE)
{
DEBUG ("value size out of range: %lu\n", value_size);
return -EINVAL;
}

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)
{
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,
const struct crypto_auditing_data *array_ptr,
unsigned long array_size)
{
struct crypto_auditing_data events[MAX_EVENTS];
int err;

if (array_size > MAX_EVENTS)
{
DEBUG ("value size out of range: %lu\n", array_size);
return -EINVAL;
}
array_size &= MAX_EVENTS - 1;

err = bpf_probe_read_user (events,
array_size * sizeof (struct crypto_auditing_data),
array_ptr);
if (err < 0)
{
DEBUG ("unable to read from data array: %ld\n", err);
return err;
}

for (unsigned long i = 0; i < array_size; i++)
{
switch (events[i].value_size)
{
case DATA_TYPE_WORD:
err = record_word_data (ctx, context,
events[i].key_ptr,
(long) events[i].value_ptr);
if (err < 0)
DEBUG ("unable to process word data: %ld\n", err);
break;

case DATA_TYPE_STRING:
err = record_string_data (ctx, context,
events[i].key_ptr,
(const char *) events[i].value_ptr);
if (err < 0)
DEBUG ("unable to process string data: %ld\n", err);
break;

default:
err = record_blob_data_explicit (ctx, context,
events[i].key_ptr,
events[i].value_ptr,
events[i].value_size);
if (err < 0)
DEBUG ("unable to process blob data: %ld\n", err);
break;
}

if (err < 0)
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,
unsigned 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)
{
return record_new_context(ctx, context, parent);
return record_new_context (ctx, context, parent);
}

SEC("usdt")
int
BPF_USDT(word_data, long context, const char *key_ptr, long value)
{
return record_word_data(ctx, context, key_ptr, value);
return record_word_data (ctx, context, key_ptr, value);
}

SEC("usdt")
int
BPF_USDT(string_data, long context, const char *key_ptr,
const char *value_ptr)
{
return record_string_data(ctx, context, key_ptr, value_ptr);
return record_string_data (ctx, context, key_ptr, value_ptr);
}

SEC("usdt")
int
BPF_USDT(blob_data, long context, const char *key_ptr)
{
return record_blob_data(ctx, context, key_ptr);
return record_blob_data (ctx, context, key_ptr);
}

SEC("usdt")
int
BPF_USDT(data, long context, const struct crypto_auditing_data *array_ptr,
unsigned 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,
void *array_ptr, unsigned long array_size)
{
return record_new_context_with_data (ctx, context, parent, array_ptr,
array_size);
}

char LICENSE[] SEC("license") = "GPL";
18 changes: 18 additions & 0 deletions agent/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
) {
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();
Expand Down
Loading

0 comments on commit 1b20641

Please sign in to comment.