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: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Acked-by: Jason Wang <jasowang@redhat.com> Message-Id: <20231019034902.7346-1-xuanzhuo@linux.alibaba.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
fafb51a67f
commit
e0592acd1e
@ -39,6 +39,39 @@ static void vp_transport_features(struct virtio_device *vdev, u64 features)
|
||||
__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 */
|
||||
static int vp_finalize_features(struct virtio_device *vdev)
|
||||
{
|
||||
@ -57,6 +90,9 @@ static int vp_finalize_features(struct virtio_device *vdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vp_check_common_size(vdev))
|
||||
return -EINVAL;
|
||||
|
||||
vp_modern_set_features(&vp_dev->mdev, vdev->features);
|
||||
|
||||
return 0;
|
||||
|
@ -296,7 +296,7 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev)
|
||||
mdev->common = vp_modern_map_capability(mdev, common,
|
||||
sizeof(struct virtio_pci_common_cfg), 4,
|
||||
0, sizeof(struct virtio_pci_modern_common_cfg),
|
||||
NULL, NULL);
|
||||
&mdev->common_len, NULL);
|
||||
if (!mdev->common)
|
||||
goto err_map_common;
|
||||
mdev->isr = vp_modern_map_capability(mdev, isr, sizeof(u8), 1,
|
||||
|
@ -45,6 +45,7 @@ struct virtio_pci_modern_device {
|
||||
|
||||
size_t notify_len;
|
||||
size_t device_len;
|
||||
size_t common_len;
|
||||
|
||||
int notify_map_cap;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user