针对已发布的 CVE-2026-98432([RHSB-2026-016])网络缓解措施的 eBPF 实现:Linux 内核 IPv4 TCP 连接请求处理中存在可远程触发的释放后使用漏洞。Red Hat 将其评为严重(Critical)。
[!WARNING] 早期版本:已通过 CI 测试,尚未经过现场测试。 每次推送都会在 Ubuntu 24.04、AlmaLinux 8.10、9.8 和 10.2 虚拟机(兼容 RHEL 的内核 4.18、5.14 和 6.12)上,以及在运行 Cilium 的 2 节点 Kubernetes(kind)集群上运行端到端测试,全部使用虚拟接口。尚未在物理网卡、bond 或 VLAN、OpenShift 或实际 RHEL 上进行测试(参见已测试平台)。请先在非生产主机上试用。非常欢迎提供测试结果反馈,无论好坏。
该程序会丢弃携带 IP 选项的入站 IPv4 TCP 数据包(IP 头长度 > 5 个字)。它与厂商的 nftables 规则是相同的过滤器:
ip protocol tcp ip hdrlength > 5 counter drop
它对 VXLAN(UDP 4789、8472)和 Geneve(UDP 6081)覆盖网络的内层数据包应用相同的检查。这样,节点之间的 Kubernetes pod 到 pod 流量会在物理接口上被丢弃,之后 CNI 插件(如 Cilium)才可能将其投递给 pod。在驱动支持时,它以 XDP 方式运行;在其他情况下,则以 tc ingress 方式运行。
有两种运行方式,使用相同的过滤器和相同的设置:
cve-2026-98432-ebpf),它使用 ip 和 tc,由 systemd 服务和定时器驱动。它最容易审计。cve-2026-98432-ebpfd),一个单一的静态二进制文件。它会立即覆盖新接口,在 tc 上先于 CNI 程序运行,并在崩溃时保持过滤器挂载。参见 Shell 加载器还是 Go 守护进程?[!IMPORTANT] 这是一个降低暴露面、但并不能修复该漏洞的临时措施。唯一完整的修复是使用已修复的内核。一旦所有主机都运行修复后的内核,请移除此缓解措施(参见 移除)。
这是一个独立的社区项目。它与 Red Hat 或任何 Linux 发行版没有关联,也未获得其认可。请查看 [公告][RHSB-2026-016] 以获取当前指导。
nftables 规则是有效的,如果它适合你的环境,就使用它。本项目面向的是不适合使用它的环境:
| nftables 规则 | 本项目 | |
|---|---|---|
| 数据包被丢弃的位置 | netfilter input 钩子(在 skb 分配、IP 分片重组和路由之后) | XDP:在驱动中,在 skb 存在之前。tc:在 netfilter 之前 |
| 覆盖范围 | 仅本地寻址的流量 | 还包括路由和转发的流量,例如发往 Kubernetes pod 的数据包,包括 VXLAN/Geneve 覆盖网络内部的数据包 |
| 与防火墙管理器的交互 | 一个独立的表,必须持久化,并且要在重写规则集的工具运行后仍然存在 | 完全不触碰 netfilter |
| 依赖 | nftables | 使用 libbpf 构建的 iproute2 |
| 按接口 | 否(全局) | 是,加载器会处理这一点(见下文) |
最新发布 包含:
-daemon RPM(Go 守护进程)和源码 RPMcve-2026-98432-ebpf-<version>.tar.gzSHA256SUMSRPM 会安装加载器、BPF 对象、配置文件和 systemd 单元,并拉入 iproute-tc。该服务不会自动启用。请选择与你的主版本匹配的 RPM(el8、el9 或 el10):
sha256sum -c SHA256SUMS --ignore-missing # verify what you downloaded
sudo dnf install ./cve-2026-98432-ebpf-0.1.1-1.el9.x86_64.rpm
sudo systemctl enable --now cve-2026-98432-ebpf.service cve-2026-98432-ebpf-reconcile.timer
sudo cve-2026-98432-ebpf status
或者,对于 Go 守护进程(二者择一使用,不要同时使用;它们的 unit 会冲突):
sudo dnf install ./cve-2026-98432-ebpf-daemon-0.1.1-1.el9.x86_64.rpm
sudo systemctl enable --now cve-2026-98432-ebpfd.service
sudo cve-2026-98432-ebpfd status
在 Debian 和 Ubuntu 上,请使用 .deb 包(见下一节)。在其他发行版上,请从源码 tarball 构建并安装(参见快速开始)。
升级方式是使用 dnf install 安装更新的 RPM。服务会重启,以便挂载新的 BPF 对象,并且你对 /etc/cve-2026-98432-ebpf.conf 所做的修改会被保留。
如需自行构建 RPM,请参见 packaging/rpm/build-rpm.sh 顶部的注释。每次推送时,CI 都会在 AlmaLinux 容器中构建 RPM,在 AlmaLinux 虚拟机中逐个安装并测试,包括 systemd 单元。
该发行版还提供两个 amd64 .deb 包,它们可在所有受支持的发行版上使用:BPF 对象不包含主机代码,且守护进程是静态二进制文件。它们包含与 RPM 相同的文件,并且同样不会启用该服务:
sha256sum -c SHA256SUMS --ignore-missing
sudo apt install ./cve-2026-98432-ebpf_0.1.1-1_amd64.deb
sudo systemctl enable --now cve-2026-98432-ebpf.service cve-2026-98432-ebpf-reconcile.timer
sudo cve-2026-98432-ebpf status
或者使用 Go 守护进程 ./cve-2026-98432-ebpf-daemon_0.1.1-1_amd64.deb,按照 RPM 章节中的方式启用。Debian 和 Ubuntu 将 tc 打包在 iproute2 本身中,并使用 libbpf 构建。
要自行构建它们,请运行
packaging/deb/build-deb.sh。每次推送时,CI
会构建 .deb 包,将它们安装到 Ubuntu 24.04 上,并针对已安装的文件运行端到端测试和
systemd 测试。它还会将它们安装到 Debian
12 和 13 以及 Ubuntu 22.04 和 24.04 上,并在那里运行 check。
使用 git 检出或来自 GitHub release 的源码 tarball。
要构建,你需要 clang、llvm、libbpf-devel / libbpf-dev 以及
内核 UAPI 头文件:
make
sudo make install
sudo cve-2026-98432-ebpf check # verify prerequisites
sudo systemctl enable --now cve-2026-98432-ebpf.service cve-2026-98432-ebpf-reconcile.timer
sudo cve-2026-98432-ebpf status
status 会列出每个受保护的接口及其挂载方式,以及丢弃的数据包数量(该计数器需要 bpftool):
eth0 XDP
wg0 tc
packets dropped: 3
在没有 systemd 的情况下,直接运行 sudo cve-2026-98432-ebpf apply 和 remove。
要从源码构建 Go 守护进程,你需要 Go ≥ 1.22、clang 以及 libbpf 头文件:
cd go && go generate ./... && CGO_ENABLED=0 go build -o cve-2026-98432-ebpfd .
sudo ./cve-2026-98432-ebpfd run --mode auto # SIGTERM detaches
ip -V 的输出必须包含 libbpf。check 会对此进行检测。已在 CI 中于 AlmaLinux 8.10、9.8 和 10.2(iproute2 6.2 至 6.17)以及 Ubuntu 24.04 上验证。tc:在 RHEL、AlmaLinux、Rocky 和 Fedora 上,它单独发布在 iproute-tc 包中(dnf install iproute-tc)。CAP_NET_ADMIN + CAP_BPF/CAP_SYS_ADMIN)。每次推送时,CI 都会检查携带 IP 选项的 IPv4 TCP 连接会被丢弃、普通连接仍可建立,以及移除后恢复正常行为。它在 veth、ipip 和 dummy 接口上以 XDP、tc 和 tunnel(L3)模式运行这些检查,并在虚拟机中的 virtio-net 上运行原生 XDP。它还会在 17 个手工构造的数据包上运行每个 eBPF 程序。关于如何在没有第二台主机的情况下完成这一切,请参阅 docs/TESTING.md:
| 发行版 | 内核 | iproute2 | Shell 加载器 | Go 守护进程 | 软件包 + systemd 单元 | Rust(研究) |
|---|---|---|---|---|---|---|
| Ubuntu 24.04 | 6.x | 6.1 (libbpf 1.3) | ✅ | ✅ | ✅ (.deb) | ✅ |
| AlmaLinux 8.10 | 4.18.0-553 | 6.2 (libbpf 0.5) | ✅ | ✅ | ✅ (RPM) | ✅ |
| AlmaLinux 9.8 | 5.14.0-687 | 6.17 (libbpf 1.5) | ✅ | ✅ | ✅ (RPM) | ✅ |
| AlmaLinux 10.2 | 6.12.0-211 | 6.17 (libbpf 1.7) | ✅ | ✅ | ✅ (RPM) | ✅ |
| Kubernetes | Shell 加载器 DaemonSet | Go 守护进程 DaemonSet |
|---|---|---|
| kind 0.33,2 个节点,Cilium 1.20 (VXLAN) | ✅ 外部 → NodePort,跨节点 pod → pod | ✅ 相同,外加仅在 cilium_vxlan 上的 tcx-head |
Go 守护进程还经过了在 SIGKILL 后存活的测试,下一次运行会接管其固定的挂载点,无论是独立运行还是在 systemd 下运行。29 个数据包测试用例包括 VXLAN 和 Geneve。
.deb 任务在 GitHub runner 本身上运行 systemd 测试:一台运行 7.0 内核的 Azure VM,在 hv_netvsc 上使用原生 XDP,其下还有一个 mlx5 VF(参见 docs/DESIGN.md)。
AlmaLinux 由与 RHEL 相同的源代码构建,但它本身不是 RHEL。 尚未测试:
容器共享节点的内核,因此存在漏洞的代码是节点的 TCP 协议栈,即使数据包是发往某个 pod 的也是如此。因此,在节点的接口上进行过滤可以保护其上的每个 pod。以 DaemonSet 形式在每个节点上部署一个实例:
oc apply -f deploy/openshift/daemonset.yaml # shell loader, or
oc apply -f deploy/openshift/daemonset-daemon.yaml # Go daemon (recommended with Cilium)
每次发布都会发布两个镜像:
ghcr.io/sevaepsteyn/cve-2026-98432-ebpf:<tag>,即 shell 加载器ghcr.io/sevaepsteyn/cve-2026-98432-ebpf-daemon:<tag>,即 Go 守护进程,一个
基于 scratch 的静态二进制文件两者也都带有 :latest 标签,清单文件使用的正是该标签。生产环境请固定使用某个发布标签。
不要使用 v0.1.0 加载器镜像:它缺少 tc,因此其 Pod 会在启动时失败。请使用 v0.1.1 或更高版本。
要自行构建:
podman build -t <registry>/cve-2026-98432-ebpf -f Containerfile .
podman build -t <registry>/cve-2026-98432-ebpf-daemon --target daemon -f Containerfile .
Pod 以特权模式在主机网络命名空间中运行,并在终止时分离过滤器。加载器每 60 秒重新应用一次,以覆盖新接口。守护进程响应 netlink 事件,并挂载主机的 /sys/fs/bpf,使过滤器在 Pod 崩溃后仍能存活。
关于覆盖与未覆盖的内容,请参阅设计说明。简而言之,来自集群外部和其他节点的流量会被覆盖,包括 VXLAN/Geneve 覆盖网络。默认情况下,同一节点上 Pod 之间的流量不会被覆盖。
| Shell 加载器 | Go 守护进程 | |
|---|---|---|
| 安装 | cve-2026-98432-ebpf RPM 或 .deb / make install | cve-2026-98432-ebpf-daemon RPM 或 .deb / 镜像 |
| 运行时依赖 | bash、带 libbpf 的 iproute2、tc | 无(静态二进制,BPF 程序已嵌入) |
| 新接口 | 定时器,60 秒内 | netlink 事件,立即 |
| tcx 内核(6.6+;在 RHEL 系列 9.x 中回移植,例如 AlmaLinux 9.8)上的 tc 回退 | 经典 tc 过滤器:在 CNI tcx 程序(如 Cilium 的)之后运行 | tcx 位于链的头部 |
| 如果崩溃或被杀死 | 过滤器保留(它是一次性工具) | 过滤器保留(固定在 /sys/fs/bpf/cve98432 中);重启后接管 |
| 干净停止 | remove | SIGTERM(systemctl stop)或 cve-2026-98432-ebpfd remove |
| 最易于审计 | ✅(一个简短的脚本,标准工具) |