Bug Report
Affected Code
File: so/dkapture.cpp, line 388, function dkapture::fs_watch()
Description
When fs_watch() is called with a non-null path, the else branch calls trace_file_init() instead of mountsnoop_init(). This is a copy-paste error from file_watch().
int dkapture::fs_watch(const char *path, DKCallback cb, void *ctx)
{
if (!cb) return mountsnoop_deinit(); // ✓ correct
if (!path) return mountsnoop_init(1, ...); // ✓ correct
else return trace_file_init(3, ...); // ✗ BUG: should be mountsnoop_init
}
Why mountsnoop_init is Correct
fs_watch is supposed to monitor filesystem-level mount/umount events, not per-file I/O operations. The evidence comes from comparing what each function does at the BPF kernel level:
mountsnoop_init — Filesystem Event Monitoring
observe/mountsnoop.cpp:87 — The -p argument is stored as a path prefix:
strncpy(filter_path, arg, PATH_MAX);
bpf/observe/mountsnoop.bpf.c:36-42 — BPF map stores a char[4096] path string:
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(value, char[4096]);
} filter SEC(".maps");
bpf/observe/mountsnoop.bpf.c:44-60 — filter_path() does prefix matching on mount source/target paths:
static bool filter_path(const char *path, int n) {
char *rule_path = bpf_map_lookup_elem(&filter, &key);
if (!rule_path || rule_path[0] == '\0') return true;
if (!path) return false;
return strncmp(path, rule_path, n) == 0;
}
Monitored events (mountsnoop.bpf.c): mount, umount, fsopen, fsconfig, fsmount, move_mount, fspick, mount_setattr, open_tree — all filesystem-level syscalls.
trace_file_init — Per-File I/O Monitoring
observe/trace-file.cpp:1206-1212 — The -p argument is used to open()+fstat() the file, resolving it to an inode:
target_fd = open(rule.path, O_RDONLY);
fstat(target_fd, &statbuf);
rule.inode = statbuf.st_ino;
bpf/observe/trace-file.bpf.c:26-35 — BPF filter uses inode+dev for matching:
union Rule {
char path[PATH_MAX];
struct { u64 not_inode; u64 inode; dev_t dev; };
};
bpf/observe/trace-file.bpf.c:128-146 — find_file_inode resolves path to inode:
if (rule->not_inode) strncmp(path, rule->path, PATH_MAX); // path matching
else {
rule->dev != file->f_path.mnt->mnt_sb->s_dev; // device matching
rule->inode != BPF_CORE_READ(file, f_inode, i_ino); // inode matching
}
Monitored events (trace-file.bpf.c, 3749 lines): vfs_open, vfs_read, vfs_write, vfs_chmod, vfs_chown, vfs_removexattr — all per-file I/O operations.
Summary
|
trace_file_init |
mountsnoop_init |
| Monitors |
Single file (by inode) |
Filesystem mount/umount events |
-p semantics |
File path → inode lookup |
Path prefix for filtering mount source/target |
| BPF hooks |
fexit/vfs_open, vfs_read, vfs_write, ... |
tracepoint/.../sys_enter_mount, sys_enter_umount, ... |
Calling trace_file_init from fs_watch is semantically wrong — it would try to open the given path as a regular file, resolve its inode, and attach file I/O hooks, which is completely unrelated to filesystem event monitoring.
Bug Report
Affected Code
File:
so/dkapture.cpp, line 388, functiondkapture::fs_watch()Description
When
fs_watch()is called with a non-null path, the else branch callstrace_file_init()instead ofmountsnoop_init(). This is a copy-paste error fromfile_watch().Why
mountsnoop_initis Correctfs_watchis supposed to monitor filesystem-level mount/umount events, not per-file I/O operations. The evidence comes from comparing what each function does at the BPF kernel level:mountsnoop_init — Filesystem Event Monitoring
observe/mountsnoop.cpp:87— The-pargument is stored as a path prefix:bpf/observe/mountsnoop.bpf.c:36-42— BPF map stores achar[4096]path string:bpf/observe/mountsnoop.bpf.c:44-60—filter_path()does prefix matching on mount source/target paths:Monitored events (mountsnoop.bpf.c): mount, umount, fsopen, fsconfig, fsmount, move_mount, fspick, mount_setattr, open_tree — all filesystem-level syscalls.
trace_file_init — Per-File I/O Monitoring
observe/trace-file.cpp:1206-1212— The-pargument is used toopen()+fstat()the file, resolving it to an inode:bpf/observe/trace-file.bpf.c:26-35— BPF filter uses inode+dev for matching:bpf/observe/trace-file.bpf.c:128-146—find_file_inoderesolves path to inode:Monitored events (trace-file.bpf.c, 3749 lines):
vfs_open,vfs_read,vfs_write,vfs_chmod,vfs_chown,vfs_removexattr— all per-file I/O operations.Summary
-psemanticsfexit/vfs_open,vfs_read,vfs_write, ...tracepoint/.../sys_enter_mount,sys_enter_umount, ...Calling
trace_file_initfromfs_watchis semantically wrong — it would try to open the given path as a regular file, resolve its inode, and attach file I/O hooks, which is completely unrelated to filesystem event monitoring.