diff options
Diffstat (limited to 'net/ceph')
| -rw-r--r-- | net/ceph/osd_client.c | 30 | ||||
| -rw-r--r-- | net/ceph/osdmap.c | 2 |
2 files changed, 32 insertions, 0 deletions
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 28d76c2f6b3e..f36ce5ae7568 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> @@ -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 @@ next_op: 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; diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index d6282f0bcff8..cf34b35c9a90 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -517,6 +517,8 @@ static struct crush_map *crush_decode(void *pbyval, void *end) ceph_decode_need(p, end, 4*sizeof(u32), bad); b->id = ceph_decode_32(p); + if (b->id != -1 - i) + goto bad; b->type = ceph_decode_16(p); if (b->type == 0) goto bad; |
