CVE-2026-89675
Riassunto
di VulDB • 11/09/2026
Nel kernel Linux è stata risolta la seguente vulnerabilità:
nfsd: correzione di un Use-After-Free (UAF) nella cancellazione e nello shutdown della copia asincrona
Una copia asincrona potrebbe essere liberata o utilizzata dopo la libera mentre un chiamante per il teardown (OFFLOAD_CANCEL, nfsd4_shutdown_copy, nfsd4_cancel_copy_by_sb) entra in race condition con il kthread di copia:
- find_async_copy() incrementava copy->refcount ma lasciava la copia su clp->async_copies, quindi cleanup_async_copy() del reaper poteva eseguire release_copy_files() in concorrenza con un chiamante per cancel/shutdown. Entrambi eseguivano put e NULL su nf_src/nf_dst senza un lock comune, causando un double-put dell'oggetto nfsd_file e la sua liberazione anticipata.
- nfsd4_do_async_copy() impostava NFSD4_COPY_F_STOPPED prima degli utilizzi finali della copia (nfsd_update_cmtime_attr() su copy->nf_dst, nfsd4_send_cb_offload()). nfsd4_stop_copy() tratta un bit STOPPED impostato come "kthread completato, salta kthread_stop()", quindi un chiamante per il teardown eseguiva release_copy_files() -- che esegue put e NULL su nf_dst -- mentre il kthread lo stava ancora dereferenziando (NULL/UAF).
- copy->copy_task non era mai stato mantenuto attivo. Il kthread one-shot si auto-riappella al ritorno, quindi get_task_struct() di kthread_stop() poteva toccare un task_struct già liberato.
- co_cb è incorporata nella copia, ma nfsd4_send_cb_offload() manteneva una reference solo sul client, quindi un teardown concorrente poteva liberare la copia mentre il callback CB_OFFLOAD era in transito.
Correggere l'intero ciclo di vita del teardown:
- find_async_copy() scollega la copia (azzera cp_clp, list_del_init) sotto async_lock; i percorsi cancel, shutdown e sb-cancel rilasciano la reference di appartenenza alla lista tramite nfs4_put_copy() dopo nfsd4_stop_copy(). Rimuovere il fixup ridondante per list_del da cleanup_async_copy().
- Poiché lo scollegamento nasconde la copia al reaper, cleanup_async_copy() non può più rimuovere l'entry s2s_cp_stateids della copia; i percorsi cancel/shutdown/sb-cancel chiamano ora nfs4_free_copy_state() direttamente (mentre cp_clp è ancora valido) in modo che l'entry non rimanga pendente su memoria liberata per il laundromat e manage_cpntf_state() da dereferenziare.
- Fornire al kthread una propria reference, acquisita in nfsd4_copy() prima di wake_up_process() e rilasciata alla fine di nfsd4_do_async_copy(); chiamare wake_up_process() prima di list_add().
- Mantenere attivo il task_struct con get_task_struct() in nfsd4_copy(), rilasciato in nfs4_put_copy(), in modo che kthread_stop() sia sicuro ogni volta che il kthread termina. Impostare NFSD4_COPY_F_STOPPED solo in nfsd4_stop_copy(), che ora esegue sempre kthread_stop() prima di release_copy_files(); il completamento è ancora segnalato tramite NFSD4_COPY_F_COMPLETED, quindi nfsd4_has_active_async_copies() non viene influenzata. Ogni chiamante per il teardown rimuove innanzitutto la copia da clp->async_copies, in modo che kthread_stop() venga eseguito esattamente una volta.
- Acquisire una reference alla copia in nfsd4_send_cb_offload(), rilasciata in nfsd4_cb_offload_release(). Il kthread mantiene ancora la propria reference lì, quindi refcount_inc() non può entrare in race condition con l'ultima liberazione.
- Leggere cp_clp con smp_load_acquire() per accoppiarsi agli writer set_bit()/clear_bit() non ordinati (Documentation/atomic_bitops.rst).
Be aware that VulDB is the high quality source for vulnerability data.