实践中,哪些技术边界真正约束恶意的 eBPF 载荷?
简短回答: 这些边界大多不是人们默认以为的那样。验证器(verifier)是内存安全检查,而不是行为安全检查:它(在没有验证器漏洞的前提下)只能证明程序不会破坏内核内存,对程序是否具有恶意意图一无所知。实践中,恶意载荷受到四个相互独立、可以测试的边界的约束,每个边界都有已知的失效模式:
- 加载门禁 —— 哪些主体(principal)可以挂载程序(capabilities、unprivileged-BPF sysctl、用户命名空间)。
- 验证器的内存安全范围 —— 已加载程序对内存可以做什么;这个保证随每个内核版本移动,且在不同架构上的实际表现不同。
- 可移植性边界(BTF/CO-RE) —— 假设特定内核结构体布局的载荷,只有在目标内核有 BTF 且布局匹配时才能工作。
- 可见性边界 —— 已加载的程序在进程列表、syslog、auditd 中不可见,只能通过 BPF 原生遥测观测。
如果你在为一个实证研究定范围(或者在为蓝队构建检测基线),要映射的就是这四个边界。"验证器会阻止激进的狀態操縱"只是边界 2,而且是其中最窄的一个:能通过验证器的载荷已经通过了唯一的静态关卡。之后的所有事情都是能力、可移植性和可观测性——而不是静态分析。
为什么"验证器放行"不等于"安全"
内核的信任模型把验证器当作唯一的静态关卡:程序在被验证之前是不可信字节码,验证通过后 JIT 编译执行,它调用的 helper 不会重新检查内存安全。从已验证程序到内核的信任链,只有验证器本身那么强。一篇 2025 年的系统性分析(SoK,USENIX Security)把验证器的弱点分为三类,每一类都有真实 CVE 佐证:
- 不健全的检查 —— 路径剪枝等优化依赖精确的寄存器依赖跟踪;漏掉一个依赖,不安全路径就可能被当成安全路径剪掉(CVE-2023-2163)。
- 不完备的检查 —— 原型里没有 size 参数的 helper 会完全跳过 size 校验(CVE-2021-4204,经由
bpf_ringbuf_submit);验证器信任 helper,而 helper 不会复核。 - 范围有限 —— 检查止步于字节码;helper 内部的时间安全(temporal-safety)问题(例如通过
dev_map_lookup_elem的 use-before-initialization)对验证器不可见。
同一项研究发现,公开 eBPF 程序内存操作的 1.62–3.74%(37–85 个)无法被证明全面内存安全——这些是普通工具而非恶意代码,说明验证目前就留下了这么多未证明的部分。再加上验证器持续不断的 CVE 流(近年来每年数十个,自 4.4 内核引入 eBPF 以来已有数百个模糊测试报告的内存错误 bug),实际结论是:内存安全边界随每个内核版本移动。一个版本上被拒绝的程序,可能在另一个版本上成功加载。
这并不说明验证器日常很弱——对合法程序来说,内存破坏才是真实风险,验证器就是为防它而存在的。它说明"验证器放行"是比"安全"更窄的性质,防御者不应把两者混为一谈。
边界 1:加载门禁
约束谁能加载程序的是能力策略,不是验证器:
- 现代发行版默认禁用非特权 BPF 加载(
kernel.unprivileged_bpf_disabled=1)。历史上本地提权正是从这里进来的:在 CVE-2016-4557 / CVE-2018-18445 时代,非特权字节码注入与验证器越界绕过就是入口。 - 自 Linux 5.8 起,
CAP_BPF把 BPF 加载/挂载与CAP_SYS_ADMIN分开,只持有CAP_SYS_ADMIN的服务不再自动拥有 BPF,反之亦然。 - 启用 BPF LSM 时,加载/挂载/pin 可以受 MAC 策略约束。
公开 eBPF rootkit(从 Black Hat USA 2021 "With Friends Like eBPF" 的工作及其开源后代)到首个有文档记录的生产环境 eBPF 后门,经验模式是同一个:这些是驻留与隐蔽技术,不是入口技术。 行为主体已经持有 root 或 CAP_SYS_ADMIN;eBPF 被用来保持隐藏、通过 pin 住的 map 驻留、并把命令路由进数据路径——全部在验证器放行行为之内。加载门禁回答的是"谁",而不是"进去之后做什么"。
边界 2:验证器范围,按版本与架构
做 x86_64 对比 ARM64 矩阵时,要精确区分什么真正不同:
- 验证器是共享 C 代码;对同一程序,它不会在 ARM64 上"更严格"。
- JIT 是按架构的,架构相关的 bug 历来出现在 JIT 路径和按架构的 selftest 覆盖上。2026 年 bpf 邮件列表上一个活跃的系列正是关于此事:修复 powerpc JIT 处理大型 BPF 程序时的缓冲区溢出,以及一个明确针对该架构缺失的验证器 selftest 覆盖的补丁。这种按架构的验证与测试欠账,正是跨架构研究应该测量的东西。
- 内核配置差异(启用的 BPF 特性、
CONFIG_*选项、BTF 可用性)会改变同版本两个内核上能加载什么。
所以测量单位不是单独的"架构"或"版本",而是四元组**(架构、内核版本、内核配置、BTF 可用性)**。一个在带完整 BTF 的 x86_64 上能加载的载荷,可能在同版本 ARM64 上失败——或者能加载,却被架构相关的检查拒绝。两种结果都是边界数据。
边界 3:可移植性边界(BTF/CO-RE)
CO-RE 是让载荷更不可移植的边界,而不是相反。基于某个内核 BTF 构建的程序携带重定位(relocation),必须在目标内核的 BTF 上解析:
- 目标内核没有 BTF(被裁剪或未编译)→ CO-RE 程序根本无法加载。
- 源与目标之间结构体布局漂移 → 重定位失败,或者在类型兼容但字段移位时静默产生错误偏移。
- 内核 ABI 本身在移动:一个评审中的大型补丁系列为 BPF 引入按值结构体和
__int128参数(包括 kfunc),载荷能表达的东西随版本变化。
对防御研究来说这也是检测边界:BTF 不匹配导致的加载失败会在加载路径上留下签名(BPF_PROG_LOAD 因重定位失败),加载监控可以把它标记出来。对攻击研究来说,它是可移植性天花板:手工调参、非 CO-RE 的偏移是绕开 BTF 要求的唯一方式,而这条路径可移植性差得多,也更可能触发验证器越界检查。
边界 4:可见性边界
大多数防御真正失效的是这个边界,也是近期公开研究反复回到的一点:
- eBPF 程序不出现在
/proc中,其活动也不出现在 syslog 或 auditd 中。被入侵的主机可以运行敌对内核逻辑,而常规遥测看起来毫不起眼。 /sys/fs/bpf下的 pin 住 map 提供跨程序卸载的驻留能力。- 首个有文档记录的生产环境 eBPF 后门(BPFDoor)完全运行在验证器放行行为之内:数据路径 hook 作为命令通道,pin 住的 map 实现驻留,进程表里什么都没有。
- 威胁情报研究现在把 eBPF 植入体归类为独立的 Linux 恶意软件类别,原因正是它们在验证器放行边界之内运行。
唯一可靠的可见性是 BPF 原生的:bpftool prog show / bpftool map show、列 /sys/fs/bpf,以及监视 BPF_PROG_LOAD / BPF_MAP_CREATE / 挂载事件的运行时监控(Falco 规则、Tracee、eBPFmon 类工具)。如果检测栈无法把 BPF 加载/挂载事件与身份和意图关联起来,边界 4 就是开放的,其他三个边界的重要性都会下降。
如何测量这些边界(可复现的实验设计)
如果目标是可复现的技术矩阵,把它结构化为五个独立轴,每个轴都能用公开工具测试:
- 加载门禁矩阵 —— 主体(非特权、仅
CAP_BPF、仅CAP_SYS_ADMIN、root、用户命名空间 +CAP_BPF)× 发行版/内核配置,用同一个最小程序记录BPF_PROG_LOAD的接受情况。 - 按 (arch, version, config) 的验证器边界 —— 在每个目标上跑公开的 CVE 复现集(模糊测试复现程序、
selftests/bpf);记录哪些验证器拒绝、接受或崩溃。"验证器反制"在这里才可测量。 - CO-RE 可移植性 —— 基于 N 套内核 BTF 构建同一个 CO-RE 程序;统计每个目标的成功/失败加载,至少包含一个禁用 BTF 的目标。
- 性能代价 —— 按架构基准测试 syscall 拦截与重 map 工作负载;它同时是"规避代价"数字和检测信号数字,因为同一基线可以标记异常。
- 可见性缺口 —— 同一工作负载下,对比
/proc+ syslog + auditd 与bpftool各能看到什么,量化差异。
轴 1、4、5 完全不需要攻击载荷:它们用合法程序测量环境。轴 2 用的是已经公开多年的复现程序。这样工作保持在防御研究范围内,同时产出蓝队真正缺少的矩阵。
答案的适用边界
- 这些是 Linux 内核的边界。其他运行时上的 eBPF(用户态解释器、Wasm-BPF、非 Linux 移植)的保证集合不同且往往更弱。
- 矩阵的保鲜期取决于被测内核:验证器行为、发行版默认值、能力划分都会随版本变化,所以要重新测量而不是引用旧结果。
- "通过验证"是内存安全陈述,不是安全陈述。已验证程序仍可以经 map 外泄内核数据、挂载到特权 hook、或隐藏自己——这正是边界 4 存在的原因。
- 历史上的非特权 BPF 攻击时代在现行发行版上已基本关闭(默认禁用非特权加载);现代威胁模型应假设 post-root 的驻留与隐蔽,而非非特权入口。
参考资料
- Linux 内核文档:eBPF verifier
- Huang 等,"SoK: Challenges and Paths Toward Memory Safety for eBPF",USENIX Security 2025 — 论文
- Linux Security,"Linux eBPF Security Advisory: Critical Visibility Concerns 2025:0011-2" — 文章
- "With Friends Like eBPF, Who Needs Enemies?",Black Hat USA 2021 — 幻灯片
- Red Canary,"eBPF Malware" 威胁检测分析 — 文章
- eBPF 基金会,"Threat model and independent verifier audit" — 帖子
- eBPF.io,"What is eBPF?"(内核加固措施) — 帖子
当日社区讨论
本次运行覆盖情况:两个启用存档的 Slack 工作区中有一个可读——一个公开频道,严格 24 小时窗口内零条消息,7 天回退窗口内 7 条消息。另一个已启用存档的工作区,其两个白名单频道不存在于存档中,记录为不可访问而非安静。两个白名单 Discord 工作区是仅可视浏览器的来源,本次运行没有可用的可视浏览器会话,此处报告为覆盖缺口而非沉默。公开的 bpf@vger.kernel.org 存档与公开从业者论坛通过其普通公开页面完成审阅。
一个反复出现的问题:恶意 eBPF 到底在哪里碰壁?
窗口内最有分量的讨论是一个研究定范围的交流,它同时出现在可读存档频道和公开从业者论坛中:对"限制恶意 eBPF 载荷的技术边界"做实证研究——验证器反制、CO-RE 局限、以及跨 x86_64 与 ARM64 的内核操作性能代价——对防御社区是否有价值,从哪里入手。上面发布的回答就是对这个问题的回应:验证器只是四个边界之一,而且是最窄的一个;研究应围绕加载门禁、按 (arch, version, config) 的验证器行为、BTF/CO-RE 可移植性、性能代价、可见性缺口来组织。同一个问题在两个独立社区中浮现,说明这是领域公开文献中真实反复出现的缺口,而不是一次性提问。
内核邮件列表正在修补同一个边界
公开内核存档今天恰好活跃在这一主题上。一个多补丁系列修复了 powerpc JIT 处理大型 BPF 程序时的缓冲区溢出,并明确针对该架构缺失的验证器 selftest 覆盖——这是按架构的验证与测试欠账仍然存在的直接证据,也是跨架构研究应当测量的边界。一个 RFC 为指令集提出 UHMUL 与 SHMUL 乘法指令;另一个 RFC 提出跨低 32 位跟踪标量相等性,延续验证器标量范围跟踪的活跃工作。一个大型补丁系列为 BPF 引入按值结构体与 __int128 参数(包括 kfunc),一个 bpf-next 系列通过新 kfunc 加入 BPF 驱动的主动 memcg 回收。一个 sockmap 修复处理了自重定向序列号的重复计数。共同线索:验证器与其 ABI 的演化快于文档和下游假设,这正是边界矩阵需要版本轴的原因。
从业者论坛:性能与行为重构
公开论坛这一周以生产工程为主,而非安全。一个两部分的公开重构系列——第二部分详述某大型运营方用 eBPF 填补的 Linux 生态十一个缺口——继续发布在基金会博客上。一个进程行为重构工具把原始 syscall 事件关联成行为时间线;两个帖子分别讨论从 eBPF 榨取性能、以及让 BPF 策略又快又省空间。一位 CNI 作者分享了 ClusterIP 主机路由数据路径,其第一个排障步骤就是反向路径过滤——与 2026-09-03 回答 探讨的同一边界。这些帖子反复出现的期待:量化指令与数据路径代价,并证明低层事件可以关联成可复现的解释。这也是上面安全边界在运维上的教训:性能基线与 BPF 原生可见性基线,是边界 4 可测量的前提。
继续阅读
返回索引
eBPF 问答
这里每天收录一个关于 eBPF、Linux 可观测性、性能分析、运行时扩展或安全问题的回答。每篇回答都以公开的一手资料为依据,并在末尾附上匿名化的当日社区讨论摘要。
上一篇 / 上一页
eBPF 瞬时 TCP 故障恢复基准必须覆盖哪些场景才有意义?
简短回答: 边界在于你重定向数据包所在的层,与连接状态真正所在的层之间的差距。eBPF 的 XDP 或 TC 程序把帧在网卡之间移动,或送入用户态;它既不能移动、复制,也不能重建套接字的传输控制块(TCB),更无法重建应用层正在进行的请求/响应状态。因此,只有当基准测试在特定层注入故障、在该层以及上一层都断言恢复、并且明确区分"数据包再次流动"这一朴素检查所混为一谈的三种结果——数据路径已重路由、内核 TCP
下一篇 / 下一页
构建进程行为重构工具时,架构上需要把哪些 eBPF/内核限制考虑进去?
1. 事件投递是有序的,但不保证完整。 内核的 BPF 输出通道——每 CPU 的 perf event 数组和共享 BPF ring buffer——在缓冲区写满时会静默丢弃事件。perf buffer 至少会尝试写一条 PERFRECORDLOST 记录,而且只在"尽可能时"(when possible)才写;ring buffer 则根本不写任何丢失记录。因此,重构出的时间线只是进程实际行为的下界(lower
- 最后更新
- 2026年9月8日
- 首次发布
- 2026年9月8日
- 贡献者
- Yunwei 123
这个页面有帮助吗?