* [PATCH] libceph: validate OSD extent maps before cursor advance
@ 2026-07-10 2:28 Michael Bommarito
0 siblings, 0 replies; only message in thread
From: Michael Bommarito @ 2026-07-10 2:28 UTC (permalink / raw)
To: Ilya Dryomov, Alex Markuze, Viacheslav Dubeyko
Cc: Milind Changire, Xiubo Li, Jeff Layton, ceph-devel, linux-kernel,
stable
net/ceph/osd_client.c:osd_sparse_read() validates that the sparse-read
data length matches the summed extent lengths, but it does not validate
that each OSD-supplied extent is monotonic and lies inside the original
request range. A malformed authenticated OSD reply can advertise a
far-forward nonzero extent offset with a matching data length and make
the client advance the message-data cursor beyond the request buffer.
This reaches the BUG_ON(!*length) assertion in ceph_msg_data_next() from
the client receive path.
Impact: A malicious or compromised authenticated Ceph OSD peer can crash
a kernel Ceph client via a malformed sparse-read reply.
Reject sparse extent maps that overflow, move backwards, overlap, or
extend outside the original sparse-read request before advancing the
cursor.
Fixes: f628d7999727 ("libceph: add sparse read support to OSD client")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
I reproduced this with a same-translation-unit KUnit test on
f5459048c38a, x86_64 with panic_on_oops=1. Without the patch, the
malformed extent triggers kernel BUG at net/ceph/messenger.c:1117 after
the benign in-range control passes. With the patch, the malformed map
returns -EREMOTEIO and both KUnit cases pass; net/ceph/osd_client.o
builds cleanly with W=1.
net/ceph/osd_client.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 2ff00070c1810..76ba3abdad9b1 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -6,6 +6,7 @@
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/mm.h>
+#include <linux/overflow.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -5799,6 +5800,31 @@ static inline void convert_extent_map(struct ceph_sparse_read *sr)
}
#endif
+static bool sparse_extent_map_valid(struct ceph_sparse_read *sr)
+{
+ u64 req_end, pos;
+ int i;
+
+ if (check_add_overflow(sr->sr_req_off, sr->sr_req_len, &req_end))
+ return false;
+
+ pos = sr->sr_req_off;
+ for (i = 0; i < sr->sr_count; i++) {
+ struct ceph_sparse_extent *ext = &sr->sr_extent[i];
+ u64 end;
+
+ if (ext->off < pos)
+ return false;
+ if (check_add_overflow(ext->off, ext->len, &end))
+ return false;
+ if (end > req_end)
+ return false;
+ pos = end;
+ }
+
+ return true;
+}
+
static int osd_sparse_read(struct ceph_connection *con,
struct ceph_msg_data_cursor *cursor,
char **pbuf)
@@ -5856,6 +5882,10 @@ static int osd_sparse_read(struct ceph_connection *con,
case CEPH_SPARSE_READ_DATA_PRE:
/* Convert sr_datalen to host-endian */
sr->sr_datalen = le32_to_cpu((__force __le32)sr->sr_datalen);
+ if (!sparse_extent_map_valid(sr)) {
+ pr_warn_ratelimited("invalid sparse extent map\n");
+ return -EREMOTEIO;
+ }
for (i = 0; i < count; i++)
len += sr->sr_extent[i].len;
if (sr->sr_datalen != len) {
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-10 2:28 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10 2:28 [PATCH] libceph: validate OSD extent maps before cursor advance Michael Bommarito
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox