Skip to content

fix(lsof): start ringbuf consumer before iterator scan - #125

Open
yuKing123-king wants to merge 1 commit into
DKapture:mainfrom
yuKing123-king:fix/lsof-ringbuf-consume-timing
Open

yuKing123-king wants to merge 1 commit into
DKapture:mainfrom
yuKing123-king:fix/lsof-ringbuf-consume-timing

Conversation

@yuKing123-king

@yuKing123-king yuKing123-king commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

本次修改主要是修复了ringbuffer消耗不及时这个问题

由于起tail和vma占用文件只能最多起大概3000左右个进程,但是在bpf程序中,logs map的最大条目数却是256 * 1024 远远大于进程数,所以体现不出来ringbuffer消耗不及时这个问题。我将logs map的最大条目数从256 * 1024改成2 * 1024后,当启动1500个占用文件的进程后,lsof这个工具就会出现丢统计的情况。如下所示:

一、现象

  1. 下面是起了1500个tail和vma进程占用文件
1
  1. 原lsof只统计到了102个tail进程占用文件,修复后的lsof统计到了1500个tail进程
tail

3.原lsof只统计到了0个vma进程占用文件,修复后的lsof统计到了1500个vma进程
vma

二、作出的修改

  1. 原因

出现统计不及时的原因是先 bpf_iter_create(bpf_link__fd(obj->links.vma_iterator))bpf_iter_create(bpf_link__fd(obj->links.file_iterator)),后 pthread_create(&t1, NULL, ringbuf_worker, NULL),这就导致了先进行统计生产后,再统一进行消费,如果同时有很多进程占用文件,超过 logs map 的最大条目数就会出现统计错误和报错。

  1. 修改

pthread_create(&t1, NULL, ringbuf_worker, NULL) 放在 bpf_iter_create(bpf_link__fd(obj->links.vma_iterator))bpf_iter_create(bpf_link__fd(obj->links.file_iterator)) 之前启动这个线程,就可以边生产边消费。同时我将 void *ringbuf_worker(void *) 这个的退出条件,从 if (err == 0 && iter_fd == -1) 换成使用 scan_done 这个更明确的状态变更。

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit 3a41602)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@yuKing123-king
yuKing123-king force-pushed the fix/lsof-ringbuf-consume-timing branch from ba47f8c to 0c8163f Compare August 17, 2026 06:27
@yuKing123-king

Copy link
Copy Markdown
Contributor Author

/review 检视一下当前提交的PR,代码有无安全风险,和其他错误的地方

@github-actions

Copy link
Copy Markdown

Preparing review...

@dkapture-ci-bot

Copy link
Copy Markdown
Contributor

你好,这是对 libdkapture#125 fix(lsof): start ringbuf consumer before iterator scan 的评审。

本轮为 DKapture 两仓(libdkapture / dkapture-bpf)全部以 fix 开头 open PR 的批量评审,共 17 个;汇总表如下,本 PR 加粗。逐项详评见分隔线下方。

PR 标题 作者 规模 结论 主要风险
#149 fix(net-traffic): initialize rules before loadin yuKing123-king +19/-9 可合并 规则安装顺序与其它工具约定不一致;本仓改动无正确性缺陷
#147 fix(net-filter): abort rule loading on invalid c yuKing123-king +9/-3 需修改 失败时 clear_rules() 波及 add_rule() 装入的规则;空白注释行导致整个加载失败
#141 fix(dkapture): honor parsed pid in read(vector<p JoeSergen +23/-2 需修改 unsafe_find 单记录语义使 /proc//fd 只回调一次;返回值语义漂移
#140 fix(dkapture): return bytes read, not remaining JoeSergen +10/-4 可合并 无阻塞风险;与文档契约对齐,仓内无调用方依赖旧语义
#114 fix: replace manual destructor calls in construc JoeSergen +28/-7 需修改 捆绑了与 open PR #112 逐字节相同的 fs_watch 修复,跨 PR 重复
#125 fix(lsof): start ringbuf consumer before iterato yuKing123-king +17/-3 需修改 线程启动后错误路径仍 goto err_out → 释放运行中 rb(UAF)+ 线程泄漏
#112 fix: fs_watch calls trace_file_init instead of m JoeSergen +1/-1 可合并 无;仅修一处复制粘贴错误
#103 fix: make power-snoop internal symbols static fo yuKing123-king +3/-2 可合并 改动无害;但 PR 描述的 multiple definition 在当前构建配置下无法复现
#119 fix(syscall-stat): stop skipping syscall key 0 d yuKing123-king +18/-6 可合并 循环终止四条路径已逐一核实;缩进与提交拆分小问题
#115 fix(syscall-stat): improve builtin flow yuKing123-king +204/-41 需修改 三处 bpf_get_map_fd 错误路径未设 ret,最终 return ret 误报成功
#117 fix(trace-signal): validate invalid command line yuKing123-king +190/-29 需修改 BUILTIN 测试入口未接入 test/Makefile,不可达;register_signal 残留
#102 fix(trace-exec): reject invalid command line arg yuKing123-king +135/-22 需修改 BUILTIN 入口同样未接入构建;-h 退出码 0→1 属未说明的行为变更
#97 fix(so): reuse pinned dkapture bpf objects corre yuKing123-king +1/-1 需修改 test mock 仍按 map- 前缀命名 pin,合并后 gtest FindMap 用例失败
#35 fix(pagefault): add max_entries and value_size f yuKing123-king +7/-3 可合并 修复真实,但已被 main 上等效修复 1e90486 取代,建议确认后关闭
#32 fix(peek-fd): correct args field name from mvlen yuKing123-king +1/-1 可合并 无功能风险;标题/描述与实际改动方向不符
#30 fix(trace-signal): avoid inflight event key coll yuKing123-king +36/-22 需修改 sys_exit_kill 的 !rule 早退路径仍泄漏 inflight 条目
#29 fix(syscall-stat): replace exec fexit with kprob yuKing123-king +93/-13 阻塞 exec 路径从 struct filename* 本身读字符串,-f 过滤将完全失效

