探索Trail of Bits的eBPF库套件:简化高效监控与追踪

Trail of Bits开发了一套开源eBPF库,包括linuxevents、ebpfpub、btfparse和ebpf-common,用于简化eBPF应用创建和部署,支持进程监控、函数追踪、内核调试符号解析和eBPF代码生成,兼容多种Linux发行版和内核版本。

使用我们的eBPF库套件

Trail of Bits开发了一套开源库,旨在简化eBPF应用程序的创建和部署。这些库促进了高效的进程和网络事件监控、函数追踪、内核调试符号解析以及eBPF代码生成。

以前,由于Linux内核版本差异以及需要外部工具进行C到eBPF字节码转换,部署便携、无依赖的eBPF应用程序面临重大挑战。我们通过创新的库解决了这些问题,这些库使用最新的eBPF和Linux内核功能来减少外部依赖。这些工具非常适合创建机上代理和启用云原生监控,积极维护,并与各种Linux发行版和内核版本兼容。一些甚至作为osquery(著名的端点可见性框架)功能的核心部分。

我们的eBPF库

此套件中的库包括linuxevents、ebpfpub、btfparse和ebpf-common。它们可以一起用于开发具有高度准确性和效率的简化事件监控。它们的应用范围从网络事件监控、函数追踪、内核调试符号解析到协助生成和使用eBPF代码。

linuxevents:一个容器感知的进程监控库,无运行时依赖

linuxevents库展示了eBPF如何监控事件,而无需准确的内核头文件或其他外部依赖。不再需要提供内核头文件、预编译eBPF字节码的多个副本或依赖BCC!linuxevents库支持运行时代码生成,在运行时创建自定义探针,而不仅仅在构建时。它也比传统的基于系统调用的钩子快得多,这是在单台机器上监控来自多个容器的事件时的关键特性。

linuxevents如何做到这一点?

首先,linuxevents使用Linux内核的BTF调试数据(通过我们的btfparse库)来准确识别函数原型和内核数据结构。这允许linuxevents自动调整数据结构布局的差异,并以大大简化追踪的方式钩住任意非公共符号。

这种方法比传统的基于系统调用的钩子更快,不仅因为它需要钩住更少的东西(sched_process_exec vs execve、execveat等),而且因为它可以避免昂贵的关联。例如,要追踪通过execve执行的磁盘上的程序,通常必须将传递给execve的文件描述符与open调用和多个chdir调用关联起来,以获取程序的完整路径。这种关联在计算上很昂贵,尤其是在具有多个活动容器的机器上。linuxevents库使用准确的内核数据结构表示,只钩住一个函数,并简单地从内核的vfs层提取路径。

linuxevents库仍是一个概念验证;它被osquery用作可切换的实验。该库还有一个追踪执行进程的规范示例,具有跨容器可见性。

ebpfpub:一个用于Linux的函数追踪库

ebpfpub库允许跨多个Linux内核版本监控系统调用,同时依赖最少的外部运行时依赖。在ebpfpub中,eBPF探针是从通过简单自定义语言定义的函数原型自动生成的,这些原型可以从追踪点描述符创建。这种方法需要运行内核的适当头文件,并带来性能损失,例如需要将文件描述符与系统调用匹配。

根据所需的目标事件,ebpfpub可以使用内核追踪点、kprobes或uprobes作为底层追踪机制。该库包括以下示例:

  • execsnoop:展示如何使用Linux内核追踪点通过execve()检测程序执行
  • kprobe_execsnoop:类似于execsnoop,但使用不同的钩子机制(kprobes而不是追踪点)
  • readline_trace:使用uprobes钩住用户模式readline库,可以启用用例,如监控机器上实时shell的使用
  • sockevents:一个示例,展示如何通过一系列connect/accept/bind调用来追踪套接字,建立与远程机器的连接
  • systemd_resolved:展示如何使用uprobes钩住systemd的DNS服务(systemd-resolved),实时显示本地机器正在查找的域

ebpfpub库目前被osquery用于通过追踪执行的系统调用来捕获进程和套接字事件。虽然ebpfpub仍在维护并在特定情况下有用(如需要支持旧内核和使用运行时代码生成),但新项目应改用linuxevents方法。

btfparse:一个解析BTF格式内核调试符号的C++库

BTF,或二进制类型格式,是一种紧凑的二进制格式,用于表示Linux内核中的类型信息。BTF存储结构、联合、枚举和typedef等数据。调试器和其他工具可以使用BTF数据通过理解复杂的C类型和表达式来启用更丰富的调试功能。BTF在Linux 4.20中引入,并从源代码和传统调试信息(如DWARF)生成。BTF比DWARF更紧凑,并通过传递比以前可用的更多语义类型信息来改善调试体验。标准化的BTF格式还允许新的调试工具跨编译器利用类型数据,实现跨语言更一致的内省质量。

