TracingPolicy
解决「策略如何加载」;本篇解决「hook
命中后是否产生事件、执行哪一个动作」。排障时若
tetra
仍看见「以为已滤掉」的事件,要先分清:内核选择器与
第 4
篇 的 JSON export allow/deny 不在同一层。
本篇在系列中的位置
篇目 核心内容 第 6 篇 · TracingPolicy CRD 与加载路径 第 7 篇 · 选择器与内核过滤 selector 语义、常用过滤器、动作挂载点 第 8 篇 · K8s 身份感知 namespace / pod / container / host 系列目录 全部篇目
版本锚定:Tetragon v1.7.0;选择器语义以 tag 文档
docs/.../concepts/tracing-policy/selectors.md与pkg/selectors/为准。本篇不是规则百科;CEL-in-BPF 只点到已核对的边界,不写成任意通用语言。
一、选择器语义:AND、最多 5、first-match
官方 Selectors 文档开篇定义(v1.7.0):
- 每个 hook 最多 5 个 selector。
- 单个 selector 内:所有过滤器必须同时成立(AND);若该 selector 未定义任何过滤器,则视为匹配。
- 多个 selector 之间:只应用第一个匹配 selector 的动作(短路 OR / first-match)。
- 某 selector 未写
matchActions时,默认动作是Post(向用户态投递事件)。 - hook 完全不写 selectors 时,同样默认
Post。
官方示例(文档示例,非本机输出):用第一个 selector 对
/usr/bin/mount 做 NoPost,第二个
selector 对其余调用
Post——从而「排除某二进制的事件」:
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: "mount-example"
spec:
kprobes:
- call: "sys_mount"
syscall: true
selectors:
- matchBinaries:
- operator: In
values:
- "/usr/bin/mount"
matchActions:
- action: NoPost
- matchActions:
- action: Postflowchart TD
hook["Hook_fires"] --> s0{"Selector_0_all_filters_AND"}
s0 -->|"match"| act0["Run_actions_of_selector_0"]
s0 -->|"no"| s1{"Selector_1_AND"}
s1 -->|"match"| act1["Run_actions_of_selector_1"]
s1 -->|"no"| sN{"Later_selectors_up_to_5"}
sN -->|"none matched"| none["No_selector_action"]
常见误读:把多个 selector 理解成「全部执行」或「合并动作」。v1.7.0 文档明确是 first-match;后面的 selector 在前者已匹配时不会再跑。
这与 JSON denylist 的关系:选择器决定内核是否 Post;denylist 只影响文件 sink。二者不一致时,见第 4 篇 Caution。
其它过滤器(本篇不展开)
同一文档还定义
matchData、matchReturnArgs、matchPIDs、matchNamespaces、matchCapabilities
以及 namespace/capability
变更过滤器。它们服从同一套 AND /
first-match 规则。例如 matchPIDs
文档用「namespace PID 不为 1」近似捕捉
kubectl exec
注入进程——这是模式提示,不是完备检测器;与进程模型中的
in_init_tree 叙述对照见 第 2
篇。
本篇刻意不写成「每个算子 × 每个 hook」矩阵:规则百科会过时,且掩盖 first-match 顺序这个真正高频故障点。
二、matchArgs
/ matchBinaries /
matchParentBinaries
本节约到三条最高频过滤器;PID / namespace / capability 等过滤器文档有完整列表,排障时回查 selectors.md,不在此做成规则库。
matchArgs
按函数参数值过滤。可用
index(函数参数位置)或 args(spec
中参数位置);args 优先。常用算子包括
Equal、NotEqual、Prefix、Postfix、Mask、FileType、NotFileType
等(以文档为准)。
对 file / path
类型参数,可直接按路径或文件类型匹配。多个
matchArgs 条目仍在同一 selector 内
AND。
matchBinaries
按进程二进制路径过滤。算子含 In /
NotIn / Prefix /
NotPrefix / Postfix /
NotPostfix。默认行为文档写明与
followForks: true 相关:子进程会被跟随。
followChildren: true
时额外限制:策略安装之前已存在的子进程不会匹配;带
followChildren 的 matchBinaries
段不超过 64;算子限于 In /
NotIn。
Shebang 脚本:文档
Caution——匹配的是解释器路径,不是脚本路径。写
/opt/scripts/foo.py 不会按预期工作,应匹配
/usr/bin/python3 一类解释器。
matchParentBinaries(v1.7.0)
按父进程二进制路径过滤,算子集合与
matchBinaries 类似。文档 Warning:仅在启用 BPF
parents_map 时可用(选项
--parents-map-enabled),并带来额外内存开销。followChildren
的限制与 binaries 侧同类(安装前已有子进程不匹配;带
followChildren 的段 ≤ 64;算子限
In/NotIn)。
典型组合:父为交互 shell、子为
cat——用于区分「脚本/服务拉起」与「人在 shell
里敲」。
| 过滤器 | 匹配对象 | v1.7.0 额外前提 |
|---|---|---|
matchArgs |
hook 参数 | 参数类型与 hook 声明一致 |
matchBinaries |
当前进程二进制(解释器而非 shebang 脚本) | followChildren 有名额与算子限制 |
matchParentBinaries |
父进程二进制 | --parents-map-enabled |
matchBinaries 与 matchArgs
写在同一 selector 时仍然是 AND:例如「二进制是 sshd 子孙
且 fd 为 1/2/3」的官方 write
示例,依赖的是同一 selector 内组合,而不是两个 selector 的
OR。若误拆成两个 selector,first-match
可能让你只打到其中一半条件。
三、动作:Post
/ NoPost / Override /
Sigkill / Signal
动作写在 matchActions(返回路径另有
matchReturnActions,本篇不展开百科)。默认无动作即
Post。
| 动作 | 文档语义(摘要) | 本系列后续 |
|---|---|---|
Post |
事件从内核传到 agent;可带
rateLimit、栈追踪等参数 |
节流细节 → 第 11 篇 |
NoPost |
抑制事件,但同 selector 内其它动作仍执行 | 适合「只要 Override/杀进程、不要日志洪水」 |
Override |
改写调用返回值;kprobe 依赖内核 error injection /
CONFIG_BPF_KPROBE_OVERRIDE;uprobe Override
文档限 x86_64 |
保证语义 → 第 10 篇 |
Sigkill |
在内核同步终止匹配进程 | 不保证当前 syscall 无副作用 → 第 10 篇 |
Signal |
向当前进程发 argSig
指定信号;SIGKILL(9) 可近似 Sigkill 示例 |
第 10 篇 |
Post 的
rateLimit:文档写明默认可按秒,后缀
m/h
为分/时;在时间窗内对同线程、相同已检查参数(每个参数前
40 字节)抑制重复 Post;需内核 ≥
5.3。可用 rateLimitScope 扩到
process 或
global。完整观测税与误杀面放到第 11
篇,本篇只立指针。
Override 的文档约束值得单独记住(细节与
TOCTOU 在第 10 篇展开):
- kprobe:依赖内核 error injection
框架,需要相应内核配置(文档指向
CONFIG_BPF_KPROBE_OVERRIDE一类前提)。 - 相对
Sigkill:Override 让这次调用以指定错误返回;Sigkill 终止进程,但不保证当前 syscall 已执行部分无副作用。 - uprobe Override:文档写明仅 x86_64。
若策略在无 Override 能力的内核上仍写
action: Override,加载或运行期会失败/无效——不要把「YAML
能 apply」当成「阻断已生效」。
四、内核执行
vs 用户态 GetUrl / DnsLookup
selectors.md 的 Note(v1.7.0)划分:
- 内核 BPF 内直接执行:文档列举
Sigkill、Override、FollowFD族、Post、TrackSock/UntrackSock等。 - 用户态、在事件到达 agent
之后:
GetUrl、DnsLookup(例如打 canary URL / DNS)。
工程含义:
- 依赖
GetUrl/DnsLookup做「阻断」是错的——它们不在 syscall 路径上 inline 失败。 - 真正要缩小 Garfinkel 所说的检查窗口,应使用内核侧
Override/Sigkill(仍受 TOCTOU 与配置依赖约束,见第 10 篇)。 FollowFD族在文档中已标 deprecated(文案仍写计划于 1.5 移除;以 v1.7.0 文档现状为准:不要在新策略里依赖)。
文档 Note 没有把 Signal
写进「内核直接执行」那一列表,也未把它与 GetUrl
并列。写作上本篇只保证:Sigkill/Override/Post
的内核对齐、GetUrl/DnsLookup
的用户态对齐均有明文;Signal 的精确执行位点以
selectors 专节与第 10 篇源码路径为准,不在此脑补。
五、CEL-in-BPF:点到边界,不写成通用语言
v1.7.0 引入在 BPF 中求值 CEL 表达式的能力(Release notes · PR #4504)。本篇不提供 CEL 教程。已从 tag 源码核对的硬边界:
bpf/process/cel_expr.h:在__LARGE_BPF_PROG且(GENERIC_KPROBE或GENERIC_UPROBE)时,提供cel_expr_0…cel_expr_7(即 最多 8 路生成函数);id超出则返回 0。- 未满足上述宏时,
cel_expr直接返回 0。
因此:不要把 CEL-in-BPF 叙述成「任意 CEL 都能在所有
hook/内核上跑」。需要表达式能力时,回到
pkg/celbpf/
与具体策略加载日志,而不是假设与用户态 CEL 库同构。
六、学术谱系、争论与开放问题
谱系:Wright et al.(USENIX Security 2002)把安全决策挂到内核 hook;选择器是 Tetragon 在 eBPF 程序里对「哪些调用值得处理」的可配置裁剪。Garfinkel(NDSS 2003)论证用户态系统调用拦截的竞态:过滤若发生在用户态,强制执行可能永远「慢半拍」。Tetragon 把 match* 与 Sigkill/Override 放进 BPF,是对该论点的工程回应——前提是 selector 真的在内核匹配,且动作选的是内核路径。
争论:表达力 vs 可预测性
| 侧 | 主张 | 代价 |
|---|---|---|
| 多 selector + 丰富算子 | 一条 hook 覆盖复杂例外(如 mount 示例) | first-match 顺序敏感;难审计「为何没 Post」 |
| 尽量单 selector + 显式 Post/NoPost | 心智模型简单 | 例外逻辑可能拆成多条 TracingPolicy,增加
collectionKey 管理成本 |
开放问题:Post.rateLimit 与
cgroup-rate(第 11
篇)叠加时,运维如何区分「被节流」与「未匹配」——需要 metrics
与排障坐标系,而不是再加一条更宽的 selector。
七、小结
- Selector 内 AND;每 hook ≤ 5;多 selector 为
first-match;默认
Post。 matchArgs/matchBinaries/matchParentBinaries覆盖参数与血缘侧二进制;后者要--parents-map-enabled。NoPost抑日志不抑同组动作;Override/Sigkill/Signal的保证边界见第 10 篇。GetUrl/DnsLookup在用户态,不能当 inline 阻断。- CEL-in-BPF 有宏与最多 8 路表达式边界;下一篇谈 K8s 身份如何在加载前再裁一轮工作负载集合。
不写边界(本篇)
- MITRE / 完整规则库;把每个
match*算子做成百科。 - 未打开
pkg/celbpf边界就宣称「任意 CEL」。 - 未实测的 selector 命中率或 CPU
税;
Post.rateLimit的生产调参菜谱(留给第 11 篇机制)。
八、参考资料
规范 / 官方文档(A)
docs/content/en/docs/concepts/tracing-policy/selectors.md@ v1.7.0 — 语义、过滤器、动作、rateLimit。- Tetragon v1.7.0 Release notes —
matchParentBinaries(PR #4254)、CEL-in-BPF(PR #4504)。
源码(A)
pkg/selectors/@ v1.7.0bpf/process/cel_expr.h:cel_expr_0…cel_expr_7@ v1.7.0pkg/celbpf/@ v1.7.0(边界线索;本篇不展开编译器)pkg/option/flags.go:KeyParentsMapEnabled默认 false @ v1.7.0
核心论文
- Wright et al., Linux Security Modules…, USENIX Security 2002 — hook 框架谱系。
- Garfinkel, Traps and Pitfalls…, NDSS 2003 — 用户态拦截竞态;对照内核过滤动机。
站内对照
实验台账
- 未在节点实测 selector 命中率;YAML 摘自官方文档示例并标明来源。
→ 上一篇:TracingPolicy · 系列目录 · 下一篇:K8s 身份感知策略
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【Tetragon / eBPF】强制执行:Override 与 SIGKILL 各自保证什么
按 Tetragon v1.7.0 官方 Enforcement 文档钉死:Override 使函数不执行并返回 argError;SIGKILL 终止进程但不保证当前 syscall 无副作用;monitor 与 enforce 如何把动作抹掉;以及 Bishop–Dilger–Garfinkel 的 TOCTOU 谱系落到 bpf_enforcer.c 的边界。
【Tetragon / eBPF】排障坐标系:无事件、策略不生效、导出缺口、误阻断与血缘空洞
按五轴映射 Tetragon v1.7.0 故障:无事件落在 Hook/BTF/加载,策略不生效落在 collectionKey 撞名与 policyfilter,JSON allow/deny 不等于 gRPC,Override 依赖 CONFIG_BPF_KPROBE_OVERRIDE,血缘空洞来自 execve_map 未命中与 procFS 回填。
【Tetragon / eBPF】运行时安全全景:缺口、五轴坐标系与 16 篇路线
相对 Cilium 数据面、可观测对照与 Falco 口号,钉清 Tetragon v1.7.0 运行时安全内核缺口;定义进程血缘、Sensor/Hook、策略加载、过滤分层、强制执行五条坐标系,给出 16 篇阅读路线。
【Tetragon / eBPF】进程模型:exec_id、血缘、in_init_tree 与 procfs 回填
钉清 Tetragon v1.7.0 的进程身份:process_exec/exit 字段、exec_id 如何由 node:ktime:pid 生成、execve_map 与用户态 cache 的分工、in_init_tree 如何区分 kubectl exec 注入,以及 fork 时父不在 map 则子不入图的失败路径。