Saltar al contenido
CVE-2026-89675 Fuente: CVE.org Publicada · sin explotación confirmada

Vulnerabilidad de uso después de liberar memoria (use-after-free) en Linux kernel (nfsd)

Linux · Linux · Publicada en CVE.org el 11-09-2026 · Última actualización: 09-11-2026

Descripción

En el Linux kernel se resolvió la siguiente vulnerabilidad: nfsd: corrección de uso después de liberar memoria (use-after-free) en la cancelación y el apagado de copias asíncronas Una copia asíncrona podía liberarse o usarse después de liberada mientras una función de desmontaje (OFFLOAD_CANCEL, nfsd4_shutdown_copy, nfsd4_cancel_copy_by_sb) competía con el kthread de copia: - find_async_copy() incrementaba copy->refcount pero dejaba la copia en clp->async_copies, por lo que cleanup_async_copy() del reaper podía ejecutar release_copy_files() de forma concurrente con una función de cancelación/apagado. Ambas liberaban y ponían en NULL nf_src/nf_dst sin un bloqueo común, liberando dos veces la referencia de nfsd_file y liberándolo antes de tiempo. - nfsd4_do_async_copy() establecía NFSD4_COPY_F_STOPPED antes de sus últimos usos de la copia (nfsd_update_cmtime_attr() sobre copy->nf_dst, nfsd4_send_cb_offload()). nfsd4_stop_copy() interpreta el bit STOPPED activo como "kthread terminado, omitir kthread_stop()", por lo que una función de desmontaje ejecutaba release_copy_files() (que libera y pone en NULL nf_dst) mientras el kthread aún lo desreferenciaba (NULL/use-after-free). - copy->copy_task nunca se fijaba. El kthread de un solo uso se libera a sí mismo al retornar, por lo que get_task_struct() de kthread_stop() podía acceder a un task_struct liberado. - co_cb está incrustado en la copia, pero nfsd4_send_cb_offload() mantenía una referencia solo sobre el cliente, por lo que un desmontaje concurrente podía liberar la copia mientras la callback CB_OFFLOAD estaba en curso. Se corrige el ciclo de vida del desmontaje en su conjunto: - find_async_copy() desvincula la copia (borra cp_clp, list_del_init) bajo async_lock; las rutas de cancelación, apagado y sb-cancel liberan la referencia de pertenencia a la lista mediante nfs4_put_copy() después de nfsd4_stop_copy(). Se elimina el ajuste list_del, ahora redundante, de cleanup_async_copy(). - Como la desvinculación oculta la copia al reaper, su cleanup_async_copy() ya no puede eliminar la entrada s2s_cp_stateids de la copia; las rutas de cancelación/apagado/sb-cancel ahora llaman ellas mismas a nfs4_free_copy_state() (mientras cp_clp aún es válido), de modo que la entrada no quede apuntando a memoria liberada que el laundromat y manage_cpntf_state() puedan desreferenciar. - Se da al kthread su propia referencia, tomada en nfsd4_copy() antes de wake_up_process() y liberada al final de nfsd4_do_async_copy(); se llama a wake_up_process() antes de list_add(). - Se fija el task_struct con get_task_struct() en nfsd4_copy(), liberado en nfs4_put_copy(), para que kthread_stop() sea seguro cada vez que el kthread termine. NFSD4_COPY_F_STOPPED se establece solo en nfsd4_stop_copy(), que ahora siempre ejecuta kthread_stop() antes de release_copy_files(); la finalización se sigue informando mediante NFSD4_COPY_F_COMPLETED, por lo que nfsd4_has_active_async_copies() no se ve afectada. Cada función de desmontaje elimina primero la copia de clp->async_copies, por lo que kthread_stop() se ejecuta exactamente una vez. - Se toma una referencia de la copia en nfsd4_send_cb_offload(), liberada en nfsd4_cb_offload_release(). El kthread aún mantiene su propia referencia en ese punto, por lo que refcount_inc() no puede competir con la liberación final. - Se lee cp_clp con smp_load_acquire() para emparejarlo con las escrituras no ordenadas set_bit()/clear_bit() (Documentation/atomic_bitops.rst).

Qué hacer

Revisa si usas el producto afectado y en qué versión, y aplica la actualización o la mitigación que indique el aviso del fabricante. CISA no ha confirmado que se esté explotando; si eso cambia, esta ficha pasa a «explotada» y te avisamos en el boletín.

