Skip to content

Commit 431dae7

Browse files
cohuckbonzini
authored andcommitted
KVM: s390: virtio-ccw: don't overwrite config space values
Eric noticed problems with vhost-scsi and virtio-ccw: vhost-scsi complained about overwriting values in the config space, which was triggered by a broken implementation of virtio-ccw's config get/set routines. It was probably sheer luck that we did not hit this before. When writing a value to the config space, the WRITE_CONF ccw will always write from the beginning of the config space up to and including the value to be set. If the config space up to the value has not yet been retrieved from the device, however, we'll end up overwriting values. Keep track of the known config space and update if needed to avoid this. Moreover, READ_CONF will only read the number of bytes it has been instructed to retrieve, so we must not copy more than that to the buffer, or we might overwrite trailing values. Reported-by: Eric Farman <[email protected]> Signed-off-by: Cornelia Huck <[email protected]> Reviewed-by: Eric Farman <[email protected]> Tested-by: Eric Farman <[email protected]> Signed-off-by: Christian Borntraeger <[email protected]> Cc: [email protected] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 59fd132 commit 431dae7

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

drivers/s390/kvm/virtio_ccw.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct virtio_ccw_device {
6565
bool is_thinint;
6666
bool going_away;
6767
bool device_lost;
68+
unsigned int config_ready;
6869
void *airq_info;
6970
};
7071

@@ -833,8 +834,11 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
833834
if (ret)
834835
goto out_free;
835836

836-
memcpy(vcdev->config, config_area, sizeof(vcdev->config));
837-
memcpy(buf, &vcdev->config[offset], len);
837+
memcpy(vcdev->config, config_area, offset + len);
838+
if (buf)
839+
memcpy(buf, &vcdev->config[offset], len);
840+
if (vcdev->config_ready < offset + len)
841+
vcdev->config_ready = offset + len;
838842

839843
out_free:
840844
kfree(config_area);
@@ -857,6 +861,9 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
857861
if (!config_area)
858862
goto out_free;
859863

864+
/* Make sure we don't overwrite fields. */
865+
if (vcdev->config_ready < offset)
866+
virtio_ccw_get_config(vdev, 0, NULL, offset);
860867
memcpy(&vcdev->config[offset], buf, len);
861868
/* Write the config area to the host. */
862869
memcpy(config_area, vcdev->config, sizeof(vcdev->config));

0 commit comments

Comments
 (0)