aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2015-06-29 10:44:01 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-07-10 12:49:37 -0400
commitaae3d9fecc22c1c7565c94f0818704a1908543ce (patch)
tree73e5bbf2bb1a991b16814e5ae1627cf6c4483a82 /drivers/s390
parent2c7a81c60df147a14735ca3c0f039cf4507b65fc (diff)
KVM: s390: virtio-ccw: don't overwrite config space values
commit 431dae778aea4eed31bd12e5ee82edc571cd4d70 upstream. 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> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/s390')
-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));