ebpf 月报 - 2023 年 1 月
Tags: ebpf
Published: 2023-01-26 12:08:26

本刊物旨在为中文用户提供及时、深入、有态度的 ebpf 资讯。

如果你吃了鸡蛋觉得好吃，还想认识下蛋的母鸡，欢迎关注：
笔者的 twitter：https://twitter.com/spacewanderlzx
笔者的 GitHub：https://github.com/spacewander

## Merbridge 成为 CNCF sandbox 项目

Istio、Linkerd、Kuma 这三个项目除了都是 service mesh 之外，还有什么共同点？
它们都可以通过 [Merbridge](https://merbridge.io/) 加速！

Merbridge 是一个旨在通过 ebpf 代替 iptables，给 service mesh 加速的项目。作为成立刚满一周年的新项目，Merbridge 已经[应用到 kuma 的官方版本当中](https://kuma.io/blog/2022/kuma-2-0-0/)。最近 Merbridge 又达到了另外一个里程碑 —— Merbridge 正式成为 CNCF sandbox 项目。

从 Merbridge 提交给 CNCF 的[维护者列表](https://github.com/cncf/foundation/pull/479/files)来看，目前该项目背后是由 DaoCloud 推动的，半数维护者来自于该公司。不过由于 Merbridge 的位置偏向于底层组件，我们还是可以相信该项目的中立性。想必该项目的创立之初是为了加速 istio，后来也被 kuma 等非 istio 的 service mesh 所采纳。

在使用 Merbridge 进行一键加速之前，一个典型的 service mesh 的网络通信是这样的：

![ebpf-1-before](https://image-static.segmentfault.com/307/026/3070262909-63d2262487251_fix732)

Merbridge 使用了 ebpf 的 [SOCKMAP](https://blog.cloudflare.com/sockmap-tcp-splicing-of-the-future/) 功能，在 socket 层面上完成包的转发，绕过其他弯弯绕绕的路线。

在采用 Merbridge 之后，sidecar 和 app 之间的路径能够显著缩短：

![ebpf-1-after](https://image-static.segmentfault.com/269/110/2691100777-63d226472141b_fix732)

在 Readme 上，Merbridge 把这种变化比喻成穿过了爱因斯坦-罗森桥（虫洞），倒是挺贴切。

## SkyWalking Rover：使用 eBPF 提升 HTTP 可观测性 - L7 指标和追踪

https://skywalking.apache.org/zh/ebpf-enhanced-http-observability-l7-metrics-and-tracing/

提供及时的抓包信息一直是做接入层的程序员的刚需。在笔者的上上家公司，就有同事使用 pcap 实现了可以交互式抓包的后台服务。Elastic 公司也有个开源项目 packetbeat 支持通过 pcap 或者 af_packet 来常态化抓包。

只支持纯抓包的项目都有个限制，那就是无法跟用户态的更多信息有机结合起来。假设可以把用户态的上下文容纳入网络包的信息中，前景将会大大拓宽。比如通过比较用户态的读写方法和内核中实际的读写操作的时间差和数据量，用户会对应用中的 buffering 情况有更深入的了解。抑或通过 hook 应用中的 TLS 操作，可以得到未加密的真实的请求内容。

ebpf 填充了纯抓包和纯用户态的可观测性之间的鸿沟。通过 ebpf，用户能够同时在 kprobe 和 uprobe 中记录上下文，把两者紧密结合在一起。

言归正传，SkyWalking Rover 的这篇文章，强调了它对 L7 协议的可观测性。众所周知，作为一个跑在内核态里面、对执行方式有强约束的技术，想要在 ebpf 里面实现完整的 L7 协议栈是一件很困难的事。那么 SkyWalking Rover 是如何做到的？

SkyWalking Rover hook 了内核相关的函数，嗅探新连接的内容。它会读取最开始的一段内容做分析，猜测其背后采用的协议。虽然有的协议需要更加复杂的处理方式，比如嗅探 websocket 需要剥开外面的 HTTP1 的壳。不过对于绝大多数协议，这样就够了。在完成基本的筛选后，它会把内容转到用户态，交给用户态的解析程序来完成。用户态的解析程序会完成完整的 L7 协议解析。

## Caretta：轻量级的 k8s 服务调用网络可视化工具

https://github.com/groundcover-com/caretta

作为一个去年 11 月才开始开发的项目，Caretta 在最近一个月的 star 增长得飞快，不得不让人佩服 groundcover 这家商业公司的宣发。

![ebpf-1-caretta](https://image-static.segmentfault.com/263/248/2632489576-63d225f21151c_fix732)

groundcover 是一家成立于 2021 年，基于 ebpf 做可观测性的以色列 APM 厂商。Caretta 并非是他们产品的开源版，而是该公司开源出来的小工具。Caretta 是一个轻量级的 k8s 服务调用网络可视化工具，能够梳理集群内不同应用之间的调用关系。这个工具通过 ebpf 获取 Node 上各个连接的信息，接着在用户态借助 k8s 的上下文把连接信息翻译成 k8s 的服务调用，然后通过 Prometheus 的标准接口把信息暴露出来，最后提供了 Grafana 报表展示 Prometheus 采集到的服务调用信息。毕竟是才开发了两个月的项目，这个工具在 ebpf 方面的逻辑其实并不复杂，比较酷炫的展示，是通过 Grafana 来实现的。

## 如何应对 eBPF 带来的新攻击方式

https://redcanary.com/blog/ebpf-malware/

ebpf 这么强大，一定会有人把它应用到黑产上。本文提到了一些借助 ebpf 进行不法行为的方式，并且给出若干加固的建议。
总结起来就两条：

1. defense in depth
2. 如果不用，禁掉 ebpf 和/或 kprobe

对第一条展开说一下。由于 ebpf 能够跑在内核态的，所以通常需要 root 权限，或者 CAP_SYS_ADMIN / CAP_BPF（Linux 5.8 新加的）来跑。然而实际上非特权用户也能跑 ebpf，只是有些功能会被限制。感兴趣的读者可以搜索下“unprivileged ebpf”。但是，就像大家平时写的代码，内核代码中也难免不会出现 bug，导致非特权用户绕过限制的情况。

比如下面的博客就分析了之前一个绕过 Linux ebpf verifier 的安全漏洞：
`https://stdnoerr.github.io/writeup/2022/08/21/eBPF-exploitation-(ft.-D-3CTF-d3bpf).html`

所以考虑到非特权用户运行 ebpf 是如此鲜见，我们大可通过设置 `kernel.unprivileged_bpf_disabled` 禁用该功能。我检查了手上几个 Linux 设备，开发环境上 unprivileged ebpf 是启用的，而两台 VPS 上 unprivileged ebpf 都是禁用的。较新的发行版默认就是禁用 unprivileged ebpf，见 https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#unprivileged-bpf-disabled。

即使设置了 root 才能跑 ebpf，也不代表高枕无忧。黑客们可以通过别的手段拿到 root 权限，然后在 rootkit 里面植入 ebpf 程序。还有一种思路是采用供应链攻击，就像 log4j 一样。不过考虑到目前好像没有什么应用能够动态根据用户输入执行 ebpf 代码，而且 ebpf 也不能直接 import 别人的代码库，在这一块谈供应链攻击还尚早。

借助 ebpf 的 rootkit 是跑在内核里的，且许多 Linux 加固手段也是同样应用在内核里，看来彼此在内核中的斗争会是持久的攻防战。