btfparse库允许您在C++项目中读取BTF数据,并直接在内存中生成头文件,无需任何外部应用程序。该库还附带一个名为btf-dump的工具,既作为使用btfparse的示例,又作为可以转储Linux内核映像中存在的BTF数据的独立工具。

ebpf-common:一个帮助编写新的基于eBPF工具的C++库

ebpf-common库是一组实用程序,协助生成、加载和使用eBPF代码。它是支撑我们所有eBPF相关工具的公共基础。使用epbf-common创建您自己的运行时、基于eBPF的工具!

ebpf-common库的主要工作是编译C代码到eBPF字节码,并提供有用的抽象,使编写eBPF钩子更容易。以下是ebpf-common提供的一些功能:

  • 它使用LLVM和clang作为库,写入内存暂存缓冲区。
  • 它包括抽象,使访问eBPF数据结构(哈希映射、数组、环形缓冲区等)变得简单。这些数据结构用于在eBPF和您的应用程序之间交换数据。
  • 它包括抽象来创建和读取perf输出,这是eBPF与追踪应用程序通信的另一种方式。
  • 它允许管理触发eBPF程序执行的事件(如kprobes、uprobes和追踪点)。
  • 最后,它包括通过LLVM实现eBPF助手和相关功能的函数。

ebpf-common库被用作我们所有其他eBPF工具的核心,这些工具作为库客户端和ebpf-common用例的示例,供您的应用程序参考。请参阅我们的博客文章All your tracing are belong to BPF以获取有关如何使用ebpf-common的额外指导和示例。

我们的eBPF工具

ebpfault:一个构建在eBPF之上的Linux系统调用故障注入器

ebpfault是一个系统范围的故障注入器,不需要可能崩溃系统的危险内核驱动程序。它可以启动特定程序、目标运行进程或目标除特定列表上的进程之外的所有进程。一个简单的JSON格式配置文件让您通过使用系统调用名称、注入故障的概率和应返回的错误代码来配置故障。

ebpfault针对htop进程运行并通过特定配置引起故障的录制

BPF深入探讨和演讲

大多数在线材料都倾向于使用演示eBPF的命令行示例工具,这些工具大多作为独立演示,而不是可重用的库。我们想为开发人员填补空白,并从编写追踪工具的开发人员角度提供如何从头开始实际集成eBPF的逐步指南。文档侧重于使用LLVM库的运行时代码生成。

All your tracing belong to BPF博客文章和我们的配套代码指南展示了如何使用epbf-common创建一个使用eBPF计数系统调用的工具,每个示例复杂性递增,从简单计数开始,到使用映射存储数据,最后使用perf事件进行输出。

Monitoring Linux events是Alessandro Gario关于使用eBPF进行事件监控的演讲。Alessandro描述了如何动态决定监控什么,并直接从C++生成您自己的eBPF字节码。他触及了eBPF映射、perf事件的一些复杂性,以及使用我们的eBPF工具和库的实际考虑。

eBPF公共贡献

eBPF的世界继续扩展,并在各个领域找到应用。我们探索了eBPF与追踪和性能监控之外的有趣任务相关的内容,例如改进eBPF字节码的CI/CD、为Solana平台编写eBPF到ARM64 JIT编译器,以及改善在Windows上构建eBPF项目的体验。

  • ebpf-verifier:有时需要捆绑预构建的eBPF程序。Linux内核在加载时“验证”eBPF程序,并拒绝任何它认为不安全的程序。捆绑eBPF字节码是CI/CD的噩梦,因为每个内核的验证都略有不同。ebpf-verifier旨在通过在运行内核之外执行eBPF验证器来消除这种噩梦,并为跨不同内核版本测试eBPF程序的可能性打开大门。
  • Solana eBPF-to-ARM64 JIT编译器:eBPF出现在许多令人惊讶的地方!Solana区块链使用eBPF虚拟机运行其智能合约,并使用JIT编译器将eBPF字节码编译到本机架构。Trail of Bits将Solana eBPF JIT编译器移植到ARM64,以允许Solana应用程序在本机运行在现在非常流行的ARM64平台上,如Apple Silicon。
  • 向Windows的eBPF添加CMake支持:eBPF也可以在Windows上工作!为了使Windows开发更容易,我们将先前基于Visual Studio的构建系统移植到CMake。改进包括更好地处理传递依赖和属性、更好的打包以及增强的构建设置,以获得更高效的开发体验。

结论

我们使用eBPF为系统检测代理(如osquery)提供快速、高质量的监控数据。我们的意图是我们创建的框架和工具将帮助开发人员更无缝地将eBPF集成到他们的应用程序中。eBPF是一种有用的技术,在各种领域都有光明的未来,包括日益增长的云原生监控和观察。

我们计划在不久的将来分享更多从eBPF工具开发中学到的经验教训,并希望将这些经验教训应用于云原生监控和可观察性问题。

如果您喜欢这篇文章,请分享: Twitter LinkedIn GitHub Mastodon Hacker News

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计