本页目录
ptrace 与调试接口
覆盖: ptrace(PTRACE_ATTACH/PTRACE_SYSCALL/PTRACE_PEEKDATA/PTRACE_GETREGS) → strace/gdb 实现原理 → /proc/pid/mem → seccomp user notify 适用: Linux 用户态, x86-64/ARM64
概述
ptrace 是 Unix 最古老的调试接口——它允许一个 tracer 进程完全控制 tracee 进程。gdb(断点、单步、寄存器读写)、strace(系统调用追踪)都是基于 ptrace 构建的。近年来出现了更高效的替代方案(/proc/pid/mem、seccomp user notify),但 ptrace 仍然是最通用的。
ptrace 核心操作
// 附加 (自己或别人):
; // tracee 声明"可以被 trace"
// 或
; // tracer 附加到 tracee
; // 附加但不停 (SEIZE, 3.4+)
// 控制:
; // 继续执行 (可选注信号)
; // syscall entry + exit 都停
; // 单步执行一条指令
// 读写:
; // 读 tracee 内存 (word at a time)
; // 写 tracee 内存
; // 读寄存器
; // 写寄存器
// 分离:
;
strace 原理
// strace 的核心逻辑 (简化):
// 1. fork 子进程
pid = ;
if
// 2. 父进程 (tracer):
; // 等第一个 stop (execve 之后的 SIGTRAP)
while
每次 syscall entry/exit 都经过: tracer → PTRACE_SYSCALL → waitpid → GETREGS → PTRACE_SYSCALL → waitpid → GETREGS。这就是 strace 开销大的根源——每个被追踪的系统调用要 4 次上下文切换(tracee→tracer→tracee→tracer)。
gdb 原理
断点:
gdb 用 PTRACE_PEEKDATA 读断点位置的指令 → 保存
用 PTRACE_POKEDATA 把该位置替换为 INT3 (0xCC)
执行到 INT3 → SIGTRAP → tracer 被通知 (waitpid)
tracer 恢复原始指令 → 单步或继续
单步:
PTRACE_SINGLESTEP → CPU 执行 1 条指令 → SIGTRAP → tracer
寄存器读写:
PTRACE_GETREGS / PTRACE_SETREGS
内存读写:
PTRACE_PEEKDATA / PTRACE_POKEDATA (慢, per-word)
/proc/pid/mem: 更高效 (pread/pwrite, 任意大小)
/proc/pid/mem: ptrace 的替代
// 不需要 ptrace ATTACH → 读/写 tracee 的虚拟内存
// 但需要 ptrace ATTACH 才能写非 rw 区域 (5.x+ 之前)
// 5.x+: process_vm_readv/writev 更高效 (不需要打开 /proc/pid/mem)
int memfd = ;
; // 读 tracee 地址 addr
; // 写 tracee 地址 addr
seccomp user notify: "新时代的 ptrace"
// SECCOMP_RET_USER_NOTIF: seccomp filter 把 syscall 通知给监督进程
// 监督进程可以检查/修改/批准/拒绝 → 不需要 ptrace (开销低很多)
// ptrace 的问题:
// 所有 syscall 都 stop → tracer → tracee (即使不关心的 syscall)
// seccomp user notify:
// 只拦截 seccomp filter 匹配的 syscall → 其他不受影响
// → ptrace 的开销是 O(所有 syscall), seccomp 是 O(关心的)
调试器限制
1. 一个进程只能有 1 个 tracer (多个 strace 不行)
2. PTRACE_TRACEME 后的进程不能 setuid (安全限制)
3. 不能 trace init (PID 1)
4. Yama LSM: /proc/sys/kernel/yama/ptrace_scope 限制谁可以 trace
0: 任何人可以 trace 任何人 (宽松)
1: 只能 trace 自己或后代 (默认)
2: 只能 trace 后代 (admin override)
3: 完全禁止 ptrace
参考
- man: ptrace(2)
- 源码:
kernel/ptrace.c,kernel/seccomp.c - LWN: "Better ptrace", "Seccomp user-space notification"
关键词: ptrace, PTRACE_ATTACH, PTRACE_SYSCALL, PTRACE_SINGLESTEP, PTRACE_PEEKDATA, strace, gdb, /proc/pid/mem, seccomp user notify, Yama