vDPA/ifcvf: get_config_size should return a value no greater than dev implementation
authorZhu Lingshan <lingshan.zhu@intel.com>
Fri, 22 Jul 2022 11:53:04 +0000 (19:53 +0800)
committerMichael S. Tsirkin <mst@redhat.com>
Thu, 11 Aug 2022 08:26:08 +0000 (04:26 -0400)
Drivers must not access a BAR outside the capability length,
and for a virtio device, ifcvf driver should not report any non-standard
capability contents to the upper layers.

Function ifcvf_get_config_size() is introduced here to return a safe value
of the device config capability size.

Signed-off-by: Zhu Lingshan <lingshan.zhu@intel.com>
Message-Id: <20220722115309.82746-2-lingshan.zhu@intel.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
drivers/vdpa/ifcvf/ifcvf_base.c
drivers/vdpa/ifcvf/ifcvf_base.h

index 47b9409..75a703b 100644 (file)
@@ -127,6 +127,7 @@ int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev)
                        break;
                case VIRTIO_PCI_CAP_DEVICE_CFG:
                        hw->dev_cfg = get_cap_addr(hw, &cap);
+                       hw->cap_dev_config_size = le32_to_cpu(cap.length);
                        IFCVF_DBG(pdev, "hw->dev_cfg = %p\n", hw->dev_cfg);
                        break;
                }
@@ -232,15 +233,23 @@ int ifcvf_verify_min_features(struct ifcvf_hw *hw, u64 features)
 u32 ifcvf_get_config_size(struct ifcvf_hw *hw)
 {
        struct ifcvf_adapter *adapter;
+       u32 net_config_size = sizeof(struct virtio_net_config);
+       u32 blk_config_size = sizeof(struct virtio_blk_config);
+       u32 cap_size = hw->cap_dev_config_size;
        u32 config_size;
 
        adapter = vf_to_adapter(hw);
+       /* If the onboard device config space size is greater than
+        * the size of struct virtio_net/blk_config, only the spec
+        * implementing contents size is returned, this is very
+        * unlikely, defensive programming.
+        */
        switch (hw->dev_type) {
        case VIRTIO_ID_NET:
-               config_size = sizeof(struct virtio_net_config);
+               config_size = min(cap_size, net_config_size);
                break;
        case VIRTIO_ID_BLOCK:
-               config_size = sizeof(struct virtio_blk_config);
+               config_size = min(cap_size, blk_config_size);
                break;
        default:
                config_size = 0;
index 115b61f..f5563f6 100644 (file)
@@ -87,6 +87,8 @@ struct ifcvf_hw {
        int config_irq;
        int vqs_reused_irq;
        u16 nr_vring;
+       /* VIRTIO_PCI_CAP_DEVICE_CFG size */
+       u32 cap_dev_config_size;
 };
 
 struct ifcvf_adapter {