[v1] bus/pci: fix VF bus error for memory access
Checks
Commit Message
To fix CVE-2020-12888, the linux vfio-pci module will invalidate mmaps
and block MMIO access on disabled memory, it will send a SIGBUS to the
application.
In fact, vfio-pci will enable the memory command when openning the PCI
device, but according to the PCIe specification, this enablement by real
PCI write command doesn't have effect, it still has 0 value:
Table 9-13 Command Register Changes
Bit Location | PF and VF Register Differences | PF | VF
| From Base | Attributes | Attributes
-------------+--------------------------------+------------+-----------
| Memory Space Enable - Does not | |
| apply to VFs. Must be hardwired| Base | 0b
1 | to 0b for VFs. VF Memory Space | |
| is controlled by the VF MSE bit| |
| in the VF Control register. | |
-------------+--------------------------------+------------+-----------
So that when the vfio-pci initializes its own PCI configuration space
data called 'vconfig' by reading the VF's real configuration space, it
will have the memory command with 0b value, then, the vfio-pci finds the
BAR memory is disabled by checking the its vconfig space, and the SIGBUS
will be triggerred.
So it needs to enable PCI bus memory command explicitly to avoid access
on disabled memory, which will call vfio-pci ioctl to change the memory
command in vconfig space to 1b.
Fixes: 33604c31354a ("vfio: refactor PCI BAR mapping")
Cc: stable@dpdk.org
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
Put the long link here, since the patch doesn't support to add so long
line.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=abafbc551fddede3e0a08dee1dcde08fc0eb8476
---
drivers/bus/pci/linux/pci_vfio.c | 37 ++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
@@ -149,6 +149,38 @@ pci_vfio_get_msix_bar(int fd, struct pci_msix_table *msix_table)
return 0;
}
+/* enable PCI bus memory command */
+static int
+pci_vfio_enable_bus_memory(int dev_fd)
+{
+ uint16_t cmd;
+ int ret;
+
+ ret = pread64(dev_fd, &cmd, sizeof(cmd),
+ VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
+ PCI_COMMAND);
+
+ if (ret != sizeof(cmd)) {
+ RTE_LOG(ERR, EAL, "Cannot read command from PCI config space!\n");
+ return -1;
+ }
+
+ if (cmd & PCI_COMMAND_MEMORY)
+ return 0;
+
+ cmd |= PCI_COMMAND_MEMORY;
+ ret = pwrite64(dev_fd, &cmd, sizeof(cmd),
+ VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
+ PCI_COMMAND);
+
+ if (ret != sizeof(cmd)) {
+ RTE_LOG(ERR, EAL, "Cannot write command to PCI config space!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
/* set PCI bus mastering */
static int
pci_vfio_set_bus_master(int dev_fd, bool op)
@@ -427,6 +459,11 @@ pci_rte_vfio_setup_device(struct rte_pci_device *dev, int vfio_dev_fd)
return -1;
}
+ if (pci_vfio_enable_bus_memory(vfio_dev_fd)) {
+ RTE_LOG(ERR, EAL, "Cannot enable bus memory command!\n");
+ return -1;
+ }
+
/* set bus mastering for the device */
if (pci_vfio_set_bus_master(vfio_dev_fd, true)) {
RTE_LOG(ERR, EAL, "Cannot set up bus mastering!\n");