Skip to content

fix: fs_watch calls trace_file_init instead of mountsnoop_init with path argument - #112

Open
JoeSergen wants to merge 1 commit into
DKapture:mainfrom
JoeSergen:fix/fs-watch-wrong-init
Open

fix: fs_watch calls trace_file_init instead of mountsnoop_init with path argument#112
JoeSergen wants to merge 1 commit into
DKapture:mainfrom
JoeSergen:fix/fs-watch-wrong-init

Conversation

@JoeSergen

@JoeSergen JoeSergen commented Jul 25, 2026

Copy link
Copy Markdown

Summary

Fix copy-paste bug in so/dkapture.cpp where fs_watch() called trace_file_init() instead of mountsnoop_init() in its path-specific else branch.

Root Cause

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
}

This is a copy-paste error from file_watch(). The developer correctly changed the deinit and null-path branches to mountsnoop_*, but the else branch was missed.

Why mountsnoop_init is Correct

fs_watch monitors filesystem-level mount/umount events, not per-file I/O. Evidence from the BPF kernel side:

mountsnoop_init — Filesystem Event Monitoring

User-space (observe/mountsnoop.cpp): The -p argument is stored as a path prefix and written to a BPF char[4096] array map.

Kernel-space (bpf/observe/mountsnoop.bpf.c:44-60): filter_path() performs path prefix matching against 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: sys_enter_mount, sys_enter_umount, fsopen, fsmount, move_mount, etc. — all filesystem-level syscalls.

trace_file_init — Per-File I/O Monitoring

User-space (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;

Kernel-space (bpf/observe/trace-file.bpf.c:128-146): find_file_inode matches by inode+dev:

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: vfs_open, vfs_read, vfs_write, vfs_chmod, vfs_chown, vfs_removexattr — all per-file I/O operations.

Semantic Mismatch

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_* file ops tracepoint/.../sys_enter_mount etc.

Calling trace_file_init from fs_watch would open the given path as a regular file, resolve its inode, and attach VFS-level file I/O hooks — completely unrelated to filesystem event monitoring.

Changes

  • so/dkapture.cpp:388: Changed trace_file_init to mountsnoop_init (1 line)

Verification

  • Both functions have identical signatures: int(int argc, char** argv, DKCallback cb, void* ctx)
  • No ABI changes, no header changes, no build dependency changes

Closes #111

…ath argument

When fs_watch() is called with a non-null path, the else branch
incorrectly calls trace_file_init() instead of mountsnoop_init().
This is a copy-paste error from file_watch(). The correct behavior
is to initialize mountsnoop for filesystem event monitoring.

Signed-off-by: JoeSergen <jxq142857@163.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: fs_watch calls trace_file_init instead of mountsnoop_init with path argument

1 participant