Versiones afectadas

  • Linux Afectadas: e0639dc5805a9d4faaa2c07ad98fa853b9529dd3 y anteriores a 9031493ef7369d5c59c4bacc96f0c85965f09a98 · e0639dc5805a9d4faaa2c07ad98fa853b9529dd3 y anteriores a a385cf5e016b748babf94cc664e43a26e17db117 · e0639dc5805a9d4faaa2c07ad98fa853b9529dd3 y anteriores a 62c0f6eaf050bb9284c1f9cac6ed1770092e6b95
  • Linux Afectadas: 4.20 No afectadas: 6.18.51 · 7.2.4 · 7.3

Según el registro de la vulnerabilidad en CVE.org, tal como lo publicó el fabricante. Confirma tu versión exacta en el aviso del fabricante.

Referencias

Ver el texto original en inglés (CVE.org)

nfsd: fix UAF in async copy cancel and shutdown

In the Linux kernel, the following vulnerability has been resolved: nfsd: fix UAF in async copy cancel and shutdown An async copy could be freed or used after free while a teardown caller (OFFLOAD_CANCEL, nfsd4_shutdown_copy, nfsd4_cancel_copy_by_sb) raced the copy kthread: - find_async_copy() bumped copy->refcount but left the copy on clp->async_copies, so the reaper's cleanup_async_copy() could run release_copy_files() concurrently with a cancel/shutdown caller. Both put and NULL nf_src/nf_dst without a common lock, double-putting the nfsd_file and freeing it early. - nfsd4_do_async_copy() set NFSD4_COPY_F_STOPPED before its final uses of the copy (nfsd_update_cmtime_attr() on copy->nf_dst, nfsd4_send_cb_offload()). nfsd4_stop_copy() treats a set STOPPED bit as "kthread done, skip kthread_stop()", so a teardown caller ran release_copy_files() -- which puts and NULLs nf_dst -- while the kthread still dereferenced it (NULL/UAF). - copy->copy_task was never pinned. The one-shot kthread self-reaps on return, so kthread_stop()'s get_task_struct() could touch a freed task_struct. - co_cb is embedded in the copy, but nfsd4_send_cb_offload() held a reference only on the client, so a concurrent teardown could free the copy while the CB_OFFLOAD callback was in flight. Fix the teardown lifetime as a whole: - find_async_copy() unlinks the copy (clear cp_clp, list_del_init) under async_lock; the cancel, shutdown, and sb-cancel paths drop the list-membership reference via nfs4_put_copy() after nfsd4_stop_copy(). Drop the now-redundant list_del fixup from cleanup_async_copy(). - Because unlinking hides the copy from the reaper, its cleanup_async_copy() can no longer remove the copy's s2s_cp_stateids entry; the cancel/shutdown/sb-cancel paths now call nfs4_free_copy_state() themselves (while cp_clp is still valid) so the entry does not dangle at freed memory for the laundromat and manage_cpntf_state() to dereference. - Give the kthread its own reference, taken in nfsd4_copy() before wake_up_process() and dropped at the end of nfsd4_do_async_copy(); call wake_up_process() before list_add(). - Pin the task_struct with get_task_struct() in nfsd4_copy(), released in nfs4_put_copy(), so kthread_stop() is safe whenever the kthread exits. Set NFSD4_COPY_F_STOPPED only in nfsd4_stop_copy(), which now always kthread_stop()s before release_copy_files(); completion is still reported via NFSD4_COPY_F_COMPLETED, so nfsd4_has_active_async_copies() is unaffected. Each teardown caller removes the copy from clp->async_copies first, so kthread_stop() runs exactly once. - Take a copy reference in nfsd4_send_cb_offload(), dropped in nfsd4_cb_offload_release(). The kthread still holds its own reference there, so the refcount_inc() cannot race the final free. - Read cp_clp with smp_load_acquire() to pair with the unordered set_bit()/clear_bit() writers (Documentation/atomic_bitops.rst).

Recibe el boletín cuando CISA agregue vulnerabilidades nuevas

Te escribimos solo cuando CISA agrega vulnerabilidades nuevas, ya traducidas: cada día que haya, o en un resumen los lunes. Confirmas por correo y te das de baja con un clic.

Frecuencia