From 2303e69f36ac83a6a8df304f2afdb6187b528e3d Mon Sep 17 00:00:00 2001 From: Jeffle Xu Date: Wed, 29 Jul 2020 11:40:25 +0800 Subject: [PATCH 1866/2944] alinux: virtio-blk: fix discard buffer overrun fix #29557176 For DISCARD request, the generic block layer may not guarantee that @req->nr_phys_segments equals the number of bios in the request. In that case, we are in risk of overruning virtio_blk_discard_write_zeroes buffers. commit 8cb6af7b3a6d ("nvme: Fix discard buffer overrun") has fixed the similar issue in nvme driver. Signed-off-by: Jeffle Xu Reviewed-by: Joseph Qi --- drivers/block/virtio_blk.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 4adbf93..921b4b1 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -208,12 +208,19 @@ static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap) u64 sector = bio->bi_iter.bi_sector; u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT; - range[n].flags = cpu_to_le32(flags); - range[n].num_sectors = cpu_to_le32(num_sectors); - range[n].sector = cpu_to_le64(sector); + if (n < segments) { + range[n].flags = cpu_to_le32(flags); + range[n].num_sectors = cpu_to_le32(num_sectors); + range[n].sector = cpu_to_le64(sector); + } n++; } + if (WARN_ON_ONCE(n != segments)) { + kfree(range); + return -EIO; + } + req->special_vec.bv_page = virt_to_page(range); req->special_vec.bv_offset = offset_in_page(range); req->special_vec.bv_len = sizeof(*range) * segments; @@ -335,8 +342,14 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) { err = virtblk_setup_discard_write_zeroes(req, unmap); - if (err) - return BLK_STS_RESOURCE; + if (err) { + switch (err) { + case -ENOMEM: + return BLK_STS_RESOURCE; + default: + return BLK_STS_IOERR; + } + } } num = blk_rq_map_sg(hctx->queue, req, vbr->sg); -- 1.8.3.1