CVE-2026-89675

CVE-2026-89675

Critical · published September 12, 2026

CVSS v3.1
9.8
EPSS
0%
Percentile
37.4
In the wild
Unconfirmed
What it is

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).

The record
Technical detail
CVSS v3.1
9.8 · CRITICAL
Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS v4.0
Not supplied
EPSS
0.00442 · 37.4th percentile
Published
2026-09-12T00:19Z
References (3)
EPSS history
Timeline
  • 13 SEP 03:23Z
    EPSS moved — → 0%
    epss
  • 11 SEP 19:45Z
    nfsd: fix UAF in async copy cancel and shutdown
    cvelistv5