0/5 已展开

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_argsscx_cpu_release_argsscx_sub_attach_argsscx_sub_detach_args)里的指针字段识别为 PTR_TRUSTED,从而:

  1. 解除 sleepable 程序中访问这些字段时被验证器拒绝的限制(之前只能拿到 PTR_UNTRUSTED)。
  2. 允许调度器在 ops.init_task() 这种希望 sleepable 的路径里直接传 args->cgroupbpf_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.task
  • scx_sub_attach_args.ops
  • scx_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 来回转换的绕路。