diff options
author | Xi Wang <xi.wang@gmail.com> | 2012-04-20 16:49:44 -0400 |
---|---|---|
committer | Alex Elder <elder@dreamhost.com> | 2012-05-14 13:12:41 -0400 |
commit | 50f7c4c967d0b5acd8e7ba6ab654dc4a7ac869ac (patch) | |
tree | a37aa5a2aad9e434bf6b77e0b65601b6e30589b2 /drivers/block | |
parent | f8ad495a8a0277b88c59bf38319e5e944aaf5a4a (diff) |
rbd: fix integer overflow in rbd_header_from_disk()
ondisk->snap_count is read from disk via rbd_req_sync_read() and thus
needs validation. Otherwise, a bogus `snap_count' could overflow the
kmalloc() size, leading to memory corruption.
Also use `u32' consistently for `snap_count'.
[elder@dreamhost.com: changed to use UINT_MAX rather than ULONG_MAX]
Signed-off-by: Xi Wang <xi.wang@gmail.com>
Reviewed-by: Alex Elder <elder@dreamhost.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/rbd.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index ca59d4d9471e..a75fe93a25b1 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -487,16 +487,18 @@ static void rbd_coll_release(struct kref *kref) | |||
487 | */ | 487 | */ |
488 | static int rbd_header_from_disk(struct rbd_image_header *header, | 488 | static int rbd_header_from_disk(struct rbd_image_header *header, |
489 | struct rbd_image_header_ondisk *ondisk, | 489 | struct rbd_image_header_ondisk *ondisk, |
490 | int allocated_snaps, | 490 | u32 allocated_snaps, |
491 | gfp_t gfp_flags) | 491 | gfp_t gfp_flags) |
492 | { | 492 | { |
493 | int i; | 493 | u32 i, snap_count; |
494 | u32 snap_count; | ||
495 | 494 | ||
496 | if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT))) | 495 | if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT))) |
497 | return -ENXIO; | 496 | return -ENXIO; |
498 | 497 | ||
499 | snap_count = le32_to_cpu(ondisk->snap_count); | 498 | snap_count = le32_to_cpu(ondisk->snap_count); |
499 | if (snap_count > (UINT_MAX - sizeof(struct ceph_snap_context)) | ||
500 | / sizeof (*ondisk)) | ||
501 | return -EINVAL; | ||
500 | header->snapc = kmalloc(sizeof(struct ceph_snap_context) + | 502 | header->snapc = kmalloc(sizeof(struct ceph_snap_context) + |
501 | snap_count * sizeof (*ondisk), | 503 | snap_count * sizeof (*ondisk), |
502 | gfp_flags); | 504 | gfp_flags); |
@@ -1591,7 +1593,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev, | |||
1591 | { | 1593 | { |
1592 | ssize_t rc; | 1594 | ssize_t rc; |
1593 | struct rbd_image_header_ondisk *dh; | 1595 | struct rbd_image_header_ondisk *dh; |
1594 | int snap_count = 0; | 1596 | u32 snap_count = 0; |
1595 | u64 ver; | 1597 | u64 ver; |
1596 | size_t len; | 1598 | size_t len; |
1597 | 1599 | ||