Skip to content

Commit 30ef7a8

Browse files
elic307imstsirkin
authored andcommitted
vdpa: Read device configuration only if FEATURES_OK
Avoid reading device configuration during feature negotiation. Read device status and verify that VIRTIO_CONFIG_S_FEATURES_OK is set. Protect the entire operation, including configuration read with cf_mutex to ensure integrity of the results. Signed-off-by: Eli Cohen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michael S. Tsirkin <[email protected]> Acked-by: Jason Wang <[email protected]>
1 parent 73bc0db commit 30ef7a8

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

drivers/vdpa/vdpa.c

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,21 @@ void vdpa_mgmtdev_unregister(struct vdpa_mgmt_dev *mdev)
393393
}
394394
EXPORT_SYMBOL_GPL(vdpa_mgmtdev_unregister);
395395

396+
static void vdpa_get_config_unlocked(struct vdpa_device *vdev,
397+
unsigned int offset,
398+
void *buf, unsigned int len)
399+
{
400+
const struct vdpa_config_ops *ops = vdev->config;
401+
402+
/*
403+
* Config accesses aren't supposed to trigger before features are set.
404+
* If it does happen we assume a legacy guest.
405+
*/
406+
if (!vdev->features_valid)
407+
vdpa_set_features(vdev, 0);
408+
ops->get_config(vdev, offset, buf, len);
409+
}
410+
396411
/**
397412
* vdpa_get_config - Get one or more device configuration fields.
398413
* @vdev: vdpa device to operate on
@@ -403,16 +418,8 @@ EXPORT_SYMBOL_GPL(vdpa_mgmtdev_unregister);
403418
void vdpa_get_config(struct vdpa_device *vdev, unsigned int offset,
404419
void *buf, unsigned int len)
405420
{
406-
const struct vdpa_config_ops *ops = vdev->config;
407-
408421
mutex_lock(&vdev->cf_mutex);
409-
/*
410-
* Config accesses aren't supposed to trigger before features are set.
411-
* If it does happen we assume a legacy guest.
412-
*/
413-
if (!vdev->features_valid)
414-
vdpa_set_features(vdev, 0);
415-
ops->get_config(vdev, offset, buf, len);
422+
vdpa_get_config_unlocked(vdev, offset, buf, len);
416423
mutex_unlock(&vdev->cf_mutex);
417424
}
418425
EXPORT_SYMBOL_GPL(vdpa_get_config);
@@ -813,7 +820,7 @@ static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *ms
813820
u64 features;
814821
u16 val_u16;
815822

816-
vdpa_get_config(vdev, 0, &config, sizeof(config));
823+
vdpa_get_config_unlocked(vdev, 0, &config, sizeof(config));
817824

818825
if (nla_put(msg, VDPA_ATTR_DEV_NET_CFG_MACADDR, sizeof(config.mac),
819826
config.mac))
@@ -838,12 +845,23 @@ vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid,
838845
{
839846
u32 device_id;
840847
void *hdr;
848+
u8 status;
841849
int err;
842850

851+
mutex_lock(&vdev->cf_mutex);
852+
status = vdev->config->get_status(vdev);
853+
if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) {
854+
NL_SET_ERR_MSG_MOD(extack, "Features negotiation not completed");
855+
err = -EAGAIN;
856+
goto out;
857+
}
858+
843859
hdr = genlmsg_put(msg, portid, seq, &vdpa_nl_family, flags,
844860
VDPA_CMD_DEV_CONFIG_GET);
845-
if (!hdr)
846-
return -EMSGSIZE;
861+
if (!hdr) {
862+
err = -EMSGSIZE;
863+
goto out;
864+
}
847865

848866
if (nla_put_string(msg, VDPA_ATTR_DEV_NAME, dev_name(&vdev->dev))) {
849867
err = -EMSGSIZE;
@@ -867,11 +885,14 @@ vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid,
867885
if (err)
868886
goto msg_err;
869887

888+
mutex_unlock(&vdev->cf_mutex);
870889
genlmsg_end(msg, hdr);
871890
return 0;
872891

873892
msg_err:
874893
genlmsg_cancel(msg, hdr);
894+
out:
895+
mutex_unlock(&vdev->cf_mutex);
875896
return err;
876897
}
877898

0 commit comments

Comments
 (0)