CVE-2026-89654: ceph: fix UAF in check_new_map() on session freed during unlock
In the Linux kernel, the following vulnerability has been resolved:
ceph: fix UAF in checknewmap() on session freed during unlock
checknewmap() iterates mdsc->sessions[] and for each active session drops mdsc->mutex to perform per-session operations. The forced-close path (rank removed from map) correctly takes a reference on s via cephgetmdssession() before releasing mdsc->mutex, but three other paths do not:
Path A (address changed): mutexunlock → mutexlock(&s->smutex) Path B (reconnect): mutexunlock → sendmdsreconnect(mdsc, s) Path C (active transition): mutexunlock → mutexlock(&s->smutex)
Without the extra reference, another thread can acquire mdsc->mutex during the unlock window, call unregistersession() which drops the last reference on s, and free it. The original thread then accesses freed memory via s->smutex.
Fix by adding cephgetmdssession(s) before each mutexunlock and cephputmdssession(s) after the corresponding mutexlock, matching the pattern already used in the forced-close path.
Race timeline (Path A):
Thread A (checknewmap) Thread B (another map update holds mdsc->mutex or session teardown) -------------------------- -------------------------- s = mdsc->sessions[i] (refcount == 1, held only by sessions[] array)
mutexunlock(&mdsc->mutex) ---> acquires mdsc->mutex unregistersession(mdsc, s) sessions[i] = NULL cephputmdssession(s) refcount: 1 -> 0 kfree(s) <--- freed!
mutexlock(&s->smutex) UAF on freed s->smutex
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Modify Ceph MDS code (check_new_map) so that before releasing mdsc->mutex via mutex_unlock, the code takes an extra reference with ceph_get_mds_session(s); then after mutex_lock(&s->s_mutex) (and the corresponding work), release references with the matching ceph_put_mds_session(s), preventing UAF of s->s_mutex during the unlock window.
Linux kernel (Ceph MDS session handling) Reference management around mdsc->mutex release (ceph_get_mds_session/ceph_put_mds_session) = Add ceph_get_mds_session(s) before each mutex_unlock of mdsc->mutex, and add matching ceph_put_mds_session(s) after the corresponding mutex_lock in check_new_map(); ensure ceph_get_mds_session(s) is taken for sessions[] iterations and released after per-session operations.
Event History
Frequently Asked Questions
Which systems are exposed to this issue?
The issue affects the Ceph code in the Linux kernel where metadata server sessions are processed during map updates. It is relevant to systems using that kernel Ceph functionality.
What must occur for the use-after-free to be triggered?
check_new_map() must release mdsc->mutex while handling an active session, and another thread must unregister and free that session during the unlock window. The original thread can then resume and access the freed session through s->s_mutex or related per-session operations.