你的 Agent 是个黑箱:eBPF 如何看见它真正在做什么
- 一、三层观测:从"它说了什么"到"它做了什么"
- 二、实操:用 bpftrace 看 Claude Code 在干什么
- 三、语义鸿沟:eBPF 知道"它做了什么",但不知道"为什么做"
- 四、为什么通用安全工具不够:AI Agent 没有稳定行为基线
- 五、eBPF 不是银弹
沙箱防逃逸,审批防越权,但 Agent 拿到合法权限后的行为——没人看得见。
本文首发地址 https://h89.cn/archives/625.html
上个月披露的 TrapDoor 攻击,攻击者在 .cursorrules 里埋零宽 Unicode 字符,Agent 读取后自动遍历文件系统外发密钥。这个月 Miasma Wave 2 更进一步——后门配置文件直接丢进项目目录,你克隆仓库、打开项目,后门就激活了。
没有弹窗,没有告警,沙箱也不触发。攻击完全发生在授权边界内,Agent 只是"按配置工作"。
所有防御措施都在解决"安装前"的问题:扫描依赖、审核 registry、提醒用户只装可信来源。但一旦恶意配置进了你的环境,Agent 开始运行之后——它实际在做什么,没人知道。

一、三层观测:从"它说了什么"到"它做了什么"
我画了一个分层模型,把 Agent 可观测性拆成三层:
L1: Agent 日志层 —— "它打算做什么"
L2: OTel 链路层 —— "它调了什么 API"
L3: eBPF 内核层 —— "它实际做了什么"
L1 日志层就是你最熟悉的:Claude Code 的 stdout、LangChain 的 callback、你自己打的 log。这一层的问题是不可信——Agent 被注入控制后,可以选择性报告,甚至伪造日志。
L2 链路层用 OpenTelemetry 追踪 Agent → LLM → Tool 的调用链,记录 token 用量、耗时、成本。这一层比 L1 客观,但它只能看到"应用层约定好的交互",看不到进程内部实际读了哪些文件、连了哪些 IP。
L3 eBPF 内核层才是本文的重点。eBPF 是 Linux 内核的沙盒运行时,让你在不改内核、不装内核模块的情况下,在内核态执行自定义程序。它通过三种钩子接入系统:
| 类型 | 用途 | 稳定性 |
|---|---|---|
| kprobes/kretprobes | 动态探针,挂载到任意内核函数(tcp_connect、do_sys_open) |
非稳定 ABI,内核升级可能失效 |
| tracepoints | 稳定检测点(sched_process_exec、sys_enter_*),永不过期 |
稳定,适合长期部署 |
| LSM hooks | 强制访问控制层,可在操作完成前拒绝(bpf_lsm_file_open) |
稳定,适合 enforcement |
前两种让你"看见",第三种让你"拦住"。对于 Agent 可观测性,tracepoints 做长期监控,kprobes 做按需审计,LSM hooks 做实时阻断——三者配合,你在系统边界就有了完整的控制面。
它能看到的每个系统调用:
openat2—— 读了什么文件connect—— 连了哪个 IPexecve—— 启动了什么子进程sendto/recvfrom—— 网络流量细节
而且Agent 完全无感知——不需要改一行 Agent 代码,不需要装什么 sidecar,开销只有 1-3% CPU。
二、实操:用 bpftrace 看 Claude Code 在干什么
理论讲完,直接上手。
1. 安装 bpftrace
sudo apt-get install -y bpftrace
以下这段脚本,可以实时打印 Claude Code 进程打开的文件(在 kernel 5.8+ 上测试通过):
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_openat {
if (comm == "claude") {
printf("OPEN: pid=%d, file=%s\n", pid, str(args->filename));
}
}'
跑起来之后,你在另一个终端正常用 Claude Code 工作,这边就会实时输出:
OPEN: pid=8842, file=/home/user/.claude/settings.json
OPEN: pid=8842, file=/home/user/project/src/main.rs
OPEN: pid=8842, file=/home/user/project/.env
关键点是——这个信息是内核直接报告的,不经过 Claude Code 的日志系统。即使 Claude Code 被注入了"不要记录文件访问"的指令,内核依然会如实上报。
网络监控为什么不在这里展示?
实际测试发现,用 bpftrace 抓网络连接有两个问题:
- 现代 Agent 大多使用长连接/连接池,启动时就建好了,
connect()系统调用很少触发 - 如果要抓数据传输(
send/recv),需要更复杂的内核结构体解析,一行脚本搞不定
生产环境的网络监控,推荐用下面介绍的 Tetragon + TracePolicy,或者直接用 ss -tunap | grep <进程名> 查看已建立的连接。
想监控 OpenCode?把
comm == "claude"改成comm == "opencode"即可。进程名可以通过ps aux | grep <你的Agent>查看。
2. 生产环境:Tetragon
bpftrace 适合临时审计。如果要长期监控,特别是 K8s 环境里跑 Agent,用 Tetragon 更合适——它通过 eBPF 做内核级追踪,原生支持 pod/namespace/label 关联,还能用 TracePolicy 做进程级阻断。
这里需要澄清一个容易混淆的点:bpftrace 只能观测,不能阻断。它适合临时审计和快速验证,但生产环境要做 enforcement(拦截),需要 Tetragon 的 TracePolicy(支持进程级阻断)或 KubeArmor 的 LSM 策略。Falco 检测-only,不拦截。
三、语义鸿沟:eBPF 知道"它做了什么",但不知道"为什么做"
假设你的客服 Agent 收到一个含间接 prompt injection 的工单。注入指令覆盖任务上下文,让 Agent 从 PII 表拉数据,POST 到一个外部端点。
我们用这个实际攻击场景来说明不同检测层的能力边界:
不同检测层的能力边界对比
| 检测层 | 能看到什么 | 漏掉什么 |
|---|---|---|
| eBPF/kernel | 新 TCP 连接到未知 IP。DNS 解析到不明域名。数据库 socket 读取量异常。 | 为什么建立这个连接。数据库查询是否合法。是不是 prompt injection 触发的。 |
| 容器运行时 | 无镜像漂移。无意外进程。可能的网络出口流量峰值。 | 出口流量是合法数据传输还是外泄。无因果链。 |
| K8s 控制面 | 无。RBAC 不变、SA 不变、API server 不变。 | 一切。攻击在授权边界内完成。 |
| 应用层 L7 + tool | 输入流中的注入 prompt。针对新表的未授权数据库 tool 调用。含 PII 的 POST 到未知域名。完整的因果链:工单→外泄。 | 几乎没有。这是拥有完整上下文的一层。 |
这个表说明两件事:第一,K8s 和容器运行时在这个场景下几乎失明——攻击不需要逃逸、不需要提权,完全在授权边界内完成。第二,eBPF 能捕捉到异常信号,但无法区分"合法新行为"和"攻击行为"。
这就是看到不等于理解。eBPF 知道 Agent 在 14:23:05 连了一个陌生 IP、读了一块数据库区域,但它不知道:
- 这个连接是因为 prompt injection 触发的
- 数据库查询读取的是 PII 还是普通数据
- Agent 的"意图"是什么
这就是 UC Berkeley 的 AgentSight 论文(arXiv:2508.02736)里提出的"语义鸿沟"(Semantic Gap):
- Intent stream(意图流):Agent 在 LLM 通信中表达的意图——即便流量是 TLS 加密的,也可以在
SSL_read/SSL_write挂 uprobe 截获解密后的内容 - Action stream(动作流):Agent 实际执行的系统调用
- 两者之间的断层:内核知道动作,但不知道意图;LLM 通信里有意图,但如果没有关联机制,它就是孤立文本
AgentSight 的核心创新就是做了一个因果关联引擎:把"某个时间点 LLM 输出了什么意图"和"之后 N 秒内发生了哪些系统调用"实时关联,再用一个副 LLM 做语义分析,判断行为是否偏离预期。
论文报告的 overhead 不到 3%。代码开源在 GitHub,Rust 6000 行 + TS 3000 行前端。
四、为什么通用安全工具不够:AI Agent 没有稳定行为基线
你可能会问:既然 eBPF 能监控进程行为,那直接用 Falco、Tetragon 这些成熟工具不就行了?为什么还要专门搞"AI-aware"的方案?
因为 AI Agent 的行为不是确定的。
一个 Web 服务器的行为是可预测的:它监听 80/443,读写特定目录,连特定的数据库和缓存。你给 Falco 写一条规则:"除了连 redis:6379 和 postgres:5432 之外的网络连接都告警",这完全可行。
但 Agent 的行为由 prompt 决定。同一个 Agent,上午的任务是"分析销售数据",下午的任务是"爬取竞品信息"。前者可能只读本地 CSV,后者可能要连几十个外部域名。静态白名单要么太松(等于没设),要么太紧(频繁误报打断 Agent 正常工作)。
先看开源工具的适用性(截至 2026-06):
| 工具 | 类型 | Agent 场景适用性 | Overhead |
|---|---|---|---|
| Cilium Tetragon (v1.7+) | 运行时安全 + enforcement | 中等——K8s-aware,支持 TracePolicy CRD,可阻断 | 最低(in-kernel 过滤) |
| Falco (v0.40+) | 运行时安全(检测-only) | 低——检测-only,不阻断,静态规则 | 中低 |
| Tracee (v0.23+) | 深度系统调用追踪 | 低——overhead 高(2-4x Tetragon),适合调试非生产 | 高 |
| KubeArmor (v1.4+) | 强制访问控制 | 中等——LSM-based,支持 file/network/process 策略 | 中低 |
Tetragon 适合 Agent 行为基线建立 + 异常检测,Falco 适合安全审计 + 合规但无法实时阻断,Tracee 深度足够但 overhead 太高不适合生产。它们对确定性工作负载有效,但 Agent 没有稳定的 syscall profile。
这些工具本身不接 LLM。Tetragon 和 KubeArmor 是规则驱动的——你写 YAML 定义"检测到 X 就拦截",执行是确定性的,没有 LLM 参与。这和 AgentSight 那种"用副 LLM 做语义分析"是两条完全不同的路线。
那 LLM 在阻断链路里能干什么?目前看有三类方案,但没有一个是"LLM 实时推理拦截系统调用"的:
| 方案类型 | 代表项目 | LLM 角色 | 实时性 |
|---|---|---|---|
| LLM 生成规则,规则引擎执行 | AgentSpec (ICSE 2026)、SafeClaw-R | LLM 离线生成安全策略/DSL 规则 | ✅ 毫秒级执行 |
| LLM 分析异常,人工/异步响应 | AgentSight、ARMO | LLM 关联意图流和动作流,判断偏离 | ❌ 告警后响应 |
| 权限框架,deny-by-default | SkillGuard | 基于 skill manifest 预定义权限边界 | ✅ 实时 |
AgentSpec 论文的关键结论:"LLM-as-a-Judge lack reliable real-time enforcement"——LLM 做判断太慢且不一致,系统调用级别的拦截等不起几百毫秒的推理延迟。所以现实架构是LLM 离线生成规则 + 轻量级引擎实时执行。
ARMO 在 2026 年 3 月的一篇博客里提出了一个概念叫 Application Profile DNA——不是记录"Agent 通常做什么"的静态快照,而是记录"Agent 在不同任务下的行为分布",并随时间演化。
对比一下就清楚了:
| 维度 | 通用 eBPF(Tetragon/Falco) | AI-aware eBPF(ARMO) |
|---|---|---|
| 策略模型 | 静态白名单 + 规则 | 动态策略,基于行为基线演化 |
| 检测上下文 | 系统调用级异常 | syscall + 应用层 tool 调用 + L7 流量内容 |
| 策略粒度 | 按 pod/namespace | 按 Agent 个体,反映各自行为画像 |
另一个值得关注的方向是 groundcover(2026)。他们在 K8s 集群里跑 eBPF sensor,自动识别 OpenAI/Anthropic 等 provider 的流量,把 LLM 调用转成 OTel trace——prompt、响应、token 用量、延迟全部记录为 span,无需 SDK 埋点。甚至还提供 MCP Server,让 Agent 自己 query 观测数据。
这个思路的本质是:不要试图用规则预测 Agent 会做什么,而是观察它实际做了什么,然后问"这偏离正常模式多远"。
五、eBPF 不是银弹
写到这里必须诚实:eBPF 解决的是"看见"的问题,不是"理解"的问题。
它能告诉你 Agent 在 14:23:05 连了 104.18.32.47:443,但它不能告诉你这个连接是正常 API 调用还是数据外泄。要做出这个判断,你需要:
- 应用层上下文:这个连接的 HTTP body 里是什么?(需要 L7 探针或 AgentSight 那样的 TLS 截获)
- 业务语义:这个 IP 是否在白名单里?这次数据读取是否符合当前任务?(需要对接你的业务系统)
- 因果链:这个行为是由哪个用户请求、哪条 prompt 触发的?(需要 OTel 链路追踪)
所以正确的架构是三层叠加,不是单层替代:
┌─────────────────────────────────────────┐
│ L1: Agent 日志(自报告,不可信) │
├─────────────────────────────────────────┤
│ L2: OTel 链路(API 调用链,不完整) │
├─────────────────────────────────────────┤
│ L3: eBPF 内核(内核视角,无上下文) │
└─────────────────────────────────────────┘
L1 给你业务语义,L2 给你调用链,L3 给你不可抵赖的系统行为证据。三者交叉验证,才能回答那个真正重要的问题:Agent 有没有做它不该做的事?
对了,Futurum 2026 年初的调研显示,AI Agent 可观测性已经进入了企业采购优先级的 Top 10。不是因为 CFO 们突然关心新技术,而是因为第一批在生产环境跑 Agent 的团队,已经踩过坑了。
如果你现在就想动手:
- 快速验证:装一个 bpftrace,跑上面的脚本,看看你的 Agent 实际在做什么
- 建立基线:用 Tetragon 在测试环境跑 1-2 周,记录 Agent 的行为分布
- 打通三层:把 L1 日志、L2 OTel、L3 eBPF 三层联动起来,交叉验证异常行为
eBPF 不是银弹,但它至少让你看见了之前看不见的东西。
参考资料
- AgentSight (UC Berkeley, arXiv:2508.02736): https://arxiv.org/html/2508.02736v2
- ARMO: eBPF for AI Agent Enforcement: https://www.armosec.io/blog/ebpf-based-ai-agent-enforcement
- groundcover: AI Agent Observability: https://www.groundcover.com/learn/observability/ai-agent-observability
- Tetragon: https://tetragon.io
- Futurum 2026 调研: AI Agent 可观测性进入企业采购优先级 Top 10
本文链接:你的 Agent 是个黑箱:eBPF 如何看见它真正在做什么 - https://h89.cn/archives/625.html
版权声明:原创文章 遵循 CC 4.0 BY-SA 版权协议,转载请附上原文链接和本声明。