本 PR 评审详情

作者: yuKing123-king | 规模: +17/-3 | 文件: 1
结论: 需修改
主要风险: worker 线程启动后的错误路径仍跳 err_out,会在 worker 仍在 ring_buffer__poll 时释放 rb(use-after-free)并泄漏线程。

总体结论: 将 ringbuf 消费线程提前到 iterator 扫描之前启动,并用独立原子标志 scan_done 替代旧的 iter_fd==-1 判断扫描结束,方向正确,能消除原 TODO 注明的"扫描期间 ringbuf 无人消费导致丢事件"竞态。但新增的 stop_worker 清理标签没有任何 goto 跳转(死代码),而 pthread_create 之后两处 iterator 创建失败路径仍直接 goto err_out,构成 UAF + 线程泄漏。

主要问题:

  • (P1) observe/lsof.cpp:305,317 (新) — pthread_create(&t1,...)(:299 新)之后,file_iterator / vma_iterator 创建失败仍 goto err_out(补丁后逐行核对);err_out(:344-347 仓库行号)执行 ring_buffer__free(rb),此时 ringbuf_worker 可能正阻塞在该 rb 的 ring_buffer__poll 上 → use-after-free;且 t1 从未 join,线程不可回收。两处应改为 goto stop_worker
  • (P2) observe/lsof.cpp:334-341 (新) — stop_worker: 标签无任何 goto 引用(死代码,-Wall 下触发 unused-label 告警,observe/Makefile CFLAGS 含 -Wall);该块缩进混用空格与 Tab( \tscan_done = true;、四空格行),违反 .clang-format(IndentWidth: 4,仓库其余代码用 Tab)。

次要建议:

  • observe/lsof.cpp:298 (新) — scan_done = false; 冗余(静态初始化即 false),可删或注明防御意图。
  • observe/lsof.cpp:299 (新) — pthread_create 返回值未检查,失败时后续 pthread_join(t1) 为 UB(延续原有模式,建议顺手检查)。

亮点:

  • 用显式 scan_done 原子标志表达"扫描已完成",比复用 iter_fd 哨兵值语义清晰;stop_worker 统一错误清理的意图值得肯定(只是尚未接线)。

commit message: 标题符合 fix(lsof): 规范,但无正文;仓库近期 fix 提交(如 fix(switch_count)、fix(net-filter) 系列)均附根因说明正文,建议补充。

已有讨论: PR 下有 3 条 issue 评论:PR-Agent bot 评审(针对旧版本,指出两次 pthread_create 覆盖 t1 导致线程泄漏、第二个 worker 启动时 scan_done 已为 true 会过早退出)+ 作者发起 /review 的请求 + bot 的 Preparing review 占位。当前单 commit head 已消除 bot 指出的"第二次 pthread_create"问题;但 bot 指出的线程泄漏本质(错误路径不回收线程)在 head 上以新形式仍然存在,为本评审增量意见的核心。

Signed-off-by: Wang Yu <wangyu6@uniontech.com>
@github-actions

Copy link
Copy Markdown

Persistent review updated to latest commit 3a41602

@dkapture-ci-bot

Copy link
Copy Markdown
Contributor

增量复审(第二轮):本 PR 在上轮评审(2026-09-15 上轮评论)后更新了 head(0c8163f → 3a41602,+17/-3 → +23/-5)。以下为增量结论;总体汇总表与逐项详评见上条评论。

复审结论:可合并

上轮问题的核实

  • (P1) pthread_create 之后的 iterator 创建失败路径仍 goto err_out,会对运行中 worker 正在 poll 的 rb 执行 ring_buffer__free(use-after-free)并泄漏线程 —— 已正确解决。 两处 iterator 创建失败均已改为 goto stop_worker(observe/lsof.cpp:306、:322 附近,(新));stop_worker: 现在被实际引用:关闭 iter_fd → scan_done = trueexit_flag = truepthread_join(t1),随后自然落入 err_out。此时 worker 已退出并被回收,err_out 中的 ring_buffer__free(rb) 安全,上轮的死代码标签与 UAF 同时消除。
  • 次要 pthread_create 返回值未检查 —— 已解决:失败时打印 strerror 并 goto err_out(此时尚无线程,err_out 路径安全)。原冗余的 scan_done = false; 也已按建议移除(静态初始化即 false)。

本轮新发现(均为次要/风格,不阻塞)

  • 风格: stop_worker: 块内三行仍混用空格与 tab( \tscan_done = true;、四空格的 exit_flag/pthread_join 行),与上轮指出的同类问题,建议 clang-format 统一。
  • 风格: fprintf(stderr,"Error creating ringbuf worker: ... 逗号后缺空格。
  • 确认无误: 正常路径 scan_done = true → follow_trace_pipe → pthread_join → goto err_out,与错误路径共用清理;无双 join、无重复释放。

commit message

单 commit(amend),标题符合 fix(lsof) 规范;正文仍缺根因说明(上轮已提,可选)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants