mirror of
https://github.com/torvalds/linux.git
synced 2026-09-14 16:10:02 +02:00
libceph: validate OSD extent maps before cursor advance
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.
[ idryomov: perform sparse_extent_map_valid() check a bit earlier,
in CEPH_SPARSE_READ_DATA_LEN instead of CEPH_SPARSE_READ_DATA_PRE
state ]
Cc: stable@vger.kernel.org
Fixes: f628d79997 ("libceph: add sparse read support to OSD client")
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
parent
d2a8d446a0
commit
9ec08b7499
|
|
@ -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>
|
||||
|
|
@ -5802,6 +5803,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)
|
||||
|
|
@ -5852,6 +5878,10 @@ static int osd_sparse_read(struct ceph_connection *con,
|
|||
fallthrough;
|
||||
case CEPH_SPARSE_READ_DATA_LEN:
|
||||
convert_extent_map(sr);
|
||||
if (!sparse_extent_map_valid(sr)) {
|
||||
pr_warn_ratelimited("invalid sparse extent map\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
ret = sizeof(sr->sr_datalen);
|
||||
*pbuf = (char *)&sr->sr_datalen;
|
||||
sr->sr_state = CEPH_SPARSE_READ_DATA_PRE;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user