From aa509a2cae3b4bed8071462cdb93fcd8a45daf25 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Wed, 1 Apr 2026 10:59:21 +0200 Subject: [PATCH 1/4] cleanup: refactor submit event functions A new submit_event_args_t type is added to group together common arguments used by all submit event functions. This reduces the number of arguments that need to be passed into these functions and make it harder to make mistakes in the ordering of the actual arguments. --- fact-ebpf/src/bpf/events.h | 135 +++++++++++++++++-------------------- fact-ebpf/src/bpf/main.c | 123 +++++++++++++++++---------------- tests/test_path_rename.py | 4 +- 3 files changed, 131 insertions(+), 131 deletions(-) diff --git a/fact-ebpf/src/bpf/events.h b/fact-ebpf/src/bpf/events.h index fe521450..e5aea55f 100644 --- a/fact-ebpf/src/bpf/events.h +++ b/fact-ebpf/src/bpf/events.h @@ -12,134 +12,125 @@ #include // clang-format on -__always_inline static void __submit_event(struct event_t* event, - struct metrics_by_hook_t* m, - file_activity_type_t event_type, - const char filename[PATH_MAX], - inode_key_t* inode, - inode_key_t* parent_inode, - bool use_bpf_d_path) { - event->type = event_type; +struct submit_event_args_t { + struct event_t* event; + struct metrics_by_hook_t* metrics; + const char* filename; + inode_key_t* inode; + inode_key_t parent_inode; + bool use_bpf_d_path; +}; + +__always_inline static void __submit_event(struct submit_event_args_t* args) { + struct event_t* event = args->event; event->timestamp = bpf_ktime_get_boot_ns(); - inode_copy_or_reset(&event->inode, inode); - inode_copy_or_reset(&event->parent_inode, parent_inode); - bpf_probe_read_str(event->filename, PATH_MAX, filename); + inode_copy_or_reset(&event->inode, args->inode); + inode_copy_or_reset(&event->parent_inode, &args->parent_inode); + bpf_probe_read_str(event->filename, PATH_MAX, args->filename); struct helper_t* helper = get_helper(); if (helper == NULL) { goto error; } - int64_t err = process_fill(&event->process, use_bpf_d_path); + int64_t err = process_fill(&event->process, args->use_bpf_d_path); if (err) { bpf_printk("Failed to fill process information: %d", err); goto error; } - m->added++; + args->metrics->added++; bpf_ringbuf_submit(event, 0); return; error: - m->error++; + args->metrics->error++; bpf_ringbuf_discard(event, 0); } -__always_inline static void submit_open_event(struct metrics_by_hook_t* m, - file_activity_type_t event_type, - const char filename[PATH_MAX], - inode_key_t* inode, - inode_key_t* parent_inode) { - struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (event == NULL) { - m->ringbuffer_full++; +__always_inline static void submit_open_event(struct submit_event_args_t* args, + file_activity_type_t event_type) { + args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); + if (args->event == NULL) { + args->metrics->ringbuffer_full++; return; } + args->event->type = event_type; - __submit_event(event, m, event_type, filename, inode, parent_inode, true); + __submit_event(args); } -__always_inline static void submit_unlink_event(struct metrics_by_hook_t* m, - const char filename[PATH_MAX], - inode_key_t* inode, - inode_key_t* parent_inode) { - struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (event == NULL) { - m->ringbuffer_full++; +__always_inline static void submit_unlink_event(struct submit_event_args_t* args) { + args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); + if (args->event == NULL) { + args->metrics->ringbuffer_full++; return; } + args->event->type = FILE_ACTIVITY_UNLINK; - __submit_event(event, m, FILE_ACTIVITY_UNLINK, filename, inode, parent_inode, path_hooks_support_bpf_d_path); + __submit_event(args); } -__always_inline static void submit_mode_event(struct metrics_by_hook_t* m, - const char filename[PATH_MAX], - inode_key_t* inode, - inode_key_t* parent_inode, +__always_inline static void submit_mode_event(struct submit_event_args_t* args, umode_t mode, umode_t old_mode) { - struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (event == NULL) { - m->ringbuffer_full++; + args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); + if (args->event == NULL) { + args->metrics->ringbuffer_full++; return; } - event->chmod.new = mode; - event->chmod.old = old_mode; + args->event->type = FILE_ACTIVITY_CHMOD; + args->event->chmod.new = mode; + args->event->chmod.old = old_mode; - __submit_event(event, m, FILE_ACTIVITY_CHMOD, filename, inode, parent_inode, path_hooks_support_bpf_d_path); + __submit_event(args); } -__always_inline static void submit_ownership_event(struct metrics_by_hook_t* m, - const char filename[PATH_MAX], - inode_key_t* inode, - inode_key_t* parent_inode, +__always_inline static void submit_ownership_event(struct submit_event_args_t* args, unsigned long long uid, unsigned long long gid, unsigned long long old_uid, unsigned long long old_gid) { - struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (event == NULL) { - m->ringbuffer_full++; + args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); + if (args->event == NULL) { + args->metrics->ringbuffer_full++; return; } - event->chown.new.uid = uid; - event->chown.new.gid = gid; - event->chown.old.uid = old_uid; - event->chown.old.gid = old_gid; + args->event->type = FILE_ACTIVITY_CHOWN; + args->event->chown.new.uid = uid; + args->event->chown.new.gid = gid; + args->event->chown.old.uid = old_uid; + args->event->chown.old.gid = old_gid; - __submit_event(event, m, FILE_ACTIVITY_CHOWN, filename, inode, parent_inode, path_hooks_support_bpf_d_path); + __submit_event(args); } -__always_inline static void submit_rename_event(struct metrics_by_hook_t* m, - const char new_filename[PATH_MAX], +__always_inline static void submit_rename_event(struct submit_event_args_t* args, const char old_filename[PATH_MAX], - inode_key_t* new_inode, - inode_key_t* old_inode, - inode_key_t* new_parent_inode) { - struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (event == NULL) { - m->ringbuffer_full++; + inode_key_t* old_inode) { + args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); + if (args->event == NULL) { + args->metrics->ringbuffer_full++; return; } - bpf_probe_read_str(event->rename.old_filename, PATH_MAX, old_filename); - inode_copy_or_reset(&event->rename.old_inode, old_inode); + args->event->type = FILE_ACTIVITY_RENAME; + bpf_probe_read_str(args->event->rename.old_filename, PATH_MAX, old_filename); + inode_copy_or_reset(&args->event->rename.old_inode, old_inode); - __submit_event(event, m, FILE_ACTIVITY_RENAME, new_filename, new_inode, new_parent_inode, path_hooks_support_bpf_d_path); + __submit_event(args); } -__always_inline static void submit_mkdir_event(struct metrics_by_hook_t* m, - const char filename[PATH_MAX], - inode_key_t* inode, - inode_key_t* parent_inode) { - struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (event == NULL) { - m->ringbuffer_full++; +__always_inline static void submit_mkdir_event(struct submit_event_args_t* args) { + args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); + if (args->event == NULL) { + args->metrics->ringbuffer_full++; return; } + args->event->type = DIR_ACTIVITY_CREATION; // d_instantiate doesn't support bpf_d_path, so we use false and rely on the stashed path from path_mkdir - __submit_event(event, m, DIR_ACTIVITY_CREATION, filename, inode, parent_inode, false); + __submit_event(args); } diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index d262f2d8..1cf315d8 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -25,8 +25,12 @@ int BPF_PROG(trace_file_open, struct file* file) { if (m == NULL) { return 0; } + struct submit_event_args_t args = { + .metrics = &m->file_open, + .use_bpf_d_path = true, + }; - m->file_open.total++; + args.metrics->total++; file_activity_type_t event_type = FILE_ACTIVITY_INIT; if ((file->f_mode & FMODE_CREATED) != 0) { @@ -43,15 +47,16 @@ int BPF_PROG(trace_file_open, struct file* file) { m->file_open.error++; return 0; } + args.filename = path->path; inode_key_t inode_key = inode_to_key(file->f_inode); - inode_key_t* inode_to_submit = &inode_key; + args.inode = &inode_key; struct dentry* parent_dentry = BPF_CORE_READ(file, f_path.dentry, d_parent); struct inode* parent_inode_ptr = parent_dentry ? BPF_CORE_READ(parent_dentry, d_inode) : NULL; - inode_key_t parent_key = inode_to_key(parent_inode_ptr); + args.parent_inode = inode_to_key(parent_inode_ptr); - inode_monitored_t status = is_monitored(inode_key, path, &parent_key, &inode_to_submit); + inode_monitored_t status = is_monitored(inode_key, path, &args.parent_inode, &args.inode); if (status == PARENT_MONITORED && event_type == FILE_ACTIVITY_CREATION) { inode_add(&inode_key); @@ -61,7 +66,7 @@ int BPF_PROG(trace_file_open, struct file* file) { goto ignored; } - submit_open_event(&m->file_open, event_type, path->path, inode_to_submit, &parent_key); + submit_open_event(&args, event_type); return 0; @@ -76,8 +81,12 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { if (m == NULL) { return 0; } + struct submit_event_args_t args = { + .metrics = &m->path_unlink, + .use_bpf_d_path = path_hooks_support_bpf_d_path, + }; - m->path_unlink.total++; + args.metrics->total++; struct bound_path_t* path = path_read_append_d_entry(dir, dentry); if (path == NULL) { @@ -85,11 +94,12 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { m->path_unlink.error++; return 0; } + args.filename = path->path; inode_key_t inode_key = inode_to_key(dentry->d_inode); - inode_key_t* inode_to_submit = &inode_key; + args.inode = &inode_key; - if (is_monitored(inode_key, path, NULL, &inode_to_submit) == NOT_MONITORED) { + if (is_monitored(inode_key, path, NULL, &args.inode) == NOT_MONITORED) { m->path_unlink.ignored++; return 0; } @@ -97,10 +107,7 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { // We only support files with one link for now inode_remove(&inode_key); - submit_unlink_event(&m->path_unlink, - path->path, - inode_to_submit, - NULL); + submit_unlink_event(&args); return 0; } @@ -110,31 +117,31 @@ int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { if (m == NULL) { return 0; } + struct submit_event_args_t args = { + .metrics = &m->path_chmod, + .use_bpf_d_path = path_hooks_support_bpf_d_path, + }; - m->path_chmod.total++; + args.metrics->total++; struct bound_path_t* bound_path = path_read(path); if (bound_path == NULL) { bpf_printk("Failed to read path"); - m->path_chmod.error++; + args.metrics->error++; return 0; } + args.filename = bound_path->path; inode_key_t inode_key = inode_to_key(path->dentry->d_inode); - inode_key_t* inode_to_submit = &inode_key; + args.inode = &inode_key; - if (is_monitored(inode_key, bound_path, NULL, &inode_to_submit) == NOT_MONITORED) { - m->path_chmod.ignored++; + if (is_monitored(inode_key, bound_path, NULL, &args.inode) == NOT_MONITORED) { + args.metrics->ignored++; return 0; } umode_t old_mode = BPF_CORE_READ(path, dentry, d_inode, i_mode); - submit_mode_event(&m->path_chmod, - bound_path->path, - inode_to_submit, - NULL, - mode, - old_mode); + submit_mode_event(&args, mode, old_mode); return 0; } @@ -148,21 +155,26 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign if (m == NULL) { return 0; } + struct submit_event_args_t args = { + .metrics = &m->path_chown, + .use_bpf_d_path = path_hooks_support_bpf_d_path, + }; - m->path_chown.total++; + args.metrics->total++; struct bound_path_t* bound_path = path_read(path); if (bound_path == NULL) { bpf_printk("Failed to read path"); - m->path_chown.error++; + args.metrics->error++; return 0; } + args.filename = bound_path->path; inode_key_t inode_key = inode_to_key(path->dentry->d_inode); - inode_key_t* inode_to_submit = &inode_key; + args.inode = &inode_key; - if (is_monitored(inode_key, bound_path, NULL, &inode_to_submit) == NOT_MONITORED) { - m->path_chown.ignored++; + if (is_monitored(inode_key, bound_path, NULL, &args.inode) == NOT_MONITORED) { + args.metrics->ignored++; return 0; } @@ -170,14 +182,7 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign unsigned long long old_uid = BPF_CORE_READ(d, d_inode, i_uid.val); unsigned long long old_gid = BPF_CORE_READ(d, d_inode, i_gid.val); - submit_ownership_event(&m->path_chown, - bound_path->path, - inode_to_submit, - NULL, - uid, - gid, - old_uid, - old_gid); + submit_ownership_event(&args, uid, gid, old_uid, old_gid); return 0; } @@ -190,14 +195,19 @@ int BPF_PROG(trace_path_rename, struct path* old_dir, if (m == NULL) { return 0; } + struct submit_event_args_t args = { + .metrics = &m->path_rename, + .use_bpf_d_path = path_hooks_support_bpf_d_path, + }; - m->path_rename.total++; + args.metrics->total++; struct bound_path_t* new_path = path_read_append_d_entry(new_dir, new_dentry); if (new_path == NULL) { bpf_printk("Failed to read path"); goto error; } + args.filename = new_path->path; struct bound_path_t* old_path = path_read_alt_append_d_entry(old_dir, old_dentry); if (old_path == NULL) { @@ -209,26 +219,21 @@ int BPF_PROG(trace_path_rename, struct path* old_dir, inode_key_t new_inode = inode_to_key(new_dentry->d_inode); inode_key_t* old_inode_submit = &old_inode; - inode_key_t* new_inode_submit = &new_inode; + args.inode = &new_inode; inode_monitored_t old_monitored = is_monitored(old_inode, old_path, NULL, &old_inode_submit); - inode_monitored_t new_monitored = is_monitored(new_inode, new_path, NULL, &new_inode_submit); + inode_monitored_t new_monitored = is_monitored(new_inode, new_path, NULL, &args.inode); if (old_monitored == NOT_MONITORED && new_monitored == NOT_MONITORED) { - m->path_rename.ignored++; + args.metrics->ignored++; return 0; } - submit_rename_event(&m->path_rename, - new_path->path, - old_path->path, - old_inode_submit, - new_inode_submit, - NULL); + submit_rename_event(&args, old_path->path, old_inode_submit); return 0; error: - m->path_rename.error++; + args.metrics->error++; return 0; } @@ -292,35 +297,39 @@ int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { if (m == NULL) { return 0; } + struct submit_event_args_t args = { + .metrics = &m->d_instantiate, + .use_bpf_d_path = false, + }; - m->d_instantiate.total++; + args.metrics->total++; __u64 pid_tgid = bpf_get_current_pid_tgid(); if (inode == NULL) { - m->d_instantiate.ignored++; + args.metrics->ignored++; goto cleanup; } struct mkdir_context_t* mkdir_ctx = bpf_map_lookup_elem(&mkdir_context, &pid_tgid); if (mkdir_ctx == NULL) { - m->d_instantiate.ignored++; + args.metrics->ignored++; return 0; } + args.filename = mkdir_ctx->path; + args.parent_inode = mkdir_ctx->parent_inode; inode_key_t inode_key = inode_to_key(inode); + args.inode = &inode_key; - if (inode_add(&inode_key) == 0) { - m->d_instantiate.added++; + if (inode_add(args.inode) == 0) { + args.metrics->added++; } else { - m->d_instantiate.error++; + args.metrics->error++; } - submit_mkdir_event(&m->d_instantiate, - mkdir_ctx->path, - &inode_key, - &mkdir_ctx->parent_inode); + submit_mkdir_event(&args); cleanup: bpf_map_delete_elem(&mkdir_context, &pid_tgid); diff --git a/tests/test_path_rename.py b/tests/test_path_rename.py index a3600eff..98c3447a 100644 --- a/tests/test_path_rename.py +++ b/tests/test_path_rename.py @@ -48,9 +48,9 @@ def test_rename(monitored_dir, server, filename): Event(process=Process.from_proc(), event_type=EventType.CREATION, file=old_fut, host_path=old_fut), Event(process=Process.from_proc(), event_type=EventType.RENAME, - file=fut, host_path=old_fut, old_file=old_fut, old_host_path=''), + file=fut, host_path='', old_file=old_fut, old_host_path=old_fut), Event(process=Process.from_proc(), event_type=EventType.RENAME, - file=old_fut, host_path=old_fut, old_file=fut, old_host_path=''), + file=old_fut, host_path='', old_file=fut, old_host_path=old_fut), ] server.wait_events(events) From 2c7376cbb5496dcbe2e1989d081310db151b9783 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Mon, 6 Apr 2026 16:22:22 +0200 Subject: [PATCH 2/4] chore: simplify inode handling kernel side --- fact-ebpf/src/bpf/events.h | 8 ++++---- fact-ebpf/src/bpf/file.h | 6 +++--- fact-ebpf/src/bpf/inode.h | 16 +++++++-------- fact-ebpf/src/bpf/main.c | 41 ++++++++++++++++---------------------- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/fact-ebpf/src/bpf/events.h b/fact-ebpf/src/bpf/events.h index e5aea55f..c4cb4e8c 100644 --- a/fact-ebpf/src/bpf/events.h +++ b/fact-ebpf/src/bpf/events.h @@ -16,7 +16,7 @@ struct submit_event_args_t { struct event_t* event; struct metrics_by_hook_t* metrics; const char* filename; - inode_key_t* inode; + inode_key_t inode; inode_key_t parent_inode; bool use_bpf_d_path; }; @@ -24,8 +24,8 @@ struct submit_event_args_t { __always_inline static void __submit_event(struct submit_event_args_t* args) { struct event_t* event = args->event; event->timestamp = bpf_ktime_get_boot_ns(); - inode_copy_or_reset(&event->inode, args->inode); - inode_copy_or_reset(&event->parent_inode, &args->parent_inode); + inode_copy(&event->inode, &args->inode); + inode_copy(&event->parent_inode, &args->parent_inode); bpf_probe_read_str(event->filename, PATH_MAX, args->filename); struct helper_t* helper = get_helper(); @@ -118,7 +118,7 @@ __always_inline static void submit_rename_event(struct submit_event_args_t* args args->event->type = FILE_ACTIVITY_RENAME; bpf_probe_read_str(args->event->rename.old_filename, PATH_MAX, old_filename); - inode_copy_or_reset(&args->event->rename.old_inode, old_inode); + inode_copy(&args->event->rename.old_inode, old_inode); __submit_event(args); } diff --git a/fact-ebpf/src/bpf/file.h b/fact-ebpf/src/bpf/file.h index eac1b429..efdccfc5 100644 --- a/fact-ebpf/src/bpf/file.h +++ b/fact-ebpf/src/bpf/file.h @@ -27,8 +27,8 @@ __always_inline static bool path_is_monitored(struct bound_path_t* path) { return res; } -__always_inline static inode_monitored_t is_monitored(inode_key_t inode, struct bound_path_t* path, const inode_key_t* parent, inode_key_t** submit) { - const inode_value_t* volatile inode_value = inode_get(&inode); +__always_inline static inode_monitored_t is_monitored(inode_key_t* inode, struct bound_path_t* path, const inode_key_t* parent) { + const inode_value_t* volatile inode_value = inode_get(inode); const inode_value_t* volatile parent_value = inode_get(parent); inode_monitored_t status = inode_is_monitored(inode_value, parent_value); @@ -36,7 +36,7 @@ __always_inline static inode_monitored_t is_monitored(inode_key_t inode, struct return status; } - *submit = NULL; + inode_reset(inode); if (path_is_monitored(path)) { return MONITORED; } diff --git a/fact-ebpf/src/bpf/inode.h b/fact-ebpf/src/bpf/inode.h index 481313e3..6b213c3b 100644 --- a/fact-ebpf/src/bpf/inode.h +++ b/fact-ebpf/src/bpf/inode.h @@ -80,6 +80,11 @@ __always_inline static long inode_remove(struct inode_key_t* inode) { return bpf_map_delete_elem(&inode_map, inode); } +__always_inline static void inode_reset(struct inode_key_t* inode) { + inode->inode = 0; + inode->dev = 0; +} + typedef enum inode_monitored_t { NOT_MONITORED = 0, MONITORED, @@ -99,16 +104,11 @@ __always_inline static inode_monitored_t inode_is_monitored(const inode_value_t* return NOT_MONITORED; } -__always_inline static void inode_copy_or_reset(inode_key_t* dst, const inode_key_t* src) { +__always_inline static void inode_copy(inode_key_t* dst, const inode_key_t* src) { if (dst == NULL) { return; } - if (src != NULL) { - dst->inode = src->inode; - dst->dev = src->dev; - } else { - dst->inode = 0; - dst->dev = 0; - } + dst->inode = src->inode; + dst->dev = src->dev; } diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index 1cf315d8..5ccf4e47 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -49,17 +49,16 @@ int BPF_PROG(trace_file_open, struct file* file) { } args.filename = path->path; - inode_key_t inode_key = inode_to_key(file->f_inode); - args.inode = &inode_key; + args.inode = inode_to_key(file->f_inode); struct dentry* parent_dentry = BPF_CORE_READ(file, f_path.dentry, d_parent); struct inode* parent_inode_ptr = parent_dentry ? BPF_CORE_READ(parent_dentry, d_inode) : NULL; args.parent_inode = inode_to_key(parent_inode_ptr); - inode_monitored_t status = is_monitored(inode_key, path, &args.parent_inode, &args.inode); + inode_monitored_t status = is_monitored(&args.inode, path, &args.parent_inode); if (status == PARENT_MONITORED && event_type == FILE_ACTIVITY_CREATION) { - inode_add(&inode_key); + inode_add(&args.inode); } if (status == NOT_MONITORED) { @@ -96,16 +95,15 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { } args.filename = path->path; - inode_key_t inode_key = inode_to_key(dentry->d_inode); - args.inode = &inode_key; + args.inode = inode_to_key(dentry->d_inode); - if (is_monitored(inode_key, path, NULL, &args.inode) == NOT_MONITORED) { + if (is_monitored(&args.inode, path, NULL) == NOT_MONITORED) { m->path_unlink.ignored++; return 0; } // We only support files with one link for now - inode_remove(&inode_key); + inode_remove(&args.inode); submit_unlink_event(&args); return 0; @@ -132,10 +130,9 @@ int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { } args.filename = bound_path->path; - inode_key_t inode_key = inode_to_key(path->dentry->d_inode); - args.inode = &inode_key; + args.inode = inode_to_key(path->dentry->d_inode); - if (is_monitored(inode_key, bound_path, NULL, &args.inode) == NOT_MONITORED) { + if (is_monitored(&args.inode, bound_path, NULL) == NOT_MONITORED) { args.metrics->ignored++; return 0; } @@ -170,10 +167,9 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign } args.filename = bound_path->path; - inode_key_t inode_key = inode_to_key(path->dentry->d_inode); - args.inode = &inode_key; + args.inode = inode_to_key(path->dentry->d_inode); - if (is_monitored(inode_key, bound_path, NULL, &args.inode) == NOT_MONITORED) { + if (is_monitored(&args.inode, bound_path, NULL) == NOT_MONITORED) { args.metrics->ignored++; return 0; } @@ -215,21 +211,19 @@ int BPF_PROG(trace_path_rename, struct path* old_dir, goto error; } - inode_key_t old_inode = inode_to_key(old_dentry->d_inode); - inode_key_t new_inode = inode_to_key(new_dentry->d_inode); + args.inode = inode_to_key(new_dentry->d_inode); - inode_key_t* old_inode_submit = &old_inode; - args.inode = &new_inode; + inode_key_t old_inode = inode_to_key(old_dentry->d_inode); - inode_monitored_t old_monitored = is_monitored(old_inode, old_path, NULL, &old_inode_submit); - inode_monitored_t new_monitored = is_monitored(new_inode, new_path, NULL, &args.inode); + inode_monitored_t old_monitored = is_monitored(&old_inode, old_path, NULL); + inode_monitored_t new_monitored = is_monitored(&args.inode, new_path, NULL); if (old_monitored == NOT_MONITORED && new_monitored == NOT_MONITORED) { args.metrics->ignored++; return 0; } - submit_rename_event(&args, old_path->path, old_inode_submit); + submit_rename_event(&args, old_path->path, &old_inode); return 0; error: @@ -320,10 +314,9 @@ int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { args.filename = mkdir_ctx->path; args.parent_inode = mkdir_ctx->parent_inode; - inode_key_t inode_key = inode_to_key(inode); - args.inode = &inode_key; + args.inode = inode_to_key(inode); - if (inode_add(args.inode) == 0) { + if (inode_add(&args.inode) == 0) { args.metrics->added++; } else { args.metrics->error++; From 6b6b3fc640362eeaa4a8d16d3deb9e27e722bed6 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Fri, 10 Apr 2026 12:40:45 +0200 Subject: [PATCH 3/4] cleanup: move ringbuf event reservation to its own function --- fact-ebpf/src/bpf/events.h | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/fact-ebpf/src/bpf/events.h b/fact-ebpf/src/bpf/events.h index c4cb4e8c..18ad38ae 100644 --- a/fact-ebpf/src/bpf/events.h +++ b/fact-ebpf/src/bpf/events.h @@ -21,6 +21,15 @@ struct submit_event_args_t { bool use_bpf_d_path; }; +__always_inline static bool reserve_event(struct submit_event_args_t* args) { + args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); + if (args->event == NULL) { + args->metrics->ringbuffer_full++; + return false; + } + return true; +} + __always_inline static void __submit_event(struct submit_event_args_t* args) { struct event_t* event = args->event; event->timestamp = bpf_ktime_get_boot_ns(); @@ -50,9 +59,7 @@ __always_inline static void __submit_event(struct submit_event_args_t* args) { __always_inline static void submit_open_event(struct submit_event_args_t* args, file_activity_type_t event_type) { - args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (args->event == NULL) { - args->metrics->ringbuffer_full++; + if (!reserve_event(args)) { return; } args->event->type = event_type; @@ -61,9 +68,7 @@ __always_inline static void submit_open_event(struct submit_event_args_t* args, } __always_inline static void submit_unlink_event(struct submit_event_args_t* args) { - args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (args->event == NULL) { - args->metrics->ringbuffer_full++; + if (!reserve_event(args)) { return; } args->event->type = FILE_ACTIVITY_UNLINK; @@ -74,9 +79,7 @@ __always_inline static void submit_unlink_event(struct submit_event_args_t* args __always_inline static void submit_mode_event(struct submit_event_args_t* args, umode_t mode, umode_t old_mode) { - args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (args->event == NULL) { - args->metrics->ringbuffer_full++; + if (!reserve_event(args)) { return; } @@ -92,9 +95,7 @@ __always_inline static void submit_ownership_event(struct submit_event_args_t* a unsigned long long gid, unsigned long long old_uid, unsigned long long old_gid) { - args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (args->event == NULL) { - args->metrics->ringbuffer_full++; + if (!reserve_event(args)) { return; } @@ -110,9 +111,7 @@ __always_inline static void submit_ownership_event(struct submit_event_args_t* a __always_inline static void submit_rename_event(struct submit_event_args_t* args, const char old_filename[PATH_MAX], inode_key_t* old_inode) { - args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (args->event == NULL) { - args->metrics->ringbuffer_full++; + if (!reserve_event(args)) { return; } @@ -124,9 +123,7 @@ __always_inline static void submit_rename_event(struct submit_event_args_t* args } __always_inline static void submit_mkdir_event(struct submit_event_args_t* args) { - args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0); - if (args->event == NULL) { - args->metrics->ringbuffer_full++; + if (!reserve_event(args)) { return; } args->event->type = DIR_ACTIVITY_CREATION; From 0c1b26f06b6a05e93e6fc57b93da099b16389e1f Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Fri, 10 Apr 2026 16:13:52 +0200 Subject: [PATCH 4/4] fix: prevent verifier error on bpf_d_path not being removed --- fact-ebpf/src/bpf/events.h | 18 +++++++++--------- fact-ebpf/src/bpf/main.c | 30 ++++++------------------------ 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/fact-ebpf/src/bpf/events.h b/fact-ebpf/src/bpf/events.h index 18ad38ae..276a1d97 100644 --- a/fact-ebpf/src/bpf/events.h +++ b/fact-ebpf/src/bpf/events.h @@ -18,7 +18,6 @@ struct submit_event_args_t { const char* filename; inode_key_t inode; inode_key_t parent_inode; - bool use_bpf_d_path; }; __always_inline static bool reserve_event(struct submit_event_args_t* args) { @@ -30,7 +29,8 @@ __always_inline static bool reserve_event(struct submit_event_args_t* args) { return true; } -__always_inline static void __submit_event(struct submit_event_args_t* args) { +__always_inline static void __submit_event(struct submit_event_args_t* args, + bool use_bpf_d_path) { struct event_t* event = args->event; event->timestamp = bpf_ktime_get_boot_ns(); inode_copy(&event->inode, &args->inode); @@ -42,7 +42,7 @@ __always_inline static void __submit_event(struct submit_event_args_t* args) { goto error; } - int64_t err = process_fill(&event->process, args->use_bpf_d_path); + int64_t err = process_fill(&event->process, use_bpf_d_path); if (err) { bpf_printk("Failed to fill process information: %d", err); goto error; @@ -64,7 +64,7 @@ __always_inline static void submit_open_event(struct submit_event_args_t* args, } args->event->type = event_type; - __submit_event(args); + __submit_event(args, true); } __always_inline static void submit_unlink_event(struct submit_event_args_t* args) { @@ -73,7 +73,7 @@ __always_inline static void submit_unlink_event(struct submit_event_args_t* args } args->event->type = FILE_ACTIVITY_UNLINK; - __submit_event(args); + __submit_event(args, path_hooks_support_bpf_d_path); } __always_inline static void submit_mode_event(struct submit_event_args_t* args, @@ -87,7 +87,7 @@ __always_inline static void submit_mode_event(struct submit_event_args_t* args, args->event->chmod.new = mode; args->event->chmod.old = old_mode; - __submit_event(args); + __submit_event(args, path_hooks_support_bpf_d_path); } __always_inline static void submit_ownership_event(struct submit_event_args_t* args, @@ -105,7 +105,7 @@ __always_inline static void submit_ownership_event(struct submit_event_args_t* a args->event->chown.old.uid = old_uid; args->event->chown.old.gid = old_gid; - __submit_event(args); + __submit_event(args, path_hooks_support_bpf_d_path); } __always_inline static void submit_rename_event(struct submit_event_args_t* args, @@ -119,7 +119,7 @@ __always_inline static void submit_rename_event(struct submit_event_args_t* args bpf_probe_read_str(args->event->rename.old_filename, PATH_MAX, old_filename); inode_copy(&args->event->rename.old_inode, old_inode); - __submit_event(args); + __submit_event(args, path_hooks_support_bpf_d_path); } __always_inline static void submit_mkdir_event(struct submit_event_args_t* args) { @@ -129,5 +129,5 @@ __always_inline static void submit_mkdir_event(struct submit_event_args_t* args) args->event->type = DIR_ACTIVITY_CREATION; // d_instantiate doesn't support bpf_d_path, so we use false and rely on the stashed path from path_mkdir - __submit_event(args); + __submit_event(args, false); } diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index 5ccf4e47..c6effe8d 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -25,10 +25,7 @@ int BPF_PROG(trace_file_open, struct file* file) { if (m == NULL) { return 0; } - struct submit_event_args_t args = { - .metrics = &m->file_open, - .use_bpf_d_path = true, - }; + struct submit_event_args_t args = {.metrics = &m->file_open}; args.metrics->total++; @@ -80,10 +77,7 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { if (m == NULL) { return 0; } - struct submit_event_args_t args = { - .metrics = &m->path_unlink, - .use_bpf_d_path = path_hooks_support_bpf_d_path, - }; + struct submit_event_args_t args = {.metrics = &m->path_unlink}; args.metrics->total++; @@ -115,10 +109,7 @@ int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { if (m == NULL) { return 0; } - struct submit_event_args_t args = { - .metrics = &m->path_chmod, - .use_bpf_d_path = path_hooks_support_bpf_d_path, - }; + struct submit_event_args_t args = {.metrics = &m->path_chmod}; args.metrics->total++; @@ -152,10 +143,7 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign if (m == NULL) { return 0; } - struct submit_event_args_t args = { - .metrics = &m->path_chown, - .use_bpf_d_path = path_hooks_support_bpf_d_path, - }; + struct submit_event_args_t args = {.metrics = &m->path_chown}; args.metrics->total++; @@ -191,10 +179,7 @@ int BPF_PROG(trace_path_rename, struct path* old_dir, if (m == NULL) { return 0; } - struct submit_event_args_t args = { - .metrics = &m->path_rename, - .use_bpf_d_path = path_hooks_support_bpf_d_path, - }; + struct submit_event_args_t args = {.metrics = &m->path_rename}; args.metrics->total++; @@ -291,10 +276,7 @@ int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { if (m == NULL) { return 0; } - struct submit_event_args_t args = { - .metrics = &m->d_instantiate, - .use_bpf_d_path = false, - }; + struct submit_event_args_t args = {.metrics = &m->d_instantiate}; args.metrics->total++;