From c33abb3cf6164e25454aed87ee3c17d3ab2d2972 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Tue, 25 Aug 2026 10:10:55 +0200 Subject: [PATCH 1/3] fix(bpf): disable preemption during hook processing This prevents the hooks from being preempted and replaced by another hook that might overwrite the contents of the shared per-CPU maps before sending the event to the ringbuffer. A similar issue was found to be corrupting events in Falco and is addressed in this PR of our fork, see the discussion there for more details: https://github.com/stackrox/falcosecurity-libs/pull/98 In order to call `bpf_preempt_enable/disable` aya needs to support ksyms, which is currently only supported on main, therefore we pin the dependency to a commit known to work. We will unpin this once a new aya release is created. --- Cargo.lock | 6 +- Cargo.toml | 2 +- fact-ebpf/src/bpf/main.c | 132 ++++++++++++++++++++++++++++----------- fact/src/bpf/mod.rs | 2 +- fact/src/host_scanner.rs | 2 +- 5 files changed, 100 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63e36a26..7b32f398 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,8 +148,7 @@ dependencies = [ [[package]] name = "aya" version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e644424fada9fff4fdc63848db1732fb69b626e8328202ef55c03df1f4d939" +source = "git+https://github.com/aya-rs/aya.git?rev=c29cd71cb4fe1440bc0d566633afa822f1b41fc5#c29cd71cb4fe1440bc0d566633afa822f1b41fc5" dependencies = [ "assert_matches", "aya-obj", @@ -166,8 +165,7 @@ dependencies = [ [[package]] name = "aya-obj" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c76b9c75d9cdc155ff8f6a06d61e873f67bf47be8cfa92a3b5aaea43f4b4077" +source = "git+https://github.com/aya-rs/aya.git?rev=c29cd71cb4fe1440bc0d566633afa822f1b41fc5#c29cd71cb4fe1440bc0d566633afa822f1b41fc5" dependencies = [ "bytes", "log", diff --git a/Cargo.toml b/Cargo.toml index f59198bb..617b4174 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" [workspace.dependencies] anyhow = { version = "1", default-features = false, features = ["std", "backtrace"] } -aya = { version = "0.14.0", default-features = false } +aya = { git = "https://github.com/aya-rs/aya.git", rev = "c29cd71cb4fe1440bc0d566633afa822f1b41fc5", default-features = false } libc = { version = "0.2.159", default-features = false } prost = "0.14.0" prost-types = "0.14.0" diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index 8d5aae7d..1cc8eb32 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -21,9 +21,10 @@ char _license[] SEC("license") = "Dual MIT/GPL"; SEC("lsm/file_open") int BPF_PROG(trace_file_open, struct file* file) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->file_open}; @@ -58,7 +59,7 @@ int BPF_PROG(trace_file_open, struct file* file) { if (path == NULL) { bpf_printk("Failed to read path"); m->file_open.error++; - return 0; + goto end; } args.filename = path->path; @@ -79,10 +80,13 @@ int BPF_PROG(trace_file_open, struct file* file) { submit_open_event(&args, event_type); +end: + bpf_preempt_enable(); return 0; ignored: m->file_open.ignored++; + bpf_preempt_enable(); return 0; } @@ -125,9 +129,10 @@ int BPF_PROG(trace_path_link, struct dentry* old_dentry, const struct path* new_ SEC("lsm/path_unlink") int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->path_unlink}; @@ -137,7 +142,7 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { if (path == NULL) { bpf_printk("Failed to read path"); m->path_unlink.error++; - return 0; + goto end; } args.filename = path->path; @@ -146,7 +151,7 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { if (args.monitored == NOT_MONITORED) { m->path_unlink.ignored++; - return 0; + goto end; } // Only remove from kernel map if this is the last link @@ -155,14 +160,18 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { } submit_unlink_event(&args); + +end: + bpf_preempt_enable(); return 0; } SEC("lsm/path_chmod") int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->path_chmod}; @@ -172,7 +181,7 @@ int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { if (bound_path == NULL) { bpf_printk("Failed to read path"); args.metrics->error++; - return 0; + goto end; } args.filename = bound_path->path; @@ -181,12 +190,14 @@ int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - return 0; + goto end; } umode_t old_mode = BPF_CORE_READ(path, dentry, d_inode, i_mode); submit_mode_event(&args, mode, old_mode); +end: + bpf_preempt_enable(); return 0; } @@ -195,9 +206,10 @@ int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { size of the BPF registers (64 bits) to simplify further arithmetic operations. */ SEC("lsm/path_chown") int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsigned long long gid) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->path_chown}; @@ -207,7 +219,7 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign if (bound_path == NULL) { bpf_printk("Failed to read path"); args.metrics->error++; - return 0; + goto end; } args.filename = bound_path->path; @@ -216,7 +228,7 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - return 0; + goto end; } struct dentry* d = BPF_CORE_READ(path, dentry); @@ -225,6 +237,8 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign submit_ownership_event(&args, uid, gid, old_uid, old_gid); +end: + bpf_preempt_enable(); return 0; } @@ -232,9 +246,10 @@ SEC("lsm/path_rename") int BPF_PROG(trace_path_rename, struct path* old_dir, struct dentry* old_dentry, struct path* new_dir, struct dentry* new_dentry, unsigned int flags) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->path_rename}; @@ -270,7 +285,7 @@ int BPF_PROG(trace_path_rename, struct path* old_dir, case NOT_MONITORED: if (old_monitored == NOT_MONITORED) { m->path_rename.ignored++; - return 0; + goto end; } if (old_monitored == MONITORED_BY_INODE) { @@ -331,18 +346,23 @@ int BPF_PROG(trace_path_rename, struct path* old_dir, } submit_rename_event(&args, old_path->path, &old_inode, old_monitored); - return 0; + + goto end; error: args.metrics->error++; + +end: + bpf_preempt_enable(); return 0; } SEC("lsm/path_mkdir") int BPF_PROG(trace_path_mkdir, struct path* dir, struct dentry* dentry, umode_t mode) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } m->path_mkdir.total++; @@ -365,23 +385,27 @@ int BPF_PROG(trace_path_mkdir, struct path* dir, struct dentry* dentry, umode_t if (mkdir_ctx->monitored != MONITORED_BY_PARENT) { delete_d_instantiate_ctx(); m->path_mkdir.ignored++; - return 0; + goto end; } mkdir_ctx->event_type = DIR_ACTIVITY_CREATION; - return 0; + goto end; error: delete_d_instantiate_ctx(); m->path_mkdir.error++; + +end: + bpf_preempt_enable(); return 0; } SEC("lsm/d_instantiate") int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->d_instantiate.base}; @@ -397,7 +421,7 @@ int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { struct d_instantiate_ctx_t* d_inst_ctx = get_d_instantiate_ctx(); if (d_inst_ctx == NULL || d_inst_ctx->event_type == FILE_ACTIVITY_INIT) { args.metrics->ignored++; - return 0; + goto end; } args.filename = d_inst_ctx->path.path; args.parent_inode = d_inst_ctx->parent_inode; @@ -437,6 +461,9 @@ int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { cleanup: bpf_map_delete_elem(&d_instantiate_ctx, &pid_tgid); + +end: + bpf_preempt_enable(); return 0; } @@ -465,29 +492,38 @@ __always_inline static int handle_xattr(struct metrics_by_hook_t* hook_metrics, SEC("lsm/inode_setxattr") int BPF_PROG(trace_inode_setxattr, struct mnt_idmap* idmap, struct dentry* dentry, const char* name, const void* value, size_t size, int flags) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { return 0; } - return handle_xattr(&m->inode_setxattr, dentry, name, FILE_ACTIVITY_SETXATTR); + int res = handle_xattr(&m->inode_setxattr, dentry, name, FILE_ACTIVITY_SETXATTR); + + bpf_preempt_enable(); + return res; } SEC("lsm/inode_removexattr") int BPF_PROG(trace_inode_removexattr, struct mnt_idmap* idmap, struct dentry* dentry, const char* name) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { return 0; } - return handle_xattr(&m->inode_removexattr, dentry, name, FILE_ACTIVITY_REMOVEXATTR); + int res = handle_xattr(&m->inode_removexattr, dentry, name, FILE_ACTIVITY_REMOVEXATTR); + + bpf_preempt_enable(); + return res; } SEC("lsm/inode_set_acl") int BPF_PROG(trace_inode_set_acl, struct mnt_idmap* idmap, struct dentry* dentry, const char* acl_name, struct posix_acl* kacl) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->inode_set_acl}; @@ -500,18 +536,22 @@ int BPF_PROG(trace_inode_set_acl, struct mnt_idmap* idmap, struct dentry* dentry if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - return 0; + goto end; } submit_acl_event(&args, acl_name, kacl); + +end: + bpf_preempt_enable(); return 0; } SEC("lsm/path_rmdir") int BPF_PROG(trace_path_rmdir, struct path* dir, struct dentry* dentry) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->path_rmdir}; @@ -521,7 +561,7 @@ int BPF_PROG(trace_path_rmdir, struct path* dir, struct dentry* dentry) { if (path == NULL) { bpf_printk("Failed to read directory path"); m->path_rmdir.error++; - return 0; + goto end; } args.filename = path->path; @@ -529,18 +569,22 @@ int BPF_PROG(trace_path_rmdir, struct path* dir, struct dentry* dentry) { if (inode_remove(&args.inode) < 0) { m->path_rmdir.ignored++; - return 0; + goto end; } submit_rmdir_event(&args); + +end: + bpf_preempt_enable(); return 0; } SEC("lsm/sb_mount") int BPF_PROG(trace_sb_mount, const char* dev_name, struct path* path, const char* type, unsigned long flags, void* data) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->sb_mount}; args.metrics->total++; @@ -549,7 +593,7 @@ int BPF_PROG(trace_sb_mount, const char* dev_name, struct path* path, const char if (bound_path == NULL) { bpf_printk("Failed to read mount directory"); args.metrics->error++; - return 0; + goto end; } args.filename = bound_path->path; @@ -562,19 +606,22 @@ int BPF_PROG(trace_sb_mount, const char* dev_name, struct path* path, const char args.monitored = is_monitored(&args.inode, bound_path, &args.parent_inode); if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - return 0; + goto end; } submit_mount_event(&args); +end: + bpf_preempt_enable(); return 0; } SEC("lsm/sb_umount") int BPF_PROG(trace_sb_umount, struct vfsmount* mnt, int flags) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->sb_umount}; args.metrics->total++; @@ -584,7 +631,7 @@ int BPF_PROG(trace_sb_umount, struct vfsmount* mnt, int flags) { if (bound_path == NULL) { bpf_printk("Failed to read umount directory"); args.metrics->error++; - return 0; + goto end; } args.filename = bound_path->path; @@ -597,19 +644,22 @@ int BPF_PROG(trace_sb_umount, struct vfsmount* mnt, int flags) { args.monitored = is_monitored(&args.inode, bound_path, &args.parent_inode); if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - return 0; + goto end; } submit_umount_event(&args); +end: + bpf_preempt_enable(); return 0; } SEC("lsm/move_mount") int BPF_PROG(trace_move_mount, struct path* from, struct path* to) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } struct submit_event_args_t args = {.metrics = &m->move_mount}; @@ -637,7 +687,7 @@ int BPF_PROG(trace_move_mount, struct path* from, struct path* to) { if (args.monitored != MONITORED_BY_INODE) { args.metrics->ignored++; - return 0; + goto end; } // Ensure the new mount is tracked. @@ -646,18 +696,23 @@ int BPF_PROG(trace_move_mount, struct path* from, struct path* to) { } submit_move_mount_event(&args, from_path->path, &from_inode, from_monitored); - return 0; + + goto end; error: args.metrics->error++; + +end: + bpf_preempt_enable(); return 0; } SEC("lsm/path_symlink") int BPF_PROG(trace_path_symlink, struct path* dir, struct dentry* dentry, const char* old_name) { + bpf_preempt_disable(); struct metrics_t* m = get_metrics(); if (m == NULL) { - return 0; + goto end; } m->path_symlink.total++; @@ -680,10 +735,13 @@ int BPF_PROG(trace_path_symlink, struct path* dir, struct dentry* dentry, const goto error; } - return 0; + goto end; error: delete_d_instantiate_ctx(); m->path_symlink.error++; + +end: + bpf_preempt_enable(); return 0; } diff --git a/fact/src/bpf/mod.rs b/fact/src/bpf/mod.rs index 10362574..41416785 100644 --- a/fact/src/bpf/mod.rs +++ b/fact/src/bpf/mod.rs @@ -194,7 +194,7 @@ impl Bpf { let mut new_paths = Vec::with_capacity(patterns.len()); for p in patterns.iter().map(|p| host_info::remove_host_mount(p)) { let prefix = path_prefix_t::try_from(p)?; - self.paths_lpm_map.insert(&prefix.into(), 0, 0)?; + self.paths_lpm_map.insert(&prefix.into(), &0, 0)?; new_paths.push(prefix); } new_paths diff --git a/fact/src/host_scanner.rs b/fact/src/host_scanner.rs index 907c0a71..e2b0dcc7 100644 --- a/fact/src/host_scanner.rs +++ b/fact/src/host_scanner.rs @@ -352,7 +352,7 @@ impl HostScanner { } }; - match self.kernel_inode_map.borrow_mut().insert(inode, 0, 0) { + match self.kernel_inode_map.borrow_mut().insert(&inode, &0, 0) { Ok(_) => Ok(()), Err(MapError::SyscallError(SyscallError { io_error, .. })) if io_error.kind() == io::ErrorKind::ArgumentListTooLong => From 532760cd0d74bebdf037cff27719dc56838afa35 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Tue, 25 Aug 2026 12:04:36 +0200 Subject: [PATCH 2/3] cleanup(bpf): use macro magic to simplify preempt enable/disable calls --- fact-ebpf/src/bpf/main.c | 229 ++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 138 deletions(-) diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index 1cc8eb32..e125bff7 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -19,12 +19,43 @@ char _license[] SEC("license") = "Dual MIT/GPL"; #define FMODE_PWRITE ((fmode_t)(1 << 4)) #define FMODE_CREATED ((fmode_t)(1 << 20)) -SEC("lsm/file_open") -int BPF_PROG(trace_file_open, struct file* file) { - bpf_preempt_disable(); +#define STRINGIFY(a) STR(a) +#define STR(a) #a + +#define __MAP0(m, ...) +#define __MAP1(m, t, a, ...) m(t, a) +#define __MAP2(m, t, a, ...) m(t, a), __MAP1(m, __VA_ARGS__) +#define __MAP3(m, t, a, ...) m(t, a), __MAP2(m, __VA_ARGS__) +#define __MAP4(m, t, a, ...) m(t, a), __MAP3(m, __VA_ARGS__) +#define __MAP5(m, t, a, ...) m(t, a), __MAP4(m, __VA_ARGS__) +#define __MAP6(m, t, a, ...) m(t, a), __MAP5(m, __VA_ARGS__) +#define __MAP(n, ...) __MAP##n(__VA_ARGS__) + +#define __CAT(t, a) t a +#define __ARG(t, a) a + +#define FACT_BPF_PROG(hook, n, args...) \ + static __always_inline int _handle_##hook(__MAP(n, __CAT, args)); \ + SEC("lsm/" STRINGIFY(hook)) \ + int BPF_PROG(trace_##hook, __MAP(n, __CAT, args)) { \ + bpf_preempt_disable(); \ + int res = _handle_##hook(__MAP(n, __ARG, args)); \ + bpf_preempt_enable(); \ + return res; \ + } \ + static __always_inline int _handle_##hook(__MAP(n, __CAT, args)) + +#define FACT_BPF_PROG1(hook, args...) FACT_BPF_PROG(hook, 1, args) +#define FACT_BPF_PROG2(hook, args...) FACT_BPF_PROG(hook, 2, args) +#define FACT_BPF_PROG3(hook, args...) FACT_BPF_PROG(hook, 3, args) +#define FACT_BPF_PROG4(hook, args...) FACT_BPF_PROG(hook, 4, args) +#define FACT_BPF_PROG5(hook, args...) FACT_BPF_PROG(hook, 5, args) +#define FACT_BPF_PROG6(hook, args...) FACT_BPF_PROG(hook, 6, args) + +FACT_BPF_PROG1(file_open, struct file*, file) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->file_open}; @@ -59,7 +90,7 @@ int BPF_PROG(trace_file_open, struct file* file) { if (path == NULL) { bpf_printk("Failed to read path"); m->file_open.error++; - goto end; + return 0; } args.filename = path->path; @@ -79,19 +110,14 @@ int BPF_PROG(trace_file_open, struct file* file) { } submit_open_event(&args, event_type); - -end: - bpf_preempt_enable(); return 0; ignored: m->file_open.ignored++; - bpf_preempt_enable(); return 0; } -SEC("lsm/path_link") -int BPF_PROG(trace_path_link, struct dentry* old_dentry, const struct path* new_dir, struct dentry* new_dentry) { +FACT_BPF_PROG3(path_link, struct dentry*, old_dentry, const struct path*, new_dir, struct dentry*, new_dentry) { struct metrics_t* m = get_metrics(); if (m == NULL) { return 0; @@ -127,12 +153,10 @@ int BPF_PROG(trace_path_link, struct dentry* old_dentry, const struct path* new_ return 0; } -SEC("lsm/path_unlink") -int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { - bpf_preempt_disable(); +FACT_BPF_PROG2(path_unlink, struct path*, dir, struct dentry*, dentry) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->path_unlink}; @@ -142,7 +166,7 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { if (path == NULL) { bpf_printk("Failed to read path"); m->path_unlink.error++; - goto end; + return 0; } args.filename = path->path; @@ -151,7 +175,7 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { if (args.monitored == NOT_MONITORED) { m->path_unlink.ignored++; - goto end; + return 0; } // Only remove from kernel map if this is the last link @@ -160,18 +184,13 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { } submit_unlink_event(&args); - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/path_chmod") -int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { - bpf_preempt_disable(); +FACT_BPF_PROG2(path_chmod, struct path*, path, umode_t, mode) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->path_chmod}; @@ -181,7 +200,7 @@ int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { if (bound_path == NULL) { bpf_printk("Failed to read path"); args.metrics->error++; - goto end; + return 0; } args.filename = bound_path->path; @@ -190,26 +209,21 @@ int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) { if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - goto end; + return 0; } umode_t old_mode = BPF_CORE_READ(path, dentry, d_inode, i_mode); submit_mode_event(&args, mode, old_mode); - -end: - bpf_preempt_enable(); return 0; } /* path_chown takes _unsigned long long_ for uid and gid because kuid_t and kgid_t (structs) fit in registers and since they contain only one integer, their content is extended to the size of the BPF registers (64 bits) to simplify further arithmetic operations. */ -SEC("lsm/path_chown") -int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsigned long long gid) { - bpf_preempt_disable(); +FACT_BPF_PROG3(path_chown, struct path*, path, unsigned long long, uid, unsigned long long, gid) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->path_chown}; @@ -219,7 +233,7 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign if (bound_path == NULL) { bpf_printk("Failed to read path"); args.metrics->error++; - goto end; + return 0; } args.filename = bound_path->path; @@ -228,7 +242,7 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - goto end; + return 0; } struct dentry* d = BPF_CORE_READ(path, dentry); @@ -236,20 +250,15 @@ int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsign unsigned long long old_gid = BPF_CORE_READ(d, d_inode, i_gid.val); submit_ownership_event(&args, uid, gid, old_uid, old_gid); - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/path_rename") -int BPF_PROG(trace_path_rename, struct path* old_dir, - struct dentry* old_dentry, struct path* new_dir, - struct dentry* new_dentry, unsigned int flags) { - bpf_preempt_disable(); +FACT_BPF_PROG5(path_rename, struct path*, old_dir, + struct dentry*, old_dentry, struct path*, new_dir, + struct dentry*, new_dentry, unsigned int, flags) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->path_rename}; @@ -285,7 +294,7 @@ int BPF_PROG(trace_path_rename, struct path* old_dir, case NOT_MONITORED: if (old_monitored == NOT_MONITORED) { m->path_rename.ignored++; - goto end; + return 0; } if (old_monitored == MONITORED_BY_INODE) { @@ -346,23 +355,17 @@ int BPF_PROG(trace_path_rename, struct path* old_dir, } submit_rename_event(&args, old_path->path, &old_inode, old_monitored); - - goto end; + return 0; error: args.metrics->error++; - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/path_mkdir") -int BPF_PROG(trace_path_mkdir, struct path* dir, struct dentry* dentry, umode_t mode) { - bpf_preempt_disable(); +FACT_BPF_PROG3(path_mkdir, struct path*, dir, struct dentry*, dentry, umode_t, mode) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } m->path_mkdir.total++; @@ -385,27 +388,21 @@ int BPF_PROG(trace_path_mkdir, struct path* dir, struct dentry* dentry, umode_t if (mkdir_ctx->monitored != MONITORED_BY_PARENT) { delete_d_instantiate_ctx(); m->path_mkdir.ignored++; - goto end; + return 0; } mkdir_ctx->event_type = DIR_ACTIVITY_CREATION; - - goto end; + return 0; error: delete_d_instantiate_ctx(); m->path_mkdir.error++; - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/d_instantiate") -int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { - bpf_preempt_disable(); +FACT_BPF_PROG2(d_instantiate, struct dentry*, dentry, struct inode*, inode) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->d_instantiate.base}; @@ -421,7 +418,7 @@ int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { struct d_instantiate_ctx_t* d_inst_ctx = get_d_instantiate_ctx(); if (d_inst_ctx == NULL || d_inst_ctx->event_type == FILE_ACTIVITY_INIT) { args.metrics->ignored++; - goto end; + return 0; } args.filename = d_inst_ctx->path.path; args.parent_inode = d_inst_ctx->parent_inode; @@ -461,9 +458,6 @@ int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) { cleanup: bpf_map_delete_elem(&d_instantiate_ctx, &pid_tgid); - -end: - bpf_preempt_enable(); return 0; } @@ -489,41 +483,29 @@ __always_inline static int handle_xattr(struct metrics_by_hook_t* hook_metrics, return 0; } -SEC("lsm/inode_setxattr") -int BPF_PROG(trace_inode_setxattr, struct mnt_idmap* idmap, struct dentry* dentry, - const char* name, const void* value, size_t size, int flags) { - bpf_preempt_disable(); +FACT_BPF_PROG6(inode_setxattr, struct mnt_idmap*, idmap, struct dentry*, dentry, + const char*, name, const void*, value, size_t, size, int, flags) { struct metrics_t* m = get_metrics(); if (m == NULL) { return 0; } - int res = handle_xattr(&m->inode_setxattr, dentry, name, FILE_ACTIVITY_SETXATTR); - - bpf_preempt_enable(); - return res; + return handle_xattr(&m->inode_setxattr, dentry, name, FILE_ACTIVITY_SETXATTR); } -SEC("lsm/inode_removexattr") -int BPF_PROG(trace_inode_removexattr, struct mnt_idmap* idmap, struct dentry* dentry, - const char* name) { - bpf_preempt_disable(); +FACT_BPF_PROG3(inode_removexattr, struct mnt_idmap*, idmap, struct dentry*, dentry, + const char*, name) { struct metrics_t* m = get_metrics(); if (m == NULL) { return 0; } - int res = handle_xattr(&m->inode_removexattr, dentry, name, FILE_ACTIVITY_REMOVEXATTR); - - bpf_preempt_enable(); - return res; + return handle_xattr(&m->inode_removexattr, dentry, name, FILE_ACTIVITY_REMOVEXATTR); } -SEC("lsm/inode_set_acl") -int BPF_PROG(trace_inode_set_acl, struct mnt_idmap* idmap, struct dentry* dentry, - const char* acl_name, struct posix_acl* kacl) { - bpf_preempt_disable(); +FACT_BPF_PROG4(inode_set_acl, struct mnt_idmap*, idmap, struct dentry*, dentry, + const char*, acl_name, struct posix_acl*, kacl) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->inode_set_acl}; @@ -536,22 +518,17 @@ int BPF_PROG(trace_inode_set_acl, struct mnt_idmap* idmap, struct dentry* dentry if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - goto end; + return 0; } submit_acl_event(&args, acl_name, kacl); - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/path_rmdir") -int BPF_PROG(trace_path_rmdir, struct path* dir, struct dentry* dentry) { - bpf_preempt_disable(); +FACT_BPF_PROG2(path_rmdir, struct path*, dir, struct dentry*, dentry) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->path_rmdir}; @@ -561,7 +538,7 @@ int BPF_PROG(trace_path_rmdir, struct path* dir, struct dentry* dentry) { if (path == NULL) { bpf_printk("Failed to read directory path"); m->path_rmdir.error++; - goto end; + return 0; } args.filename = path->path; @@ -569,22 +546,17 @@ int BPF_PROG(trace_path_rmdir, struct path* dir, struct dentry* dentry) { if (inode_remove(&args.inode) < 0) { m->path_rmdir.ignored++; - goto end; + return 0; } submit_rmdir_event(&args); - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/sb_mount") -int BPF_PROG(trace_sb_mount, const char* dev_name, struct path* path, const char* type, unsigned long flags, void* data) { - bpf_preempt_disable(); +FACT_BPF_PROG5(sb_mount, const char*, dev_name, struct path*, path, const char*, type, unsigned long, flags, void*, data) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->sb_mount}; args.metrics->total++; @@ -593,7 +565,7 @@ int BPF_PROG(trace_sb_mount, const char* dev_name, struct path* path, const char if (bound_path == NULL) { bpf_printk("Failed to read mount directory"); args.metrics->error++; - goto end; + return 0; } args.filename = bound_path->path; @@ -606,22 +578,17 @@ int BPF_PROG(trace_sb_mount, const char* dev_name, struct path* path, const char args.monitored = is_monitored(&args.inode, bound_path, &args.parent_inode); if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - goto end; + return 0; } submit_mount_event(&args); - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/sb_umount") -int BPF_PROG(trace_sb_umount, struct vfsmount* mnt, int flags) { - bpf_preempt_disable(); +FACT_BPF_PROG2(sb_umount, struct vfsmount*, mnt, int, flags) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->sb_umount}; args.metrics->total++; @@ -631,7 +598,7 @@ int BPF_PROG(trace_sb_umount, struct vfsmount* mnt, int flags) { if (bound_path == NULL) { bpf_printk("Failed to read umount directory"); args.metrics->error++; - goto end; + return 0; } args.filename = bound_path->path; @@ -644,22 +611,17 @@ int BPF_PROG(trace_sb_umount, struct vfsmount* mnt, int flags) { args.monitored = is_monitored(&args.inode, bound_path, &args.parent_inode); if (args.monitored == NOT_MONITORED) { args.metrics->ignored++; - goto end; + return 0; } submit_umount_event(&args); - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/move_mount") -int BPF_PROG(trace_move_mount, struct path* from, struct path* to) { - bpf_preempt_disable(); +FACT_BPF_PROG2(move_mount, struct path*, from, struct path*, to) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } struct submit_event_args_t args = {.metrics = &m->move_mount}; @@ -687,7 +649,7 @@ int BPF_PROG(trace_move_mount, struct path* from, struct path* to) { if (args.monitored != MONITORED_BY_INODE) { args.metrics->ignored++; - goto end; + return 0; } // Ensure the new mount is tracked. @@ -696,23 +658,17 @@ int BPF_PROG(trace_move_mount, struct path* from, struct path* to) { } submit_move_mount_event(&args, from_path->path, &from_inode, from_monitored); - - goto end; + return 0; error: args.metrics->error++; - -end: - bpf_preempt_enable(); return 0; } -SEC("lsm/path_symlink") -int BPF_PROG(trace_path_symlink, struct path* dir, struct dentry* dentry, const char* old_name) { - bpf_preempt_disable(); +FACT_BPF_PROG3(path_symlink, struct path*, dir, struct dentry*, dentry, const char*, old_name) { struct metrics_t* m = get_metrics(); if (m == NULL) { - goto end; + return 0; } m->path_symlink.total++; @@ -735,13 +691,10 @@ int BPF_PROG(trace_path_symlink, struct path* dir, struct dentry* dentry, const goto error; } - goto end; + return 0; error: delete_d_instantiate_ctx(); m->path_symlink.error++; - -end: - bpf_preempt_enable(); return 0; } From 23710242ba7c42a69be073043676adc503704cc9 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Tue, 25 Aug 2026 12:35:12 +0200 Subject: [PATCH 3/3] fix(bpf): check bpf_preempt_enable/disable exist before call These kfuncs where added in kernel version 6.12 and causes verifier issues on RHCOS 4.16 and 4.18 on our CI. --- fact-ebpf/src/bpf/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index e125bff7..cf372197 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -38,9 +38,14 @@ char _license[] SEC("license") = "Dual MIT/GPL"; static __always_inline int _handle_##hook(__MAP(n, __CAT, args)); \ SEC("lsm/" STRINGIFY(hook)) \ int BPF_PROG(trace_##hook, __MAP(n, __CAT, args)) { \ - bpf_preempt_disable(); \ + if (bpf_ksym_exists(bpf_preempt_disable)) { \ + bpf_preempt_disable(); \ + } \ int res = _handle_##hook(__MAP(n, __ARG, args)); \ - bpf_preempt_enable(); \ + \ + if (bpf_ksym_exists(bpf_preempt_enable)) { \ + bpf_preempt_enable(); \ + } \ return res; \ } \ static __always_inline int _handle_##hook(__MAP(n, __CAT, args))