diff options
author | Xi Wang <xi.wang@gmail.com> | 2012-04-20 22:49:44 +0200 |
---|---|---|
committer | Alex Elder <elder@dreamhost.com> | 2012-05-14 19:12:41 +0200 |
commit | 50f7c4c967d0b5acd8e7ba6ab654dc4a7ac869ac (patch) | |
tree | a37aa5a2aad9e434bf6b77e0b65601b6e30589b2 /drivers/block | |
parent | rbd: use gfp_flags parameter in rbd_header_from_disk() (diff) | |
download | linux-50f7c4c967d0b5acd8e7ba6ab654dc4a7ac869ac.tar.xz linux-50f7c4c967d0b5acd8e7ba6ab654dc4a7ac869ac.zip |
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) */ static int rbd_header_from_disk(struct rbd_image_header *header, struct rbd_image_header_ondisk *ondisk, - int allocated_snaps, + u32 allocated_snaps, gfp_t gfp_flags) { - int i; - u32 snap_count; + u32 i, snap_count; if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT))) return -ENXIO; snap_count = le32_to_cpu(ondisk->snap_count); + if (snap_count > (UINT_MAX - sizeof(struct ceph_snap_context)) + / sizeof (*ondisk)) + return -EINVAL; header->snapc = kmalloc(sizeof(struct ceph_snap_context) + snap_count * sizeof (*ondisk), gfp_flags); @@ -1591,7 +1593,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev, { ssize_t rc; struct rbd_image_header_ondisk *dh; - int snap_count = 0; + u32 snap_count = 0; u64 ver; size_t len; |