@samitouri / QOSamiQemu / commits / df67805ee9

hw/nvme: fix cross-namespace copy dif buffer overflow

The NVMe specification allows a controller with multiple namespaces to use different LBA formats per namespace. One implication of this is that the destination namespace may have a metadata area for PI, but the source does not. In that case, the controller shall generate the protection information, but the bounce buffer is erroneously allocated without space for that, causing a buffer overflow. Fix the allocation. Cc: qemu-stable@nongnu.org Fixes: d522aef88d42 ("hw/nvme: add cross namespace copy support") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3387 Reported-by: Jihe Wang <wangjihe.mail@gmail.com> Reported-by: boy juju <agx1657748706@gmail.com> Reported-by: contact <contact@xchglabs.com> Reported-by: david korczynski <david@adalogics.com> Reported-by: Brian Chastain (off_by_one / Curious-Keeper) <brian@scalingsuccess.io> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>

Klaus Jensen committed Jul 28, 2026 at 12:37 UTC df67805ee9b15f4c7d54f0e6276d8f9889ec36c4
1 file changed +6 -3
hw/nvme/ctrl.c
+6 -3
@@ -3210,7 +3210,7 @@ static void nvme_do_copy(NvmeCopyAIOCB *iocb)
3210 uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
3211 uint64_t slba;
3212 uint32_t nlb;
3213 - size_t len;
3213 + size_t len, blen;
3214 uint16_t status;
3215 uint32_t dnsid = le32_to_cpu(req->cmd.nsid);
3216 uint32_t snsid = dnsid;
@@ -3331,10 +3331,13 @@ static void nvme_do_copy(NvmeCopyAIOCB *iocb)
3331 }
3332
3333 g_free(iocb->bounce);
3334 - iocb->bounce = g_malloc_n(le16_to_cpu(sns->id_ns.mssrl),
3335 - sns->lbasz + sns->lbaf.ms);
3334 + assert(g_size_checked_mul(&blen, le16_to_cpu(sns->id_ns.mssrl),
3335 + sns->lbasz + MAX(sns->lbaf.ms, dns->lbaf.ms)));
3336 +
3337 + iocb->bounce = g_malloc(blen);
3338
3339 qemu_iovec_reset(&iocb->iov);
3340 + assert(len <= blen);
3341 qemu_iovec_add(&iocb->iov, iocb->bounce, len);
3342
3343 block_acct_start(blk_get_stats(sns->blkconf.blk), &iocb->acct.read, 0,