diff --git a/fact-ebpf/src/bpf/inode.h b/fact-ebpf/src/bpf/inode.h index 481313e3..fa841536 100644 --- a/fact-ebpf/src/bpf/inode.h +++ b/fact-ebpf/src/bpf/inode.h @@ -11,7 +11,9 @@ #include // clang-format on +// From: man(2) statfs #define BTRFS_SUPER_MAGIC 0x9123683E +#define OVERLAYFS_SUPER_MAGIC 0x794c7630 /** * Retrieve the inode and device numbers and return them as a new key. @@ -58,6 +60,21 @@ __always_inline static inode_key_t inode_to_key(struct inode* inode) { return key; } +/** + * Check if the given inode belongs to an overlayfs filesystem. + * + * Overlayfs triggers LSM hooks for both the merged view and the + * underlying filesystem. This can be used to distinguish between + * them. + */ +__always_inline static bool inode_is_overlayfs(struct inode* inode) { + if (inode == NULL) { + return false; + } + unsigned long magic = BPF_CORE_READ(inode, i_sb, s_magic); + return magic == OVERLAYFS_SUPER_MAGIC; +} + __always_inline static inode_value_t* inode_get(const struct inode_key_t* inode) { if (inode == NULL) { return NULL; diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index d262f2d8..8d9b1041 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -37,6 +37,22 @@ int BPF_PROG(trace_file_open, struct file* file) { goto ignored; } + // Overlayfs deduplication: overlayfs triggers file_open twice — once + // on the overlay inode (with richer semantics like FMODE_CREATED) and + // once on the underlying filesystem inode. We keep the overlayfs + // event and skip the underlying duplicate. + __u64 pid_tgid = bpf_get_current_pid_tgid(); + if (inode_is_overlayfs(file->f_inode)) { + char flag = 1; + bpf_map_update_elem(&overlayfs_dedup, &pid_tgid, &flag, BPF_ANY); + } else { + char* flag = bpf_map_lookup_elem(&overlayfs_dedup, &pid_tgid); + if (flag != NULL) { + bpf_map_delete_elem(&overlayfs_dedup, &pid_tgid); + goto ignored; + } + } + struct bound_path_t* path = path_read_unchecked(&file->f_path); if (path == NULL) { bpf_printk("Failed to read path"); diff --git a/fact-ebpf/src/bpf/maps.h b/fact-ebpf/src/bpf/maps.h index c8595829..46d3e3f0 100644 --- a/fact-ebpf/src/bpf/maps.h +++ b/fact-ebpf/src/bpf/maps.h @@ -97,6 +97,15 @@ struct { __uint(max_entries, 1); } metrics SEC(".maps"); +// Track pid_tgid of overlayfs file_open events so we can skip the +// duplicate underlying filesystem event that follows immediately. +struct { + __uint(type, BPF_MAP_TYPE_LRU_PERCPU_HASH); + __type(key, __u64); + __type(value, char); + __uint(max_entries, 1); +} overlayfs_dedup SEC(".maps"); + __always_inline static struct metrics_t* get_metrics() { unsigned int zero = 0; return bpf_map_lookup_elem(&metrics, &zero); diff --git a/tests/test_editors/test_nvim.py b/tests/test_editors/test_nvim.py index 9f3d095d..51ffc26b 100644 --- a/tests/test_editors/test_nvim.py +++ b/tests/test_editors/test_nvim.py @@ -85,8 +85,6 @@ def test_new_file_ovfs(editor_container, server): events = [ Event(process=process, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=fut, host_path=''), ] server.wait_events(events, strict=True) @@ -120,12 +118,8 @@ def test_open_file_ovfs(editor_container, server): events = [ Event(process=touch, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=nvim, event_type=EventType.CREATION, file=vi_test_file, host_path=''), - Event(process=nvim, event_type=EventType.OPEN, - file=vi_test_file, host_path=''), Event(process=nvim, event_type=EventType.OWNERSHIP, file=vi_test_file, host_path='', owner_uid=0, owner_gid=0), Event(process=nvim, event_type=EventType.UNLINK, @@ -134,8 +128,6 @@ def test_open_file_ovfs(editor_container, server): file=fut_backup, host_path='', old_file=fut, old_host_path=''), Event(process=nvim, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=nvim, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=nvim, event_type=EventType.PERMISSION, file=fut, host_path='', mode=0o100644), Event(process=nvim, event_type=EventType.UNLINK, diff --git a/tests/test_editors/test_sed.py b/tests/test_editors/test_sed.py index c3f6a2f8..122d1527 100644 --- a/tests/test_editors/test_sed.py +++ b/tests/test_editors/test_sed.py @@ -69,12 +69,8 @@ def test_sed_ovfs(vi_container, server): events = [ Event(process=shell, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=shell, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=sed, event_type=EventType.CREATION, file=sed_tmp_file, host_path=''), - Event(process=sed, event_type=EventType.OPEN, - file=sed_tmp_file, host_path=''), Event(process=sed, event_type=EventType.OWNERSHIP, file=sed_tmp_file, host_path='', owner_uid=0, owner_gid=0), Event(process=sed, event_type=EventType.RENAME, diff --git a/tests/test_editors/test_vi.py b/tests/test_editors/test_vi.py index 4301890a..62be23a9 100644 --- a/tests/test_editors/test_vi.py +++ b/tests/test_editors/test_vi.py @@ -59,24 +59,16 @@ def test_new_file_ovfs(vi_container, server): events = [ Event(process=process, event_type=EventType.CREATION, file=swap_file, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=swap_file, host_path=''), Event(process=process, event_type=EventType.CREATION, file=swx_file, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=swx_file, host_path=''), Event(process=process, event_type=EventType.UNLINK, file=swx_file, host_path=''), Event(process=process, event_type=EventType.UNLINK, file=swap_file, host_path=''), Event(process=process, event_type=EventType.CREATION, file=swap_file, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=swap_file, host_path=''), Event(process=process, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=process, event_type=EventType.UNLINK, file=swap_file, host_path=''), ] @@ -179,30 +171,20 @@ def test_open_file_ovfs(vi_container, server): events = [ Event(process=touch_process, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch_process, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=vi_process, event_type=EventType.CREATION, file=swap_file, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=swap_file, host_path=''), Event(process=vi_process, event_type=EventType.CREATION, file=swx_file, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=swx_file, host_path=''), Event(process=vi_process, event_type=EventType.UNLINK, file=swx_file, host_path=''), Event(process=vi_process, event_type=EventType.UNLINK, file=swap_file, host_path=''), Event(process=vi_process, event_type=EventType.CREATION, file=swap_file, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=swap_file, host_path=''), Event(process=vi_process, event_type=EventType.PERMISSION, file=swap_file, host_path='', mode=0o644), Event(process=vi_process, event_type=EventType.CREATION, file=vi_test_file, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=vi_test_file, host_path=''), Event(process=vi_process, event_type=EventType.OWNERSHIP, file=vi_test_file, host_path='', owner_uid=0, owner_gid=0), Event(process=vi_process, event_type=EventType.UNLINK, @@ -211,8 +193,6 @@ def test_open_file_ovfs(vi_container, server): file=fut_backup, host_path='', old_file=fut, old_host_path=''), Event(process=vi_process, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=vi_process, event_type=EventType.PERMISSION, file=fut, host_path='', mode=0o100644), Event(process=vi_process, event_type=EventType.UNLINK, diff --git a/tests/test_editors/test_vim.py b/tests/test_editors/test_vim.py index 56cbb667..a7b9f83d 100644 --- a/tests/test_editors/test_vim.py +++ b/tests/test_editors/test_vim.py @@ -55,24 +55,16 @@ def test_new_file_ovfs(editor_container, server): events = [ Event(process=process, event_type=EventType.CREATION, file=swap_file, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=swap_file, host_path=''), Event(process=process, event_type=EventType.CREATION, file=swx_file, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=swx_file, host_path=''), Event(process=process, event_type=EventType.UNLINK, file=swx_file, host_path=''), Event(process=process, event_type=EventType.UNLINK, file=swap_file, host_path=''), Event(process=process, event_type=EventType.CREATION, file=swap_file, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=swap_file, host_path=''), Event(process=process, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=process, event_type=EventType.UNLINK, file=swap_file, host_path=''), ] @@ -173,30 +165,20 @@ def test_open_file_ovfs(editor_container, server): events = [ Event(process=touch_process, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch_process, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=vi_process, event_type=EventType.CREATION, file=swap_file, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=swap_file, host_path=''), Event(process=vi_process, event_type=EventType.CREATION, file=swx_file, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=swx_file, host_path=''), Event(process=vi_process, event_type=EventType.UNLINK, file=swx_file, host_path=''), Event(process=vi_process, event_type=EventType.UNLINK, file=swap_file, host_path=''), Event(process=vi_process, event_type=EventType.CREATION, file=swap_file, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=swap_file, host_path=''), Event(process=vi_process, event_type=EventType.PERMISSION, file=swap_file, host_path='', mode=0o644), Event(process=vi_process, event_type=EventType.CREATION, file=vi_test_file, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=vi_test_file, host_path=''), Event(process=vi_process, event_type=EventType.OWNERSHIP, file=vi_test_file, host_path='', owner_uid=0, owner_gid=0), Event(process=vi_process, event_type=EventType.UNLINK, @@ -205,8 +187,6 @@ def test_open_file_ovfs(editor_container, server): file=fut_backup, host_path='', old_file=fut, old_host_path=''), Event(process=vi_process, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=vi_process, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=vi_process, event_type=EventType.PERMISSION, file=fut, host_path='', mode=0o100644), Event(process=vi_process, event_type=EventType.UNLINK, diff --git a/tests/test_file_open.py b/tests/test_file_open.py index c43b8a15..0bc5ab2b 100644 --- a/tests/test_file_open.py +++ b/tests/test_file_open.py @@ -166,8 +166,6 @@ def test_overlay(test_container, server): events = [ Event(process=process, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=process, event_type=EventType.OPEN, - file=fut, host_path='') ] server.wait_events(events) diff --git a/tests/test_path_chmod.py b/tests/test_path_chmod.py index 08cb483d..811a4e3e 100644 --- a/tests/test_path_chmod.py +++ b/tests/test_path_chmod.py @@ -175,8 +175,6 @@ def test_overlay(test_container, server): events = [ Event(process=touch, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=chmod, event_type=EventType.PERMISSION, file=fut, host_path='', mode=int(mode, 8)), ] diff --git a/tests/test_path_chown.py b/tests/test_path_chown.py index a8c75c0b..021b5b55 100644 --- a/tests/test_path_chown.py +++ b/tests/test_path_chown.py @@ -60,8 +60,6 @@ def test_chown(test_container, server, filename): events = [ Event(process=touch, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch, event_type=EventType.OPEN, file=fut, - host_path=''), Event(process=chown, event_type=EventType.OWNERSHIP, file=fut, host_path='', owner_uid=TEST_UID, owner_gid=TEST_GID), ] @@ -104,8 +102,6 @@ def test_multiple(test_container, server): events.extend([ Event(process=touch, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch, event_type=EventType.OPEN, file=fut, - host_path=''), Event(process=chown, event_type=EventType.OWNERSHIP, file=fut, host_path='', owner_uid=TEST_UID, owner_gid=TEST_GID), ]) @@ -150,8 +146,6 @@ def test_ignored(test_container, server): events = [ Event(process=reported_touch, event_type=EventType.CREATION, file=monitored_file, host_path=''), - Event(process=reported_touch, event_type=EventType.OPEN, - file=monitored_file, host_path=''), Event(process=reported_chown, event_type=EventType.OWNERSHIP, file=monitored_file, host_path='', owner_uid=TEST_UID, owner_gid=TEST_GID), ] @@ -201,8 +195,6 @@ def test_no_change(test_container, server): events = [ Event(process=touch, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch, event_type=EventType.OPEN, file=fut, - host_path=''), chown_event, chown_event, ] diff --git a/tests/test_path_rename.py b/tests/test_path_rename.py index a3600eff..12e417e1 100644 --- a/tests/test_path_rename.py +++ b/tests/test_path_rename.py @@ -174,8 +174,6 @@ def test_overlay(test_container, server): events = [ Event(process=touch, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=mv, event_type=EventType.RENAME, file=new_fut, host_path='', old_file=fut, old_host_path=''), ] diff --git a/tests/test_path_unlink.py b/tests/test_path_unlink.py index 66a533e6..e7675c53 100644 --- a/tests/test_path_unlink.py +++ b/tests/test_path_unlink.py @@ -170,8 +170,6 @@ def test_overlay(test_container, server): events = [ Event(process=touch, event_type=EventType.CREATION, file=fut, host_path=''), - Event(process=touch, event_type=EventType.OPEN, - file=fut, host_path=''), Event(process=rm, event_type=EventType.UNLINK, file=fut, host_path=''), ]