Commit 431dae77 authored by Cornelia Huck's avatar Cornelia Huck Committed by Paolo Bonzini

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: default avatarEric Farman <farman@linux.vnet.ibm.com>
Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: default avatarEric Farman <farman@linux.vnet.ibm.com>
Tested-by: default avatarEric Farman <farman@linux.vnet.ibm.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 59fd1323
...@@ -65,6 +65,7 @@ struct virtio_ccw_device { ...@@ -65,6 +65,7 @@ struct virtio_ccw_device {
bool is_thinint; bool is_thinint;
bool going_away; bool going_away;
bool device_lost; bool device_lost;
unsigned int config_ready;
void *airq_info; void *airq_info;
}; };
...@@ -833,8 +834,11 @@ static void virtio_ccw_get_config(struct virtio_device *vdev, ...@@ -833,8 +834,11 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
if (ret) if (ret)
goto out_free; goto out_free;
memcpy(vcdev->config, config_area, sizeof(vcdev->config)); memcpy(vcdev->config, config_area, offset + len);
memcpy(buf, &vcdev->config[offset], len); if (buf)
memcpy(buf, &vcdev->config[offset], len);
if (vcdev->config_ready < offset + len)
vcdev->config_ready = offset + len;
out_free: out_free:
kfree(config_area); kfree(config_area);
...@@ -857,6 +861,9 @@ static void virtio_ccw_set_config(struct virtio_device *vdev, ...@@ -857,6 +861,9 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
if (!config_area) if (!config_area)
goto out_free; goto out_free;
/* Make sure we don't overwrite fields. */
if (vcdev->config_ready < offset)
virtio_ccw_get_config(vdev, 0, NULL, offset);
memcpy(&vcdev->config[offset], buf, len); memcpy(&vcdev->config[offset], buf, len);
/* Write the config area to the host. */ /* Write the config area to the host. */
memcpy(config_area, vcdev->config, sizeof(vcdev->config)); memcpy(config_area, vcdev->config, sizeof(vcdev->config));
......
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