From: Max Kellermann <max.kellermann@ionos.com>
To: idryomov@gmail.com, amarkuze@redhat.com, xiubo.li@clyso.com,
ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Max Kellermann <max.kellermann@ionos.com>, stable@vger.kernel.org
Subject: [PATCH v4 1/3] ceph: fix use-after-free in check_new_map() after early session put
Date: Fri, 4 Sep 2026 17:03:02 +0200 [thread overview]
Message-ID: <20260904150304.49104-2-max.kellermann@ionos.com> (raw)
In-Reply-To: <20260904150304.49104-1-max.kellermann@ionos.com>
check_new_map() drops mdsc->mutex while it locks a session, prepares a
reconnect, or kicks flushing caps. A concurrent teardown can call
__unregister_session() in that window and drop the sessions[]
reference. When check_new_map() reacquires mdsc->mutex, its temporary
reference may therefore be the only reference keeping the local
variable `s` alive.
Commit ee611a750955 ("ceph: fix UAF in check_new_map() on session freed
during unlock") addressed this by taking a temporary reference around
each unlock window, but it drops that reference as soon as mdsc->mutex
is reacquired, while `s` is still in use:
ceph_get_mds_session(s);
mutex_unlock(&mdsc->mutex);
mutex_lock(&s->s_mutex);
mutex_lock(&mdsc->mutex);
ceph_put_mds_session(s); /* may drop the last reference */
ceph_con_close(&s->s_con); /* use-after-free */
mutex_unlock(&s->s_mutex); /* use-after-free */
s->s_state = CEPH_MDS_SESSION_RESTARTING;
If the session was unregistered during the window, the sessions[]
reference is already gone, so this ceph_put_mds_session() frees it.
Additionally, the session could be freed while its s_mutex is locked,
which trips the WARN_ON(mutex_is_locked(&s->s_mutex)) in
ceph_put_mds_session() and then unlocks freed memory.
Fix this by holding a single reference for the whole loop iteration:
look the session up with __ceph_lookup_mds_session(), which returns it
with a reference held, and release that reference on every exit from
the loop body. This subsumes the per-window get/put pairs, so remove
them.
Fixes: ee611a750955 ("ceph: fix UAF in check_new_map() on session freed during unlock")
Cc: stable@vger.kernel.org
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
---
Note the stable maintainers: this is a fixup for ee611a750955, but the
bug has existed before; see
https://lore.kernel.org/ceph-devel/20260828174504.1247038-2-max.kellermann@ionos.com/
for a patch that applies to pre-7.2 kernel versions.
---
fs/ceph/mds_client.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index a091f77cedaf..d36a114747ae 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -5860,9 +5860,9 @@ static void check_new_map(struct ceph_mds_client *mdsc,
}
for (i = 0; i < oldmap->possible_max_rank && i < mdsc->max_sessions; i++) {
- if (!mdsc->sessions[i])
+ s = __ceph_lookup_mds_session(mdsc, i);
+ if (!s)
continue;
- s = mdsc->sessions[i];
oldstate = ceph_mdsmap_get_state(oldmap, i);
newstate = ceph_mdsmap_get_state(newmap, i);
@@ -5875,7 +5875,6 @@ static void check_new_map(struct ceph_mds_client *mdsc,
if (i >= newmap->possible_max_rank) {
/* force close session for stopped mds */
- ceph_get_mds_session(s);
__unregister_session(mdsc, s);
__wake_requests(mdsc, &s->s_waiting);
mutex_unlock(&mdsc->mutex);
@@ -5896,15 +5895,14 @@ static void check_new_map(struct ceph_mds_client *mdsc,
ceph_mdsmap_get_addr(newmap, i),
sizeof(struct ceph_entity_addr))) {
/* just close it */
- ceph_get_mds_session(s);
mutex_unlock(&mdsc->mutex);
mutex_lock(&s->s_mutex);
mutex_lock(&mdsc->mutex);
- ceph_put_mds_session(s);
ceph_con_close(&s->s_con);
mutex_unlock(&s->s_mutex);
s->s_state = CEPH_MDS_SESSION_RESTARTING;
} else if (oldstate == newstate) {
+ ceph_put_mds_session(s);
continue; /* nothing new with this mds */
}
@@ -5915,7 +5913,6 @@ static void check_new_map(struct ceph_mds_client *mdsc,
newstate >= CEPH_MDS_STATE_RECONNECT) {
int rc;
- ceph_get_mds_session(s);
mutex_unlock(&mdsc->mutex);
clear_bit(i, targets);
rc = send_mds_reconnect(mdsc, s);
@@ -5924,7 +5921,6 @@ static void check_new_map(struct ceph_mds_client *mdsc,
"mds%d reconnect failed: %d\n",
i, rc);
mutex_lock(&mdsc->mutex);
- ceph_put_mds_session(s);
}
/*
@@ -5937,15 +5933,14 @@ static void check_new_map(struct ceph_mds_client *mdsc,
pr_info_client(cl, "mds%d recovery completed\n",
s->s_mds);
kick_requests(mdsc, i);
- ceph_get_mds_session(s);
mutex_unlock(&mdsc->mutex);
mutex_lock(&s->s_mutex);
mutex_lock(&mdsc->mutex);
- ceph_put_mds_session(s);
ceph_kick_flushing_caps(mdsc, s);
mutex_unlock(&s->s_mutex);
wake_up_session_caps(s, RECONNECT);
}
+ ceph_put_mds_session(s);
}
/*
--
2.47.3
next prev parent reply other threads:[~2026-09-04 15:03 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-04 15:03 [PATCH v4 0/3] ceph: don't unregister an MDS session before removing its caps Max Kellermann
2026-09-04 15:03 ` Max Kellermann [this message]
2026-09-05 1:52 ` [PATCH v4 1/3] ceph: fix use-after-free in check_new_map() after early session put Xiubo Li
2026-09-04 15:03 ` [PATCH v4 2/3] ceph: stop checking a stale MDS map after dropping mutex Max Kellermann
2026-09-05 1:52 ` Xiubo Li
2026-09-04 15:03 ` [PATCH v4 3/3] ceph: don't unregister an MDS session before removing its caps Max Kellermann
2026-09-05 1:56 ` Xiubo Li
2026-09-07 19:15 ` Max Kellermann
2026-09-08 1:34 ` Xiubo Li
2026-09-05 15:05 ` [v4,3/3] " Alex Markuze
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260904150304.49104-2-max.kellermann@ionos.com \
--to=max.kellermann@ionos.com \
--cc=amarkuze@redhat.com \
--cc=ceph-devel@vger.kernel.org \
--cc=idryomov@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=xiubo.li@clyso.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.