From 08e05bd353e75fb6b4c3341be3e3a0794a423f0d Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Mon, 6 Oct 2025 13:17:09 +0200 Subject: [PATCH] feat: use BPF_MAP_TYPE_INODE_STORAGE for ignored cache Whenever we find a file that we should ignore based on its path, we can attach a byte to its inode so that we will know on future accesses that the file should be ignored before we do any sort of processing on our hooks. Because the information is attached to the inode itself, when the inode is removed, the storage will be cleaned up on its own. A re-used pointer to an inode should also not cause false hits, since this is specific to the inode we attached to and should go away when the inode is freed. --- fact-ebpf/src/bpf/main.c | 16 ++++++++++++++-- fact-ebpf/src/bpf/maps.h | 16 ++++++++++++++++ fact/src/bpf.rs | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index 8a05e389..067b2b72 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -34,6 +34,10 @@ int BPF_PROG(trace_file_open, struct file* file) { goto ignored; } + if (is_ignored(file->f_path.dentry->d_inode)) { + goto ignored; + } + struct bound_path_t* path = path_read(&file->f_path); if (path == NULL) { bpf_printk("Failed to read path"); @@ -42,6 +46,7 @@ int BPF_PROG(trace_file_open, struct file* file) { } if (!is_monitored(path)) { + add_ignored(file->f_path.dentry->d_inode); goto ignored; } @@ -61,6 +66,10 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { m->path_unlink.total++; + if (is_ignored(dentry->d_inode)) { + goto ignored; + } + struct bound_path_t* path = path_read(dir); if (path == NULL) { bpf_printk("Failed to read path"); @@ -80,8 +89,7 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { } if (!is_monitored(path)) { - m->path_unlink.ignored++; - return 0; + goto ignored; } submit_event(&m->path_unlink, FILE_ACTIVITY_UNLINK, path->path, dentry); @@ -90,4 +98,8 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { error: m->path_unlink.error++; return 0; + +ignored: + m->path_unlink.ignored++; + return 0; } diff --git a/fact-ebpf/src/bpf/maps.h b/fact-ebpf/src/bpf/maps.h index 74086c78..6f19f0e8 100644 --- a/fact-ebpf/src/bpf/maps.h +++ b/fact-ebpf/src/bpf/maps.h @@ -85,4 +85,20 @@ __always_inline static struct metrics_t* get_metrics() { uint64_t host_mount_ns; +struct { + __uint(type, BPF_MAP_TYPE_INODE_STORAGE); + __type(key, unsigned int); + __type(value, char); + __uint(max_entries, 0); + __uint(map_flags, BPF_F_NO_PREALLOC); +} ignored SEC(".maps"); + +__always_inline static void add_ignored(struct inode* inode) { + bpf_inode_storage_get(&ignored, inode, NULL, BPF_LOCAL_STORAGE_GET_F_CREATE); +} + +__always_inline static bool is_ignored(struct inode* inode) { + return bpf_inode_storage_get(&ignored, inode, NULL, 0) != NULL; +} + // clang-format on diff --git a/fact/src/bpf.rs b/fact/src/bpf.rs index d5e3e25f..c446247e 100644 --- a/fact/src/bpf.rs +++ b/fact/src/bpf.rs @@ -42,6 +42,7 @@ impl Bpf { ) .set_global("host_mount_ns", &host_info::get_host_mount_ns(), true) .set_max_entries(RINGBUFFER_NAME, config.ringbuf_size() * 1024) + .allow_unsupported_maps() .load(fact_ebpf::EBPF_OBJ)?; let ringbuf = match obj.take_map(RINGBUFFER_NAME) {