aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2015-06-29 10:44:01 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2015-07-03 12:55:18 -0400
commit431dae778aea4eed31bd12e5ee82edc571cd4d70 (patch)
treead254fb0e1540501d690508b2ddf0eaea38815b8
parent59fd132340b3e37b83179d2fcb673980035edf62 (diff)
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 <farman@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Reviewed-by: Eric Farman <farman@linux.vnet.ibm.com> Tested-by: Eric Farman <farman@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--drivers/s390/kvm/virtio_ccw.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c
index 6f1fa1773e76..f8d8fdb26b72 100644
--- a/drivers/s390/kvm/virtio_ccw.c
+++ b/drivers/s390/kvm/virtio_ccw.c
@@ -65,6 +65,7 @@ struct virtio_ccw_device {
65 bool is_thinint; 65 bool is_thinint;
66 bool going_away; 66 bool going_away;
67 bool device_lost; 67 bool device_lost;
68 unsigned int config_ready;
68 void *airq_info; 69 void *airq_info;
69}; 70};
70 71
@@ -833,8 +834,11 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
833 if (ret) 834 if (ret)
834 goto out_free; 835 goto out_free;
835 836
836 memcpy(vcdev->config, config_area, sizeof(vcdev->config)); 837 memcpy(vcdev->config, config_area, offset + len);
837 memcpy(buf, &vcdev->config[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;
838 842
839out_free: 843out_free:
840 kfree(config_area); 844 kfree(config_area);
@@ -857,6 +861,9 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
857 if (!config_area) 861 if (!config_area)
858 goto out_free; 862 goto out_free;
859 863
864 /* Make sure we don't overwrite fields. */
865 if (vcdev->config_ready < offset)
866 virtio_ccw_get_config(vdev, 0, NULL, offset);
860 memcpy(&vcdev->config[offset], buf, len); 867 memcpy(&vcdev->config[offset], buf, len);
861 /* Write the config area to the host. */ 868 /* Write the config area to the host. */
862 memcpy(config_area, vcdev->config, sizeof(vcdev->config)); 869 memcpy(config_area, vcdev->config, sizeof(vcdev->config));