ptrace+Seccomp追踪CLONE_THREAD线程时wait()挂死问题
ptrace结合Seccomp追踪多线程程序时挂死、无法捕获线程系统调用问题
问题背景
- 追踪器实现逻辑:基于ptrace实现进程及其子进程追踪,搭配可向ptrace发送通知的Seccomp过滤器完成特定系统调用的捕获打印,方案参考公开技术博文实现,常规单线程/多进程场景下运行正常。
- 故障表现:追踪default-jre提供的Java程序时,追踪器与目标进程共同挂死。排查确认故障触发点为目标进程使用
CLONE_THREAD标志调用clone()创建线程后,追踪器无法接收到新创建线程发送的信号。 - 初步原理判断:根据相关技术讨论,使用
CLONE_THREAD标志创建的子任务归属原进程的线程组,不会成为原进程的独立子进程,因此常规的子进程追踪逻辑无法覆盖这类线程。
问题复现与验证
- 测试程序复现:编写简易测试程序,调用
clone()传入指定标志执行业务逻辑。对照clone()官方手册说明,Linux 2.6.0及以上版本使用CLONE_THREAD时必须搭配CLONE_THREAD | CLONE_SIGHAND | CLONE_VM标志组合,该标志组合下两个线程任意一个结束前可被正常追踪,但无法通过常规子进程追踪逻辑实现两个线程的独立追踪。 - 标志位排查:抓取Java程序的clone调用strace日志,确认JVM的clone标志使用完全符合规范;逐一排除
CLONE_FS | CLONE_FILES | CLONE_SYSVSEM等非线程相关标志的影响,测试多组CLONE_THREAD相关标志组合,分别复现出仅能捕获父线程追踪数据、父子线程追踪行为不一致的问题,和Java场景下的故障表现完全一致。 - 复现操作步骤:
- 追踪器代码编译:
g++ tracer.cpp -o tracer -g -lseccomp -lexplain - 测试样例程序编译:
gcc sample.c -o sample - 故障复现:执行
./tracer ./sample或./tracer java,即可复现追踪器与目标进程共同挂死的现象。
- 追踪器代码编译:
- 核心疑问:strace可成功追踪所有类型的clone调用,查阅strace源码未定位到对应实现逻辑,需要在不修改目标Java程序的前提下解决该追踪故障。
根因分析与解决方案
根因
- 初始示例追踪器代码存在逻辑缺陷,未实现子线程信号的处理逻辑。
- 原业务侧ptrace附加逻辑存在遗漏:在目标进程启动后才执行ptrace附加,且仅附加了
pstree列出的进程PID,完全遗漏了Java程序创建的所有线程。
修复方案
调整ptrace附加逻辑:附加主进程后,通过命令ps -L -g <Main_PID> -o tid=获取该进程下所有子进程、线程的ID,对所有ID逐一执行ptrace附加操作。修改完成后追踪功能恢复正常,可完整捕获JVM等多线程程序的目标系统调用,不再出现挂死问题。
内容的提问来源于stack exchange,提问作者DirtyC0wBoy
相关产品推荐
相关产品推荐

