Commit df67805ee9 for qemu.org

commit df67805ee9b15f4c7d54f0e6276d8f9889ec36c4
Author: Klaus Jensen <k.jensen@samsung.com>
Date:   Tue Jul 28 12:37:57 2026 +0200

    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>

diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index e1639b3839..acd10fcc67 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -3210,7 +3210,7 @@ static void nvme_do_copy(NvmeCopyAIOCB *iocb)
     uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
     uint64_t slba;
     uint32_t nlb;
-    size_t len;
+    size_t len, blen;
     uint16_t status;
     uint32_t dnsid = le32_to_cpu(req->cmd.nsid);
     uint32_t snsid = dnsid;
@@ -3331,10 +3331,13 @@ static void nvme_do_copy(NvmeCopyAIOCB *iocb)
     }

     g_free(iocb->bounce);
-    iocb->bounce = g_malloc_n(le16_to_cpu(sns->id_ns.mssrl),
-                              sns->lbasz + sns->lbaf.ms);
+    assert(g_size_checked_mul(&blen, le16_to_cpu(sns->id_ns.mssrl),
+                              sns->lbasz + MAX(sns->lbaf.ms, dns->lbaf.ms)));
+
+    iocb->bounce = g_malloc(blen);

     qemu_iovec_reset(&iocb->iov);
+    assert(len <= blen);
     qemu_iovec_add(&iocb->iov, iocb->bounce, len);

     block_acct_start(blk_get_stats(sns->blkconf.blk), &iocb->acct.read, 0,