cid and cpu are both small s32s, trivially confused when a cid-form scheduler calls a cpu-keyed kfunc. Reject cid-form programs that reference any kfunc in the new scx_kfunc_ids_cpu_only at verifier load time. The reverse direction is intentionally permissive: cpu-form schedulers can freely call cid-form kfuncs to ease a gradual cpumask -> cid migration. The check sits in scx_kfunc_context_filter() right after the SCX struct_ops gate and before the any/idle allow and per-op allow-list checks, so it catches cpu-only kfuncs regardless of which set they belong to (any, idle, or select_cpu). v2: Sync per-entry kfunc flags with their primary declarations (Zhao). pahole intersects flags across BTF_ID_FLAGS() occurrences, so omitting them drops the flags globally.
Showing the changes to kernel (1 of 1 file). Show all
Unified · Split
| @@ -10121,6 +10121,47 @@ static const struct btf_kfunc_id_set scx_kfunc_set_any = { · 10120 unmodified lines | ||
| 10121 | 10121 | .filter = scx_kfunc_context_filter, |
| 10122 | 10122 | }; |
| 10123 | 10123 | |
| 10124 | +/* | |
| 10125 | + * cpu-form kfuncs that are forbidden from cid-form schedulers | |
| 10126 | + * (bpf_sched_ext_ops_cid). Programs targeting the cid struct_ops type must | |
| 10127 | + * use the cid-form alternative (cid/cmask kfuncs). | |
| 10128 | + * | |
| 10129 | + * Membership overlaps with scx_kfunc_ids_{any,idle,select_cpu}; the filter | |
| 10130 | + * tests this set independently and rejects matches before the per-op | |
| 10131 | + * allow-list check runs. | |
| 10132 | + * | |
| 10133 | + * pahole/resolve_btfids scans every BTF_ID_FLAGS() at build time and | |
| 10134 | + * intersects flags across duplicate entries, so each entry must carry the | |
| 10135 | + * same flags as the kfunc's primary declaration; otherwise the flags get | |
| 10136 | + * dropped globally. | |
| 10137 | + */ | |
| 10138 | +BTF_KFUNCS_START(scx_kfunc_ids_cpu_only) | |
| 10139 | +BTF_ID_FLAGS(func, scx_bpf_kick_cpu, KF_IMPLICIT_ARGS) | |
| 10140 | +BTF_ID_FLAGS(func, scx_bpf_task_cpu, KF_RCU) | |
| 10141 | +BTF_ID_FLAGS(func, scx_bpf_cpu_rq, KF_IMPLICIT_ARGS) | |
| 10142 | +BTF_ID_FLAGS(func, scx_bpf_cpu_curr, KF_IMPLICIT_ARGS | KF_RET_NULL | KF_RCU_PROTECTED) | |
| 10143 | +BTF_ID_FLAGS(func, scx_bpf_cpu_node, KF_IMPLICIT_ARGS) | |
| 10144 | +BTF_ID_FLAGS(func, scx_bpf_cpuperf_cap, KF_IMPLICIT_ARGS) | |
| 10145 | +BTF_ID_FLAGS(func, scx_bpf_cpuperf_cur, KF_IMPLICIT_ARGS) | |
| 10146 | +BTF_ID_FLAGS(func, scx_bpf_cpuperf_set, KF_IMPLICIT_ARGS) | |
| 10147 | +BTF_ID_FLAGS(func, scx_bpf_get_possible_cpumask, KF_ACQUIRE) | |
| 10148 | +BTF_ID_FLAGS(func, scx_bpf_get_online_cpumask, KF_ACQUIRE) | |
| 10149 | +BTF_ID_FLAGS(func, scx_bpf_put_cpumask, KF_RELEASE) | |
| 10150 | +BTF_ID_FLAGS(func, scx_bpf_select_cpu_dfl, KF_IMPLICIT_ARGS | KF_RCU) | |
| 10151 | +BTF_ID_FLAGS(func, __scx_bpf_select_cpu_and, KF_IMPLICIT_ARGS | KF_RCU) | |
| 10152 | +BTF_ID_FLAGS(func, scx_bpf_select_cpu_and, KF_RCU) | |
| 10153 | +BTF_ID_FLAGS(func, scx_bpf_get_idle_cpumask, KF_IMPLICIT_ARGS | KF_ACQUIRE) | |
| 10154 | +BTF_ID_FLAGS(func, scx_bpf_get_idle_cpumask_node, KF_IMPLICIT_ARGS | KF_ACQUIRE) | |
| 10155 | +BTF_ID_FLAGS(func, scx_bpf_get_idle_smtmask, KF_IMPLICIT_ARGS | KF_ACQUIRE) | |
| 10156 | +BTF_ID_FLAGS(func, scx_bpf_get_idle_smtmask_node, KF_IMPLICIT_ARGS | KF_ACQUIRE) | |
| 10157 | +BTF_ID_FLAGS(func, scx_bpf_put_idle_cpumask, KF_RELEASE) | |
| 10158 | +BTF_ID_FLAGS(func, scx_bpf_test_and_clear_cpu_idle, KF_IMPLICIT_ARGS) | |
| 10159 | +BTF_ID_FLAGS(func, scx_bpf_pick_idle_cpu, KF_IMPLICIT_ARGS | KF_RCU) | |
| 10160 | +BTF_ID_FLAGS(func, scx_bpf_pick_idle_cpu_node, KF_IMPLICIT_ARGS | KF_RCU) | |
| 10161 | +BTF_ID_FLAGS(func, scx_bpf_pick_any_cpu, KF_IMPLICIT_ARGS | KF_RCU) | |
| 10162 | +BTF_ID_FLAGS(func, scx_bpf_pick_any_cpu_node, KF_IMPLICIT_ARGS | KF_RCU) | |
| 10163 | +BTF_KFUNCS_END(scx_kfunc_ids_cpu_only) | |
| 10164 | + | |
| 10124 | 10165 | /* |
| 10125 | 10166 | * Per-op kfunc allow flags. Each bit corresponds to a context-sensitive kfunc |
| 10126 | 10167 | * group; an op may permit zero or more groups, with the union expressed in |
| @@ -10184,6 +10225,7 @@ int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id) · 57 unmodified lines | ||
| 10184 | 10225 | bool in_cpu_release = btf_id_set8_contains(&scx_kfunc_ids_cpu_release, kfunc_id); |
| 10185 | 10226 | bool in_idle = btf_id_set8_contains(&scx_kfunc_ids_idle, kfunc_id); |
| 10186 | 10227 | bool in_any = btf_id_set8_contains(&scx_kfunc_ids_any, kfunc_id); |
| 10228 | + bool in_cpu_only = btf_id_set8_contains(&scx_kfunc_ids_cpu_only, kfunc_id); | |
| 10187 | 10229 | u32 moff, flags; |
| 10188 | 10230 | |
| 10189 | 10231 | /* Not an SCX kfunc - allow. */ |
| @@ -10221,6 +10263,15 @@ int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id) · 31 unmodified lines | ||
| 10221 | 10263 | prog->aux->st_ops != &bpf_sched_ext_ops_cid) |
| 10222 | 10264 | return -EACCES; |
| 10223 | 10265 | |
| 10266 | + /* | |
| 10267 | + * cid-form schedulers must use cid/cmask kfuncs. cid and cpu are both | |
| 10268 | + * small s32s and trivially confused, so cpu-only kfuncs are rejected at | |
| 10269 | + * load time. The reverse (cpu-form calling cid-form kfuncs) is | |
| 10270 | + * intentionally permissive to ease gradual cpumask -> cid migration. | |
| 10271 | + */ | |
| 10272 | + if (prog->aux->st_ops == &bpf_sched_ext_ops_cid && in_cpu_only) | |
| 10273 | + return -EACCES; | |
| 10274 | + | |
| 10224 | 10275 | /* SCX struct_ops: check the per-op allow list. */ |
| 10225 | 10276 | if (in_any || in_idle) |
| 10226 | 10277 | return 0; |