mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
s390/vfio_ccw: Ensure index for read/write regions are within range
The introduction of the capability chain rightly clamped the
region indexes to the range of the capabilities itself, but
neglected to do so for the existing read/write regions which
should also be enforced.
Fixes: db8e5d17ac ("vfio-ccw: add capabilities chain")
Cc: stable@vger.kernel.org
Cc: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
This commit is contained in:
parent
4f6fdc6e1a
commit
9f5f9a78fe
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/vfio.h>
|
||||
#include <linux/nospec.h>
|
||||
|
||||
#include "vfio_ccw_private.h"
|
||||
|
||||
|
|
@ -24,11 +25,20 @@ static ssize_t vfio_ccw_async_region_read(struct vfio_ccw_private *private,
|
|||
return -EINVAL;
|
||||
|
||||
mutex_lock(&private->io_mutex);
|
||||
|
||||
if (i >= private->num_regions) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
i = array_index_nospec(i, private->num_regions);
|
||||
region = private->region[i].data;
|
||||
if (copy_to_user(buf, (void *)region + pos, count))
|
||||
ret = -EFAULT;
|
||||
else
|
||||
ret = count;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&private->io_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -48,6 +58,12 @@ static ssize_t vfio_ccw_async_region_write(struct vfio_ccw_private *private,
|
|||
if (!mutex_trylock(&private->io_mutex))
|
||||
return -EAGAIN;
|
||||
|
||||
if (i >= private->num_regions) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
i = array_index_nospec(i, private->num_regions);
|
||||
region = private->region[i].data;
|
||||
if (copy_from_user((void *)region + pos, buf, count)) {
|
||||
ret = -EFAULT;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/vfio.h>
|
||||
#include "vfio_ccw_private.h"
|
||||
|
||||
|
|
@ -26,6 +27,13 @@ static ssize_t vfio_ccw_schib_region_read(struct vfio_ccw_private *private,
|
|||
return -EINVAL;
|
||||
|
||||
mutex_lock(&private->io_mutex);
|
||||
|
||||
if (i >= private->num_regions) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = array_index_nospec(i, private->num_regions);
|
||||
region = private->region[i].data;
|
||||
|
||||
if (cio_update_schib(sch)) {
|
||||
|
|
@ -97,6 +105,12 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
|
|||
list_del(&crw->next);
|
||||
|
||||
mutex_lock(&private->io_mutex);
|
||||
if (i >= private->num_regions) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = array_index_nospec(i, private->num_regions);
|
||||
region = private->region[i].data;
|
||||
|
||||
if (crw)
|
||||
|
|
@ -109,6 +123,7 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
|
|||
|
||||
region->crw = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&private->io_mutex);
|
||||
|
||||
kfree(crw);
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ static ssize_t vfio_ccw_mdev_read(struct vfio_device *vdev,
|
|||
return vfio_ccw_mdev_read_io_region(private, buf, count, ppos);
|
||||
default:
|
||||
index -= VFIO_CCW_NUM_REGIONS;
|
||||
index = array_index_nospec(index, private->num_regions);
|
||||
return private->region[index].ops->read(private, buf, count,
|
||||
ppos);
|
||||
}
|
||||
|
|
@ -295,6 +296,7 @@ static ssize_t vfio_ccw_mdev_write(struct vfio_device *vdev,
|
|||
return vfio_ccw_mdev_write_io_region(private, buf, count, ppos);
|
||||
default:
|
||||
index -= VFIO_CCW_NUM_REGIONS;
|
||||
index = array_index_nospec(index, private->num_regions);
|
||||
return private->region[index].ops->write(private, buf, count,
|
||||
ppos);
|
||||
}
|
||||
|
|
@ -338,11 +340,8 @@ static int vfio_ccw_mdev_ioctl_get_region_info(struct vfio_device *vdev,
|
|||
VFIO_CCW_NUM_REGIONS + private->num_regions)
|
||||
return -EINVAL;
|
||||
|
||||
info->index = array_index_nospec(info->index,
|
||||
VFIO_CCW_NUM_REGIONS +
|
||||
private->num_regions);
|
||||
|
||||
i = info->index - VFIO_CCW_NUM_REGIONS;
|
||||
i = array_index_nospec(i, private->num_regions);
|
||||
|
||||
info->offset = VFIO_CCW_INDEX_TO_OFFSET(info->index);
|
||||
info->size = private->region[i].size;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user