FAILED: patch "[PATCH] ceph: bound num_export_targets array for mds info v2/v3" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x a3eb169ee297aa99670ba927c659990bd1e453f3
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090336-mashing-extended-23ed@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a3eb169ee297aa99670ba927c659990bd1e453f3 Mon Sep 17 00:00:00 2001
From: Michael Bommarito <[email protected]>
Date: Tue, 7 Jul 2026 14:05:59 -0400
Subject: [PATCH] ceph: bound num_export_targets array for mds info v2/v3
ceph_mdsmap_decode() in fs/ceph/mdsmap.c reads num_export_targets from each per-mds info record and advances the decode cursor by num_export_targets * sizeof(u32) without first checking that many bytes remain. The only upper-bound check that catches a runaway cursor (*p > info_end) is gated on info_v >= 4, because info_end is left NULL for info_v 2 and 3. When the monitor sends an MDS map whose per-mds info version is 2 or 3 with an oversized num_export_targets, the cursor moves past the message front buffer and the later export-targets loop calls the unchecked ceph_decode_32() on out-of-bounds memory.
A kernel client processes CEPH_MSG_MDS_MAP from its monitor session (net/ceph/mon_client.c dispatches it; fs/ceph/super.c routes it to ceph_mdsc_handle_mdsmap(), which sets end to the front buffer bound and calls ceph_mdsmap_decode()). A malicious or compromised monitor, or an on-path attacker on an unsigned/unencrypted messenger session, can therefore drive an out-of-bounds read in the client kernel; on x86_64 with KASAN it is reported as a slab-out-of-bounds read in ceph_mdsmap_decode(). The decoded values land in the internal info->export_targets[] array, so the consequence is a kernel out-of-bounds read, not an information leak to the attacker.
Impact: a malicious or compromised Ceph monitor sending an MDS map with a per-mds info version of 2 or 3 and an oversized num_export_targets field triggers an out-of-bounds read in the CephFS client kernel.
Add a ceph_decode_need() for the export-targets array before advancing the cursor, so the bound is enforced for every info_v >= 2, not only info_v >= 4. This mirrors the count-then-need idiom already used for m_data_pg_pools later in the same function.
Compute the export-targets byte count with size_mul() and reuse that checked length when advancing the cursor, so the attacker-controlled num_export_targets multiplication fails closed on overflow rather than relying on the later kcalloc() guard.
fs/ceph/mdsmap.c +6 -1
@@ -3,6 +3,7 @@#include <linux/bug.h> #include <linux/err.h> +#include <linux/overflow.h> #include <linux/random.h> #include <linux/slab.h> #include <linux/types.h>
@@ -126,6 +127,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p,u8 mdsmap_v;u16 mdsmap_ev;u32 target; +size_t export_targets_len; m =kzalloc_obj (*m,GFP_NOFS );if (!m)
@@ -224,8 +226,11 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, *p += namelen;if (info_v >=2 ) {ceph_decode_32_safe (p, end, num_export_targets, bad); + export_targets_len =size_mul (num_export_targets, +sizeof (u32)); +ceph_decode_need (p, end, export_targets_len, bad); pexport_targets = *p; - *p += num_export_targets *sizeof (u32); + *p += export_targets_len; }else { num_export_targets =0 ; }
Sasha Levin
maintainerPATCH 1/1 ceph: bound num_export_targets array for mds info v2/v3
From: Michael Bommarito <[email protected]>
[ Upstream commit a3eb169ee297aa99670ba927c659990bd1e453f3 ]
ceph_mdsmap_decode() in fs/ceph/mdsmap.c reads num_export_targets from each per-mds info record and advances the decode cursor by num_export_targets * sizeof(u32) without first checking that many bytes remain. The only upper-bound check that catches a runaway cursor (*p > info_end) is gated on info_v >= 4, because info_end is left NULL for info_v 2 and 3. When the monitor sends an MDS map whose per-mds info version is 2 or 3 with an oversized num_export_targets, the cursor moves past the message front buffer and the later export-targets loop calls the unchecked ceph_decode_32() on out-of-bounds memory.
A kernel client processes CEPH_MSG_MDS_MAP from its monitor session (net/ceph/mon_client.c dispatches it; fs/ceph/super.c routes it to ceph_mdsc_handle_mdsmap(), which sets end to the front buffer bound and calls ceph_mdsmap_decode()). A malicious or compromised monitor, or an on-path attacker on an unsigned/unencrypted messenger session, can therefore drive an out-of-bounds read in the client kernel; on x86_64 with KASAN it is reported as a slab-out-of-bounds read in ceph_mdsmap_decode(). The decoded values land in the internal info->export_targets[] array, so the consequence is a kernel out-of-bounds read, not an information leak to the attacker.
Impact: a malicious or compromised Ceph monitor sending an MDS map with a per-mds info version of 2 or 3 and an oversized num_export_targets field triggers an out-of-bounds read in the CephFS client kernel.
Add a ceph_decode_need() for the export-targets array before advancing the cursor, so the bound is enforced for every info_v >= 2, not only info_v >= 4. This mirrors the count-then-need idiom already used for m_data_pg_pools later in the same function.
Compute the export-targets byte count with size_mul() and reuse that checked length when advancing the cursor, so the attacker-controlled num_export_targets multiplication fails closed on overflow rather than relying on the later kcalloc() guard.
--- fs/ceph/mdsmap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/ceph/mdsmap.c +6 -1
@@ -3,6 +3,7 @@#include <linux/bug.h> #include <linux/err.h> +#include <linux/overflow.h> #include <linux/random.h> #include <linux/slab.h> #include <linux/types.h>
@@ -122,6 +123,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end)int err;u8 mdsmap_v;u16 mdsmap_ev; +size_t export_targets_len; m =kzalloc (sizeof (*m),GFP_NOFS );if (!m)
@@ -219,8 +221,11 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) *p += namelen;if (info_v >=2 ) {ceph_decode_32_safe (p, end, num_export_targets, bad); + export_targets_len =size_mul (num_export_targets, +sizeof (u32)); +ceph_decode_need (p, end, export_targets_len, bad); pexport_targets = *p; - *p += num_export_targets *sizeof (u32); + *p += export_targets_len; }else { num_export_targets =0 ; }
Signature · 1 line
2.53.0