问题描述
so/dkapture.cpp 中 dkapture::fs_watch() 函数存在复制粘贴错误:当 path 参数非空时,else 分支(第 388 行)调用了 trace_file_init(),而不是 mountsnoop_init(),导致启动了一个完全无关的 BPF 程序(文件事件追踪),而非预期的挂载事件监控。
问题位置
- 文件:
so/dkapture.cpp
- 函数:
dkapture::fs_watch()
- 行号: 第 388 行
问题代码
// so/dkapture.cpp 第 370-390 行
int dkapture::fs_watch(const char *path, DKCallback cb, void *ctx)
{
if (!cb)
{
return mountsnoop_deinit(); // ✅ 正确:使用 mountsnoop
}
if (path == nullptr || path[0] == 0)
{
char *arg0 = (char *)"dkapture";
char *args[] = {arg0, 0};
return mountsnoop_init(1, args, cb, ctx); // ✅ 正确:使用 mountsnoop
}
else
{
char *arg0 = (char *)"dkapture";
char *arg1 = (char *)"-p";
char *arg2 = (char *)path;
char *args[] = {arg0, arg1, arg2, 0};
return trace_file_init(3, args, cb, ctx); // ❌ 错误:应为 mountsnoop_init
}
}
分析过程
1. API 定义确认
bpf/export/dkapture.h 第 303-319 行对 fs_watch 的定义:
@brief 文件系统事件监控
@param path 挂载点路径,或文件系统所在分区设备路径
如果 mount /dev/sda1 /mnt,则 path 可以是 /mnt 或 /dev/sda1。
指定路径为 null,则监控所有文件系统挂/卸载事件。
该函数的职责明确是监控 mount/umount 事件,应始终使用 mountsnoop_* 系列函数。
2. 三个分支一致性分析
| 分支 |
条件 |
实际调用 |
预期调用 |
是否正确 |
| deinit |
cb == nullptr |
mountsnoop_deinit() |
mountsnoop_deinit() |
✅ |
| 无路径 |
path 为空 |
mountsnoop_init(1, ...) |
mountsnoop_init(1, ...) |
✅ |
| 有路径 |
path 非空 |
trace_file_init(3, ...) |
mountsnoop_init(3, ...) |
❌ |
三个分支中两个正确使用 mountsnoop_*,唯独 else 分支使用了 trace_file_init,明显不一致。
3. mountsnoop_init 对 -p 参数的支持确认
observe/mountsnoop.cpp 中 -p 参数的处理逻辑:
// 第 82-87 行:解析 -p 参数,存入 filter_path
case 'p':
memset(filter_path, 0, PATH_MAX);
strncpy(filter_path, arg, PATH_MAX);
break;
// 第 532-533 行:将 filter_path 写入 BPF map,用于内核侧过滤
DEBUG(0, "filter path: %s", filter_path);
bpf_map_update_elem(filter_map_fd, &key, filter_path, BPF_ANY);
mountsnoop_init 完全支持通过 -p <path> 进行路径过滤,且函数签名与当前调用方式兼容。
4. 复制粘贴来源确认
对比上方的 file_watch() 函数(第 323-344 行):
int dkapture::file_watch(const char *path, DKCallback cb, void *ctx)
{
if (cb == nullptr) { return trace_file_deinit(); }
if (path == nullptr || path[0] == 0)
{
// ...
return trace_file_init(1, args, cb, ctx);
}
else
{
// ...
return trace_file_init(3, args, cb, ctx); // ← else 分支被复制到 fs_watch
}
}
fs_watch() 的 else 分支与 file_watch() 的 else 分支结构完全相同,是从 file_watch() 复制后忘记将 trace_file_init 改为 mountsnoop_init。
触发条件
调用 fs_watch() 时传入非空的 path 参数,例如:
dk->fs_watch("/mnt", my_callback, my_ctx);
// 或
dk->fs_watch("/dev/sda1", my_callback, my_ctx);
当 path 为 nullptr 或空字符串时不会触发此问题。
预期行为
fs_watch("/mnt", cb, ctx) 应调用 mountsnoop_init(3, args, cb, ctx),启动 mountsnoop BPF 程序,监控挂载点 /mnt 相关的 mount/umount 系统调用事件,并通过回调 cb 返回 FsLog 类型数据。
实际行为
fs_watch("/mnt", cb, ctx) 错误调用了 trace_file_init(3, args, cb, ctx),导致:
- 功能完全错误:启动的是文件事件追踪(trace-file)BPF 程序,而非挂载事件监控(mountsnoop),不会捕获任何 mount/umount 事件。
- 资源清理错乱:后续调用
fs_watch(nullptr, nullptr, nullptr) 停止监控时,执行的是 mountsnoop_deinit(),无法正确清理 trace_file 实例,造成资源泄漏。
- 回调数据类型不匹配:
trace_file 返回的是 FileLog 类型数据,而 fs_watch 的用户期望的是 FsLog 类型数据。
建议修复
--- a/so/dkapture.cpp
+++ b/so/dkapture.cpp
@@ -385,7 +385,7 @@
char *arg1 = (char *)"-p";
char *arg2 = (char *)path;
char *args[] = {arg0, arg1, arg2, 0};
- return trace_file_init(3, args, cb, ctx);
+ return mountsnoop_init(3, args, cb, ctx);
}
}
问题描述
so/dkapture.cpp中dkapture::fs_watch()函数存在复制粘贴错误:当path参数非空时,else 分支(第 388 行)调用了trace_file_init(),而不是mountsnoop_init(),导致启动了一个完全无关的 BPF 程序(文件事件追踪),而非预期的挂载事件监控。问题位置
so/dkapture.cppdkapture::fs_watch()问题代码
分析过程
1. API 定义确认
bpf/export/dkapture.h第 303-319 行对fs_watch的定义:该函数的职责明确是监控 mount/umount 事件,应始终使用
mountsnoop_*系列函数。2. 三个分支一致性分析
cb == nullptrmountsnoop_deinit()mountsnoop_deinit()path为空mountsnoop_init(1, ...)mountsnoop_init(1, ...)path非空trace_file_init(3, ...)mountsnoop_init(3, ...)三个分支中两个正确使用
mountsnoop_*,唯独 else 分支使用了trace_file_init,明显不一致。3. mountsnoop_init 对
-p参数的支持确认observe/mountsnoop.cpp中-p参数的处理逻辑:mountsnoop_init完全支持通过-p <path>进行路径过滤,且函数签名与当前调用方式兼容。4. 复制粘贴来源确认
对比上方的
file_watch()函数(第 323-344 行):fs_watch()的 else 分支与file_watch()的 else 分支结构完全相同,是从file_watch()复制后忘记将trace_file_init改为mountsnoop_init。触发条件
调用
fs_watch()时传入非空的path参数,例如:当
path为nullptr或空字符串时不会触发此问题。预期行为
fs_watch("/mnt", cb, ctx)应调用mountsnoop_init(3, args, cb, ctx),启动 mountsnoop BPF 程序,监控挂载点/mnt相关的 mount/umount 系统调用事件,并通过回调cb返回FsLog类型数据。实际行为
fs_watch("/mnt", cb, ctx)错误调用了trace_file_init(3, args, cb, ctx),导致:fs_watch(nullptr, nullptr, nullptr)停止监控时,执行的是mountsnoop_deinit(),无法正确清理trace_file实例,造成资源泄漏。trace_file返回的是FileLog类型数据,而fs_watch的用户期望的是FsLog类型数据。建议修复