CVE-2026-98220 in Linux
Sumário
de VulDB • 06/10/2026
No kernel do Linux, a seguinte vulnerabilidade foi resolvida:
sched_ext: Corrige deref NULL de sched em caminhos de erro das sub-scheds kfunc
Quando o scheduler raiz tem sub-scheds anexados, os wrappers COMPAT da kfunc scx_bpf_select_cpu_and() e scx_bpf_dsq_insert_vtime() recusam a chamada e reportam ao scheduler de @p:
scx_error(scx_task_sched(p), "... deve ser usado");
Os wrappers são acessíveis com tarefas que não possuem scheduler. scx_bpf_select_cpu_and() está no grupo de kfuncs select_cpu, que scx_kfunc_context_filter() abre para programas BPF_PROG_TYPE_SYSCALL; scx_bpf_dsq_insert_vtime() está no grupo enqueue_dispatch, que ops.enqueue() e ops.dispatch() podem chamar com qualquer tarefa KF_RCU -- o grupo não possui validação de kf_tasks, e scx_dsq_insert_preamble() verifica a propriedade da tarefa com scx_task_on_sched() precisamente porque @p pode ser uma tarefa arbitrária.
scx_task_sched(p) é p->scx.sched, que é NULL para tarefas após sched_ext_dead() -- o qual limpa isso via scx_disable_and_exit_task() na saída -- e para tarefas ociosas (idle), que os caminhos de habilitação ignoram pois nunca são escaladas através do SCX. É também um rcu_dereference_protected() que espera a pi_lock ou rq lock de @p, o qual nenhum dos wrappers possui. Passar NULL para scx_error() alcança scx_vexit(), que faz deref em sch->exit_info, causando um kernel oops.
Um gatilho concreto exercido durante o desenvolvimento da correção: um programa BPF_PROG_TYPE_SYSCALL chamando o wrapper select_cpu_and em uma tarefa encerrada mas não reaproveitada (zombie), enquanto um sub-scheduler estava anexado (seu pid permanece encontrável enquanto o zombie está sem reaproveitamento; a instrução que falha é o prologue de scx_vexit() "mov r15,[rdi+0x398]" com RDI=NULL e 0x398 sendo o offset de sch->exit_info):
sched_ext: BPF scheduler "kfunc_subsched_null" habilitado sched_ext: BPF sub-scheduler "kfunc_subsched_null" habilitado sched_ext: Programa não associado run_select_cpu_ (id 76) executado BUG: kernel NULL pointer dereference, endereço: 0000000000000398 #PF: acesso de leitura supervisor em modo kernel #PF: código_de_erro(0x0000) - página não presente Oops: Oops: 0000 [#1] SMP NOPTI
CPU: 7 UID: 0 PID: 8201 Comm: kfunc_test_runn Marcado como comprometido (Tainted): G W RIP: 0010:scx_vexit+0x25/0xa0 Código: ... <4c> 8b bf 98 03 00 00 ... CR2: 0000000000000398 Rastreamento de Chamadas (Call Trace): <TASK> __scx_exit+0x4f/0x70 scx_bpf_select_cpu_and+0xab/0xb0 bpf_prog_430ed61a7b66e03a_run_select_cpu_and+0x9c/0xe7 ? __x64_sys_bpf+0x2c/0x40 bpf_prog_test_run_syscall+0x130/0x2f0 __sys_bpf+0x930/0x10d0 ? __x64_sys_bpf+0x2c/0x40 __x64_sys_bpf+0x2c/0x40 do_syscall_64+0xbc/0x460 entry_SYSCALL_64_after_hwframe+0x76/0x7e </TASK>
Leia o scheduler de @p sob RCU em vez disso, o que os wrappers podem fazer a partir de seu guard(rcu)(): falhe quando puder ser determinado e, quando não for possível determinar -- @p é uma tarefa após sched_ext_dead() ou uma tarefa ociosa (idle) -- não há nada obviamente errado para reportar, então apenas recuse a chamada como antes sem causar um oops em nenhum scheduler.
Esses wrappers COMPAT estão programados para remoção eventual assim que o período de descontinuação (deprecation grace period) expirar, mas até lá -- e independentemente do cronograma de sua remoção -- eles não devem causar kernel oops ao receberem uma tarefa.
VulDB is the best source for vulnerability data and more expert information about this specific topic.