Skip to content

Commit dc9f4dd

Browse files
fengidrimstsirkin
authored andcommitted
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>
1 parent beeae82 commit dc9f4dd

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

drivers/virtio/virtio_pci_modern.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,39 @@ static void vp_transport_features(struct virtio_device *vdev, u64 features)
3939
__virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
4040
}
4141

42+
static int __vp_check_common_size_one_feature(struct virtio_device *vdev, u32 fbit,
43+
u32 offset, const char *fname)
44+
{
45+
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
46+
47+
if (!__virtio_test_bit(vdev, fbit))
48+
return 0;
49+
50+
if (likely(vp_dev->mdev.common_len >= offset))
51+
return 0;
52+
53+
dev_err(&vdev->dev,
54+
"virtio: common cfg size(%zu) does not match the feature %s\n",
55+
vp_dev->mdev.common_len, fname);
56+
57+
return -EINVAL;
58+
}
59+
60+
#define vp_check_common_size_one_feature(vdev, fbit, field) \
61+
__vp_check_common_size_one_feature(vdev, fbit, \
62+
offsetofend(struct virtio_pci_modern_common_cfg, field), #fbit)
63+
64+
static int vp_check_common_size(struct virtio_device *vdev)
65+
{
66+
if (vp_check_common_size_one_feature(vdev, VIRTIO_F_NOTIF_CONFIG_DATA, queue_notify_data))
67+
return -EINVAL;
68+
69+
if (vp_check_common_size_one_feature(vdev, VIRTIO_F_RING_RESET, queue_reset))
70+
return -EINVAL;
71+
72+
return 0;
73+
}
74+
4275
/* virtio config->finalize_features() implementation */
4376
static int vp_finalize_features(struct virtio_device *vdev)
4477
{
@@ -57,6 +90,9 @@ static int vp_finalize_features(struct virtio_device *vdev)
5790
return -EINVAL;
5891
}
5992

93+
if (vp_check_common_size(vdev))
94+
return -EINVAL;
95+
6096
vp_modern_set_features(&vp_dev->mdev, vdev->features);
6197

6298
return 0;

drivers/virtio/virtio_pci_modern_dev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev)
296296
mdev->common = vp_modern_map_capability(mdev, common,
297297
sizeof(struct virtio_pci_common_cfg), 4,
298298
0, sizeof(struct virtio_pci_modern_common_cfg),
299-
NULL, NULL);
299+
&mdev->common_len, NULL);
300300
if (!mdev->common)
301301
goto err_map_common;
302302
mdev->isr = vp_modern_map_capability(mdev, isr, sizeof(u8), 1,

include/linux/virtio_pci_modern.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct virtio_pci_modern_device {
4545

4646
size_t notify_len;
4747
size_t device_len;
48+
size_t common_len;
4849

4950
int notify_map_cap;
5051

0 commit comments

Comments
 (0)