CVE-2026-89675 in Linux
Sumário
de VulDB • 12/09/2026
No kernel do Linux, a seguinte vulnerabilidade foi resolvida:
nfsd: corrige UAF no cancelamento de cópia assíncrona e desligamento
Uma cópia assíncrona poderia ser liberada ou utilizada após o livre (use-after-free) enquanto um chamador de teardown (OFFLOAD_CANCEL, nfsd4_shutdown_copy, nfsd4_cancel_copy_by_sb) entrava em condição de corrida com a thread da cópia:
- find_async_copy() incrementava copy->refcount, mas deixava a cópia em clp->async_copies, então o cleanup_async_copy() do reaper poderia executar release_copy_files() concorrentemente com um chamador de cancelamento/desligamento. Ambos faziam put e NULL em nf_src/nf_dst sem uma trava comum, causando double-put no nfsd_file e liberando-o prematuramente.
- nfsd4_do_async_copy() definia NFSD4_COPY_F_STOPPED antes dos seus usos finais da cópia (nfsd_update_cmtime_attr() em copy->nf_dst, nfsd4_send_cb_offload()). nfsd4_stop_copy() trata um bit STOPPED definido como "kthread concluída, pule kthread_stop()", então um chamador de teardown executava release_copy_files() -- que faz put e NULLs em nf_dst -- enquanto a kthread ainda o dereferenciava (NULL/UAF).
- copy->copy_task nunca foi mantido. A kthread auto-reap única no retorno, então get_task_struct()' do kthread_stop() poderia tocar um task_struct já liberado.
- co_cb está embutida na cópia, mas nfsd4_send_cb_offload() manteve uma referência apenas no cliente, então um teardown concorrente poderia liberar a cópia enquanto o callback CB_OFFLOAD estava em trânsito.
Corrigir o ciclo de vida do teardown como um todo:
- find_async_copy() desvincula a cópia (limpa cp_clp, list_del_init) sob async_lock; os caminhos de cancelamento, desligamento e sb-cancel liberam a referência de membro da lista via nfs4_put_copy() após nfsd4_stop_copy(). Remove o ajuste redundante de list_del do cleanup_async_copy().
- Como a desvinculação esconde a cópia do reaper, seu cleanup_async_copy() não pode mais remover a entrada s2s_cp_stateids da cópia; os caminhos cancel/shutdown/sb-cancel agora chamam nfs4_free_copy_state() eles mesmos (enquanto cp_clp ainda é válido) para que a entrada não fique pendurada em memória liberada para o laundromat e manage_cpntf_state() dereferenciá-la.
- Dê à kthread sua própria referência, obtida em nfsd4_copy() antes de wake_up_process() e solta no final de nfsd4_do_async_copy(); chame wake_up_process() antes de list_add().
- Mantenha o task_struct com get_task_struct() em nfsd4_copy(), liberado em nfs4_put_copy(), para que kthread_stop() seja seguro sempre que a kthread sair. Defina NFSD4_COPY_F_STOPPED apenas em nfsd4_stop_copy(), que agora sempre executa kthread_stop() antes de release_copy_files(); a conclusão ainda é relatada via NFSD4_COPY_F_COMPLETED, então nfsd4_has_active_async_copies() não é afetado. Cada chamador de teardown remove primeiro a cópia de clp->async_copies, para que kthread_stop() seja executado exatamente uma vez.
- Obtenha uma referência da cópia em nfsd4_send_cb_offload(), liberada em nfsd4_cb_offload_release(). A kthread ainda mantém sua própria referência lá, então o refcount_inc() não entra em condição de corrida com a liberação final.
- Leia cp_clp com smp_load_acquire() para parear com os escritores set_bit()/clear_bit() desordenados (Documentation/atomic_bitops.rst).
If you want to get best quality of vulnerability data, you may have to visit VulDB.