sched-ext discussion
[PATCH bpf-next] bpf: sched_ext: Mark ops argument container pointer fields as trusted
LLM 分析
sched_ext ops 参数结构体指针字段标记为 trusted
系列概况
- 标题:
[PATCH bpf-next] bpf: sched_ext: Mark ops argument container pointer fields as trusted - 作者: Tejun Heo tj@kernel.org
- 版本: 单封 PATCH,无 v2 等迭代
- 规模: 1 文件改动,+26 行
- 修改文件:
kernel/bpf/verifier.c - 代码统计: 仅
kernel/bpf/verifier.c净增 26 行;新增 4 个BTF_TYPE_SAFE_TRUSTED()声明 + 4 行BTF_TYPE_EMIT()调用 - Message-ID:
95d7ccc17681aa3a4a2eeb1b073f00f7@kernel.org - 完整性: 完整;含 commit message + diff + Signed-off-by;回复链含 CI bot 提问、作者答复、维护者 Acked-by、patchwork bot 应用确认
补丁目的
让 BPF 验证器把 sched_ext ops 参数结构体(scx_init_task_args、scx_cpu_release_args、scx_sub_attach_args、scx_sub_detach_args)里的指针字段识别为 PTR_TRUSTED,从而:
- 解除 sleepable 程序中访问这些字段时被验证器拒绝的限制(之前只能拿到
PTR_UNTRUSTED)。 - 允许调度器在
ops.init_task()这种希望 sleepable 的路径里直接传args->cgroup给bpf_cgrp_storage_get(),而不再需要先用bpf_cgroup_from_id()走 cgroup ID 再反查的绕路。
旧流程的问题
- 非 sleepable 程序访问未标注的 trusted struct 指针字段,得到
PTR_TO_BTF_ID,kfunc/helpers 可以接受。 - sleepable 程序访问同样字段,得到
PTR_UNTRUSTED,验证器直接拒绝。 - 影响 sched_ext 调度器做"sleepable init_task"用
bpf_cgrp_storage_get()的需求,只能用 cgroup ID 来回转换,性能和代码可读性都受损。
新流程
通过 BTF_TYPE_SAFE_TRUSTED() 把四个 ops 参数容器里被调用方在 ops 调用期间 pin 住、且保证非 NULL 的指针字段登记到 verifier 的 trusted-fields 白名单:
scx_init_task_args.cgroup(仅CONFIG_EXT_GROUP_SCHED下存在)scx_cpu_release_args.taskscx_sub_attach_args.opsscx_sub_detach_args.ops
登记后,无论 sleepable 还是非 sleepable 程序,这些字段都得到 PTR_TRUSTED,可以直接传给 bpf_cgrp_storage_get() 等接受 trusted 指针的 kfunc。
Patch 概览
改动全部集中在 kernel/bpf/verifier.c:
BTF_TYPE_SAFE_TRUSTED(struct scx_init_task_args) {
#ifdef CONFIG_EXT_GROUP_SCHED
struct cgroup *cgroup;
#endif
};
BTF_TYPE_SAFE_TRUSTED(struct scx_cpu_release_args) {
struct task_struct *task;
};
BTF_TYPE_SAFE_TRUSTED(struct scx_sub_attach_args) {
struct sched_ext_ops *ops;
};
BTF_TYPE_SAFE_TRUSTED(struct scx_sub_detach_args) {
struct sched_ext_ops *ops;
};
同时在 type_is_trusted() 中追加四条 BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(...)),让 verifier 真正去 BTF 里识别这些结构体。
关键实现
BTF_TYPE_SAFE_TRUSTED 是 verifier 提供的一个声明宏,告诉验证器:在这个结构体里列出的指针字段,对于访问它们的 BPF 程序来说是"已知可信、生命周期由内核 caller 保证、非 NULL"的。
type_is_trusted() 通过 BTF_TYPE_EMIT 列举已知 trusted 类型;当 BPF 程序沿着 trusted struct 访问其中某个指针字段时,verifier 会查 __safe_trusted whitelist 并返回 PTR_TRUSTED 而非 PTR_UNTRUSTED。
+-------------------+ +-----------------------+
| BPF sleepable prog| -----> | verifier walks field |
+-------------------+ +-----------+-----------+
|
v
+-------------+-------------+
| field on whitelist? |
+-------------+-------------+
| |
yes no
| |
v v
PTR_TRUSTED PTR_UNTRUSTED (kfunc ok) (kfunc reject)
类比
把 BTF_TYPE_SAFE_TRUSTED 想成机场的"已安检旅客名单"。内核 caller 在调用 sched_ext ops 之前已经把这些指针(cgroup、task_struct、ops)押在了 VIP 通道,verifier 是门口保安:名单上的指针直接放行(PTR_TRUSTED),名单外的指针必须再过一次 X 光(PTR_UNTRUSTED)。
sleepable 程序只接受走 VIP 通道的指针,所以以前只能在门口被拦下;本补丁把这几位 VIP 旅客登记进名单,调度器就能顺畅使用 sleepable 路径。
Highlight:风险与注意点
- 白名单语义要严格:声明
BTF_TYPE_SAFE_TRUSTED等于向 verifier 承诺该指针在 ops 调用期间始终有效且非 NULL。后续如果 ops 调用语义改变(例如允许cgroup == NULL),就需要同步移除登记,否则 verifier 会把本不该被信任的指针当成 trusted 传给 kfunc,可能触发越界/UAF 类假设。 - 条件编译字段:
cgroup字段只在CONFIG_EXT_GROUP_SCHED=y时存在;声明里用了#ifdef包起来,避免在关闭 cgroup 支持的 build 中误把不存在字段标记为 trusted。 - Fixes tag 的必要性:CI bot 提议带
Fixes: 8195136669661 ("sched_ext: Add cgroup support"),Tejun 答复"目前没人用,所以非严格必要,但不反对",最终由维护者 Kumar 在落库时补上。这条线索也提示以后涉及已有 trusted struct 字段扩展时,习惯性加 Fixes tag 能让 stable/backport 链路更顺。 - sleepable 与否的鸿沟:同一个 BTF 字段在 sleepable / 非 sleepable 程序里语义不同,是当前 BPF verifier 设计里的"结构性"鸿沟;这种补丁只是在 sched_ext 范围内抹平差异,不能简单复制到其他子系统。
版本变化
本系列为单封 PATCH,无 vN 到 vN+1 演进。
一句话总结
把 sched_ext 四个 ops 参数结构体里的关键指针字段加入 BPF verifier 的 trusted 白名单,让 sleepable 程序可以直接使用 args->cgroup 等指针,免去 cgroup ID 来回转换的绕路。