|
| 1 | +From 98f3488c1b6090024299f8d6362aa6aac03fe26d Mon Sep 17 00:00:00 2001 |
| 2 | +From: Akihiko Odaki <akihiko.odaki@daynix.com> |
| 3 | +Date: Wed, 28 Feb 2024 20:33:12 +0900 |
| 4 | +Subject: [PATCH] hw/nvme: Use pcie_sriov_num_vfs() |
| 5 | + |
| 6 | +nvme_sriov_pre_write_ctrl() used to directly inspect SR-IOV |
| 7 | +configurations to know the number of VFs being disabled due to SR-IOV |
| 8 | +configuration writes, but the logic was flawed and resulted in |
| 9 | +out-of-bound memory access. |
| 10 | + |
| 11 | +It assumed PCI_SRIOV_NUM_VF always has the number of currently enabled |
| 12 | +VFs, but it actually doesn't in the following cases: |
| 13 | +- PCI_SRIOV_NUM_VF has been set but PCI_SRIOV_CTRL_VFE has never been. |
| 14 | +- PCI_SRIOV_NUM_VF was written after PCI_SRIOV_CTRL_VFE was set. |
| 15 | +- VFs were only partially enabled because of realization failure. |
| 16 | + |
| 17 | +It is a responsibility of pcie_sriov to interpret SR-IOV configurations |
| 18 | +and pcie_sriov does it correctly, so use pcie_sriov_num_vfs(), which it |
| 19 | +provides, to get the number of enabled VFs before and after SR-IOV |
| 20 | +configuration writes. |
| 21 | + |
| 22 | +Cc: qemu-stable@nongnu.org |
| 23 | +Fixes: CVE-2024-26328 |
| 24 | +Fixes: 11871f53ef8e ("hw/nvme: Add support for the Virtualization Management command") |
| 25 | +Suggested-by: Michael S. Tsirkin <mst@redhat.com> |
| 26 | +Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> |
| 27 | +Message-Id: <20240228-reuse-v8-1-282660281e60@daynix.com> |
| 28 | +Reviewed-by: Michael S. Tsirkin <mst@redhat.com> |
| 29 | +Signed-off-by: Michael S. Tsirkin <mst@redhat.com> |
| 30 | +(cherry picked from commit 91bb64a8d2014fda33a81fcf0fce37340f0d3b0c) |
| 31 | +Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> |
| 32 | +--- |
| 33 | + hw/nvme/ctrl.c | 26 ++++++++------------------ |
| 34 | + 1 file changed, 8 insertions(+), 18 deletions(-) |
| 35 | + |
| 36 | +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c |
| 37 | +index 585bd3b397d..eaa6946604d 100644 |
| 38 | +--- a/hw/nvme/ctrl.c |
| 39 | ++++ b/hw/nvme/ctrl.c |
| 40 | +@@ -8497,36 +8497,26 @@ static void nvme_pci_reset(DeviceState *qdev) |
| 41 | + nvme_ctrl_reset(n, NVME_RESET_FUNCTION); |
| 42 | + } |
| 43 | + |
| 44 | +-static void nvme_sriov_pre_write_ctrl(PCIDevice *dev, uint32_t address, |
| 45 | +- uint32_t val, int len) |
| 46 | ++static void nvme_sriov_post_write_config(PCIDevice *dev, uint16_t old_num_vfs) |
| 47 | + { |
| 48 | + NvmeCtrl *n = NVME(dev); |
| 49 | + NvmeSecCtrlEntry *sctrl; |
| 50 | +- uint16_t sriov_cap = dev->exp.sriov_cap; |
| 51 | +- uint32_t off = address - sriov_cap; |
| 52 | +- int i, num_vfs; |
| 53 | ++ int i; |
| 54 | + |
| 55 | +- if (!sriov_cap) { |
| 56 | +- return; |
| 57 | +- } |
| 58 | +- |
| 59 | +- if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) { |
| 60 | +- if (!(val & PCI_SRIOV_CTRL_VFE)) { |
| 61 | +- num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); |
| 62 | +- for (i = 0; i < num_vfs; i++) { |
| 63 | +- sctrl = &n->sec_ctrl_list.sec[i]; |
| 64 | +- nvme_virt_set_state(n, le16_to_cpu(sctrl->scid), false); |
| 65 | +- } |
| 66 | +- } |
| 67 | ++ for (i = pcie_sriov_num_vfs(dev); i < old_num_vfs; i++) { |
| 68 | ++ sctrl = &n->sec_ctrl_list.sec[i]; |
| 69 | ++ nvme_virt_set_state(n, le16_to_cpu(sctrl->scid), false); |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + static void nvme_pci_write_config(PCIDevice *dev, uint32_t address, |
| 74 | + uint32_t val, int len) |
| 75 | + { |
| 76 | +- nvme_sriov_pre_write_ctrl(dev, address, val, len); |
| 77 | ++ uint16_t old_num_vfs = pcie_sriov_num_vfs(dev); |
| 78 | ++ |
| 79 | + pci_default_write_config(dev, address, val, len); |
| 80 | + pcie_cap_flr_write_config(dev, address, val, len); |
| 81 | ++ nvme_sriov_post_write_config(dev, old_num_vfs); |
| 82 | + } |
| 83 | + |
| 84 | + static const VMStateDescription nvme_vmstate = { |
| 85 | +-- |
| 86 | +GitLab |
| 87 | + |
0 commit comments