Commit e0592acd authored by Xuan Zhuo's avatar Xuan Zhuo Committed by Michael S. Tsirkin

virtio_pci: add check for common cfg size

Some buggy devices, the common cfg size may not match the features.

This patch checks the common cfg size for the
features(VIRTIO_F_NOTIF_CONFIG_DATA, VIRTIO_F_RING_RESET). When the
common cfg size does not match the corresponding feature, we fail the
probe and print error message.
Signed-off-by: default avatarXuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: default avatarJason Wang <jasowang@redhat.com>
Message-Id: <20231019034902.7346-1-xuanzhuo@linux.alibaba.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent fafb51a6
...@@ -39,6 +39,39 @@ static void vp_transport_features(struct virtio_device *vdev, u64 features) ...@@ -39,6 +39,39 @@ static void vp_transport_features(struct virtio_device *vdev, u64 features)
__virtio_set_bit(vdev, VIRTIO_F_RING_RESET); __virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
} }
static int __vp_check_common_size_one_feature(struct virtio_device *vdev, u32 fbit,
u32 offset, const char *fname)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
if (!__virtio_test_bit(vdev, fbit))
return 0;
if (likely(vp_dev->mdev.common_len >= offset))
return 0;
dev_err(&vdev->dev,
"virtio: common cfg size(%zu) does not match the feature %s\n",
vp_dev->mdev.common_len, fname);
return -EINVAL;
}
#define vp_check_common_size_one_feature(vdev, fbit, field) \
__vp_check_common_size_one_feature(vdev, fbit, \
offsetofend(struct virtio_pci_modern_common_cfg, field), #fbit)
static int vp_check_common_size(struct virtio_device *vdev)
{
if (vp_check_common_size_one_feature(vdev, VIRTIO_F_NOTIF_CONFIG_DATA, queue_notify_data))
return -EINVAL;
if (vp_check_common_size_one_feature(vdev, VIRTIO_F_RING_RESET, queue_reset))
return -EINVAL;
return 0;
}
/* virtio config->finalize_features() implementation */ /* virtio config->finalize_features() implementation */
static int vp_finalize_features(struct virtio_device *vdev) static int vp_finalize_features(struct virtio_device *vdev)
{ {
...@@ -57,6 +90,9 @@ static int vp_finalize_features(struct virtio_device *vdev) ...@@ -57,6 +90,9 @@ static int vp_finalize_features(struct virtio_device *vdev)
return -EINVAL; return -EINVAL;
} }
if (vp_check_common_size(vdev))
return -EINVAL;
vp_modern_set_features(&vp_dev->mdev, vdev->features); vp_modern_set_features(&vp_dev->mdev, vdev->features);
return 0; return 0;
......
...@@ -296,7 +296,7 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev) ...@@ -296,7 +296,7 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev)
mdev->common = vp_modern_map_capability(mdev, common, mdev->common = vp_modern_map_capability(mdev, common,
sizeof(struct virtio_pci_common_cfg), 4, sizeof(struct virtio_pci_common_cfg), 4,
0, sizeof(struct virtio_pci_modern_common_cfg), 0, sizeof(struct virtio_pci_modern_common_cfg),
NULL, NULL); &mdev->common_len, NULL);
if (!mdev->common) if (!mdev->common)
goto err_map_common; goto err_map_common;
mdev->isr = vp_modern_map_capability(mdev, isr, sizeof(u8), 1, mdev->isr = vp_modern_map_capability(mdev, isr, sizeof(u8), 1,
......
...@@ -45,6 +45,7 @@ struct virtio_pci_modern_device { ...@@ -45,6 +45,7 @@ struct virtio_pci_modern_device {
size_t notify_len; size_t notify_len;
size_t device_len; size_t device_len;
size_t common_len;
int notify_map_cap; int notify_map_cap;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment