1. linux tracing system

785 阅读5分钟

1. 参考资料

Linux Tracing System浅析

2. linux tracing system简介

linux中的tracing系统可以对整个linux系统进行跟踪、嗅探、采样、剖析与可观测。具体可分为3层:

  • 前端工具/库:对接tracing内核框架,直接与用户交互,负责采集配置与数据分析
  • tracing内核框架:负责对接数据源,采集解析发送数据,并对用户态提供接口
  • 数据源:提供数据的来源

image.png

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来添加一个静态探针,然后在特定函数中进行调用。

fa9cc8959d72974e0f9359ac337787c.png

3.3.2 动态探针

在程序启动之后加入探针(kprobe/kretprobe、ftrace、fentry/fexit):

  1. 将在要插桩的目标地址中的内容复制并保存,给单步断点指令腾出位置;
  2. 以单步中断指令覆盖目标地址;
  3. 当指令流执行到断点时,断点处理函数会检查这个断电是否是由kprobes注册的。如果是,就会先执行kprobes处理函数;
  4. 原始的指令会接着执行,指令流继续;
  5. 当不再需要kprobes时,原始的字节内容会被复制回目标地址上,这样这些指令就回到了它们的初始状态。

5102ef8ec29b3f57c39fdc18676b3e0.png

静态探针动态探针
优点1.稳定2.性能好1.可以hook几乎所有的内核函数
缺点1.需要修改内核代码来添加新的静态探针
2.内核支持的静态探针数量有限
1.不稳定,修改出现错误风险很大
2.为了安全性有一些代价,性能相对较差

优先使用静态探针。

3.3.3 ftrace

目前来讲有两层含义,一是提供函数探针的基础设施,二是基于tracefs文件系统的trace框架。包括了静态探针与动态探针。

  • tracepoint/trace event:函数执行时调用静态探针;
  • function tracer:在函数头挂动态探针;
  • function graph tracer:可以带时间戳函数执行流打印;
  • kprobe:一般是挂在函数入口点,用于获取参数;
  • kretprobe:通常是挂在函数出口点,执行探针。

image.png

function tracer原理:

  • 内核未开启ftrace功能时,对内核无影响;
  • 内核开启ftrace功能,未开启function tracer时,在每个函数执行前添加5个nop指令;
  • 内核编译开启ftrace功能时,也开启了function tracer跟踪某个函数,则会将nop指令动态替换成探针函数,执行完探针再执行原有的代码逻辑。

60f4b969fcce0f771266527b2925bd9.png

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中的地址,返回继续执行原有的路径。

b57e427b6efc38bb337884959d5bfee.png

原本的入口处插入探针,只能追踪到函数的切换。现在入口、出口同时插入探针,还能获得函数的执行时长,做更多的分析。

3.3.4 audit hooks

独立于kprobe、tracepoint之外的数据源,它通过在syscall和文件操作等内核源代码上插入自定义的hook函数来实现syscall和文件行为的监控。相比较其他技术,性能非常差。

4. tracing框架

linux tracing system 3层结构之间的关系:一个tracing框架是可以对接多个数据源的,为了适用不同的场景,一个tracing框架可能有多个前端工具/库。

8b82ec9e3f4ddcc86083621c77271b0.png

其中eBPF可以基于hardware events、tracepoint、kprobe/kretprobe、fentry/fexit的数据源进行进行数据采集。

tracing框架对比:

image.png

eBPF的优势:

  • 稳定:通过验证器,防止用户编写的程序导致内核崩溃
  • 免安装:eBPF内置于linux内核,无需安装额外以来
  • 内核编程:支持开发者插入自定义的代码逻辑(包括数据采集、分析和过滤)到内核中运行