diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index e0a23522..beab0eb1 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -84,6 +84,9 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { return 0; } + // We only support files with one link for now + inode_remove(&inode_key); + submit_unlink_event(&m->path_unlink, path->path, inode_to_submit); diff --git a/fact/src/event/mod.rs b/fact/src/event/mod.rs index 9087f5ab..06ff27b1 100644 --- a/fact/src/event/mod.rs +++ b/fact/src/event/mod.rs @@ -125,6 +125,10 @@ impl Event { }) } + pub fn is_unlink(&self) -> bool { + matches!(self.file, FileData::Unlink(_)) + } + /// Unwrap the inner FileData and return the inode that triggered /// the event. /// diff --git a/fact/src/host_scanner.rs b/fact/src/host_scanner.rs index 05d22e75..1a6fa18a 100644 --- a/fact/src/host_scanner.rs +++ b/fact/src/host_scanner.rs @@ -178,6 +178,18 @@ impl HostScanner { self.inode_map.borrow().get(inode?).cloned() } + /// Special handling for unlink events. + /// + /// This method removes the inode from the userland inode->path map. + /// The probe already cleared the kernel inode map. + fn handle_unlink_event(&self, event: &Event) { + let inode = event.get_inode(); + + if self.inode_map.borrow_mut().remove(inode).is_some() { + self.metrics.scan_inc(ScanLabels::InodeRemoved); + } + } + /// Periodically notify the host scanner main task that a scan needs /// to happen. /// @@ -229,6 +241,11 @@ impl HostScanner { event.set_old_host_path(host_path); } + // Special handling for unlink events + if event.is_unlink() { + self.handle_unlink_event(&event); + } + let event = Arc::new(event); if let Err(e) = self.tx.send(event) { self.metrics.events.dropped();