1. 参考资料
2. linux tracing system简介
linux中的tracing系统可以对整个linux系统进行跟踪、嗅探、采样、剖析与可观测。具体可分为3层:
- 前端工具/库:对接tracing内核框架,直接与用户交互,负责采集配置与数据分析
- tracing内核框架:负责对接数据源,采集解析发送数据,并对用户态提供接口
- 数据源:提供数据的来源
3. 数据源
3.1 探针
在事件执行路径上插入钩子函数,当事件执行时会跳转到钩子函数执行,再返回事件执行。
3.2 硬件探针
在硬件层面上实现的探针,比如在译码指令处添加一个计数(HPC)
-
Hardware Performance Counter(HPC):是CPU硬件提供的功能,它能够监控CPU级别的事件,比如执行的指令数,跳转的指令数,Cache Miss等等,被广泛应用于性能调试、攻击检测。
-
Last Branch Record(LBR):是CPU硬件提供的另一种特性,它能够记录每条分支(跳转)指令的源地址和目的地址。基于LBR硬件特性,可实现调用栈信息的记录。
3.3 软件探针
3.3.1 静态探针
在程序运行之前把探针加进去(tracepoint、ftrace、audit hooks),类似于在内核中加入一个printk的打印。内核开发者在内核函数中的特定逻辑位置处,有意放置了这些探针点,然后这些探针点会被编译到内核的二进制文件。内核中有专门的宏TRACE_EVENT来添加一个静态探针,然后在特定函数中进行调用。
3.3.2 动态探针
在程序启动之后加入探针(kprobe/kretprobe、ftrace、fentry/fexit):
- 将在要插桩的目标地址中的内容复制并保存,给单步断点指令腾出位置;
- 以单步中断指令覆盖目标地址;
- 当指令流执行到断点时,断点处理函数会检查这个断电是否是由kprobes注册的。如果是,就会先执行kprobes处理函数;
- 原始的指令会接着执行,指令流继续;
- 当不再需要kprobes时,原始的字节内容会被复制回目标地址上,这样这些指令就回到了它们的初始状态。
静态探针 | 动态探针 | |
---|---|---|
优点 | 1.稳定2.性能好 | 1.可以hook几乎所有的内核函数 |
缺点 | 1.需要修改内核代码来添加新的静态探针 2.内核支持的静态探针数量有限 | 1.不稳定,修改出现错误风险很大 2.为了安全性有一些代价,性能相对较差 |
优先使用静态探针。
3.3.3 ftrace
目前来讲有两层含义,一是提供函数探针的基础设施,二是基于tracefs文件系统的trace框架。包括了静态探针与动态探针。
- tracepoint/trace event:函数执行时调用静态探针;
- function tracer:在函数头挂动态探针;
- function graph tracer:可以带时间戳函数执行流打印;
- kprobe:一般是挂在函数入口点,用于获取参数;
- kretprobe:通常是挂在函数出口点,执行探针。
function tracer原理:
- 内核未开启ftrace功能时,对内核无影响;
- 内核开启ftrace功能,未开启function tracer时,在每个函数执行前添加5个nop指令;
- 内核编译开启ftrace功能时,也开启了function tracer跟踪某个函数,则会将nop指令动态替换成探针函数,执行完探针再执行原有的代码逻辑。
function graph tracer原理:
- 内核未开启ftrace功能时,对内核无影响;
- 内核开启ftrace功能,未开启function tracer时,在每个函数执行前添加5个nop指令;
- 内核编译开启ftrace功能时,也开启了function tracer跟踪某个函数func,则会将func及其子函数内的nop指令均动态替换成探针函数。与function tracer不同的是,在入口探针函数被调用时,修改了func的返回地址,不是返回到func’s parent()函数继续去执行,而是返回到reurn桩函数return_to_handler()中。return_to_handler()中执行完自己的return处理函数以后,再把返回地址恢复成func’s parent中的地址,返回继续执行原有的路径。
原本的入口处插入探针,只能追踪到函数的切换。现在入口、出口同时插入探针,还能获得函数的执行时长,做更多的分析。
3.3.4 audit hooks
独立于kprobe、tracepoint之外的数据源,它通过在syscall和文件操作等内核源代码上插入自定义的hook函数来实现syscall和文件行为的监控。相比较其他技术,性能非常差。
4. tracing框架
linux tracing system 3层结构之间的关系:一个tracing框架是可以对接多个数据源的,为了适用不同的场景,一个tracing框架可能有多个前端工具/库。
其中eBPF可以基于hardware events、tracepoint、kprobe/kretprobe、fentry/fexit的数据源进行进行数据采集。
tracing框架对比:
eBPF的优势:
- 稳定:通过验证器,防止用户编写的程序导致内核崩溃
- 免安装:eBPF内置于linux内核,无需安装额外以来
- 内核编程:支持开发者插入自定义的代码逻辑(包括数据采集、分析和过滤)到内核中运行