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 | .filter = scx_kfunc_context_filter, | 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 | * Per-op kfunc allow flags. Each bit corresponds to a context-sensitive kfunc | 10166 | * Per-op kfunc allow flags. Each bit corresponds to a context-sensitive kfunc |
| 10126 | * group; an op may permit zero or more groups, with the union expressed in | 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 | bool in_cpu_release = btf_id_set8_contains(&scx_kfunc_ids_cpu_release, kfunc_id); | 10225 | bool in_cpu_release = btf_id_set8_contains(&scx_kfunc_ids_cpu_release, kfunc_id); |
| 10185 | bool in_idle = btf_id_set8_contains(&scx_kfunc_ids_idle, kfunc_id); | 10226 | bool in_idle = btf_id_set8_contains(&scx_kfunc_ids_idle, kfunc_id); |
| 10186 | bool in_any = btf_id_set8_contains(&scx_kfunc_ids_any, kfunc_id); | 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 | u32 moff, flags; | 10229 | u32 moff, flags; |
| 10188 | 10230 | ||
| 10189 | /* Not an SCX kfunc - allow. */ | 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 | prog->aux->st_ops != &bpf_sched_ext_ops_cid) | 10263 | prog->aux->st_ops != &bpf_sched_ext_ops_cid) |
| 10222 | return -EACCES; | 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 | /* SCX struct_ops: check the per-op allow list. */ | 10275 | /* SCX struct_ops: check the per-op allow list. */ |
| 10225 | if (in_any || in_idle) | 10276 | if (in_any || in_idle) |
| 10226 | return 0; | 10277 | return 0; |