Blame SOURCES/kvm-block-nvme-Fix-VFIO_MAP_DMA-failed-No-space-left-on-.patch

a83cc2
From 1d85424fe5208986fc07fe9baa1e9b33d77b185a Mon Sep 17 00:00:00 2001
a83cc2
From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@redhat.com>
a83cc2
Date: Thu, 29 Jul 2021 07:42:35 -0400
a83cc2
Subject: [PATCH 20/39] block/nvme: Fix VFIO_MAP_DMA failed: No space left on
a83cc2
 device
a83cc2
MIME-Version: 1.0
a83cc2
Content-Type: text/plain; charset=UTF-8
a83cc2
Content-Transfer-Encoding: 8bit
a83cc2
a83cc2
RH-Author: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
RH-MergeRequest: 32: Synchronize with RHEL-AV 8.5 release 27 to RHEL 9
a83cc2
RH-Commit: [12/15] f4b3456e4ce1a876a64f9fb92c56f8f981076953 (mrezanin/centos-src-qemu-kvm)
a83cc2
RH-Bugzilla: 1957194
a83cc2
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
a83cc2
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
a83cc2
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
a83cc2
RH-Acked-by: Andrew Jones <drjones@redhat.com>
a83cc2
a83cc2
When the NVMe block driver was introduced (see commit bdd6a90a9e5,
a83cc2
January 2018), Linux VFIO_IOMMU_MAP_DMA ioctl was only returning
a83cc2
-ENOMEM in case of error. The driver was correctly handling the
a83cc2
error path to recycle its volatile IOVA mappings.
a83cc2
a83cc2
To fix CVE-2019-3882, Linux commit 492855939bdb ("vfio/type1: Limit
a83cc2
DMA mappings per container", April 2019) added the -ENOSPC error to
a83cc2
signal the user exhausted the DMA mappings available for a container.
a83cc2
a83cc2
The block driver started to mis-behave:
a83cc2
a83cc2
  qemu-system-x86_64: VFIO_MAP_DMA failed: No space left on device
a83cc2
  (qemu)
a83cc2
  (qemu) info status
a83cc2
  VM status: paused (io-error)
a83cc2
  (qemu) c
a83cc2
  VFIO_MAP_DMA failed: No space left on device
a83cc2
  (qemu) c
a83cc2
  VFIO_MAP_DMA failed: No space left on device
a83cc2
a83cc2
(The VM is not resumable from here, hence stuck.)
a83cc2
a83cc2
Fix by handling the new -ENOSPC error (when DMA mappings are
a83cc2
exhausted) without any distinction to the current -ENOMEM error,
a83cc2
so we don't change the behavior on old kernels where the CVE-2019-3882
a83cc2
fix is not present.
a83cc2
a83cc2
An easy way to reproduce this bug is to restrict the DMA mapping
a83cc2
limit (65535 by default) when loading the VFIO IOMMU module:
a83cc2
a83cc2
  # modprobe vfio_iommu_type1 dma_entry_limit=666
a83cc2
a83cc2
Cc: qemu-stable@nongnu.org
a83cc2
Cc: Fam Zheng <fam@euphon.net>
a83cc2
Cc: Maxim Levitsky <mlevitsk@redhat.com>
a83cc2
Cc: Alex Williamson <alex.williamson@redhat.com>
a83cc2
Reported-by: Michal Prívozník <mprivozn@redhat.com>
a83cc2
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
a83cc2
Message-id: 20210723195843.1032825-1-philmd@redhat.com
a83cc2
Fixes: bdd6a90a9e5 ("block: Add VFIO based NVMe driver")
a83cc2
Buglink: https://bugs.launchpad.net/qemu/+bug/1863333
a83cc2
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/65
a83cc2
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
a83cc2
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
a83cc2
(cherry picked from commit 15a730e7a3aaac180df72cd5730e0617bcf44a5a)
a83cc2
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
a83cc2
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
---
a83cc2
 block/nvme.c | 22 ++++++++++++++++++++++
a83cc2
 1 file changed, 22 insertions(+)
a83cc2
a83cc2
diff --git a/block/nvme.c b/block/nvme.c
a83cc2
index 2b5421e7aa..e8dbbc2317 100644
a83cc2
--- a/block/nvme.c
a83cc2
+++ b/block/nvme.c
a83cc2
@@ -1030,7 +1030,29 @@ try_map:
a83cc2
         r = qemu_vfio_dma_map(s->vfio,
a83cc2
                               qiov->iov[i].iov_base,
a83cc2
                               len, true, &iova);
a83cc2
+        if (r == -ENOSPC) {
a83cc2
+            /*
a83cc2
+             * In addition to the -ENOMEM error, the VFIO_IOMMU_MAP_DMA
a83cc2
+             * ioctl returns -ENOSPC to signal the user exhausted the DMA
a83cc2
+             * mappings available for a container since Linux kernel commit
a83cc2
+             * 492855939bdb ("vfio/type1: Limit DMA mappings per container",
a83cc2
+             * April 2019, see CVE-2019-3882).
a83cc2
+             *
a83cc2
+             * This block driver already handles this error path by checking
a83cc2
+             * for the -ENOMEM error, so we directly replace -ENOSPC by
a83cc2
+             * -ENOMEM. Beside, -ENOSPC has a specific meaning for blockdev
a83cc2
+             * coroutines: it triggers BLOCKDEV_ON_ERROR_ENOSPC and
a83cc2
+             * BLOCK_ERROR_ACTION_STOP which stops the VM, asking the operator
a83cc2
+             * to add more storage to the blockdev. Not something we can do
a83cc2
+             * easily with an IOMMU :)
a83cc2
+             */
a83cc2
+            r = -ENOMEM;
a83cc2
+        }
a83cc2
         if (r == -ENOMEM && retry) {
a83cc2
+            /*
a83cc2
+             * We exhausted the DMA mappings available for our container:
a83cc2
+             * recycle the volatile IOVA mappings.
a83cc2
+             */
a83cc2
             retry = false;
a83cc2
             trace_nvme_dma_flush_queue_wait(s);
a83cc2
             if (s->dma_map_count) {
a83cc2
-- 
a83cc2
2.27.0
a83cc2