Skip to content

Commit 3acbedf

Browse files
efarmangregkh
authored andcommitted
s390/vfio_ccw: Ensure index for read/write regions are within range
[ Upstream commit 9f5f9a7 ] 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: db8e5d1 ("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> Stable-dep-of: 16b0798 ("s390/vfio_ccw: Implement a crw lock") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7b6a54d commit 3acbedf

3 files changed

Lines changed: 34 additions & 4 deletions

File tree

‎drivers/s390/cio/vfio_ccw_async.c‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include <linux/vfio.h>
11+
#include <linux/nospec.h>
1112
#include <linux/mdev.h>
1213

1314
#include "vfio_ccw_private.h"
@@ -25,11 +26,20 @@ static ssize_t vfio_ccw_async_region_read(struct vfio_ccw_private *private,
2526
return -EINVAL;
2627

2728
mutex_lock(&private->io_mutex);
29+
30+
if (i >= private->num_regions) {
31+
ret = -EINVAL;
32+
goto out_unlock;
33+
}
34+
35+
i = array_index_nospec(i, private->num_regions);
2836
region = private->region[i].data;
2937
if (copy_to_user(buf, (void *)region + pos, count))
3038
ret = -EFAULT;
3139
else
3240
ret = count;
41+
42+
out_unlock:
3343
mutex_unlock(&private->io_mutex);
3444
return ret;
3545
}
@@ -49,6 +59,12 @@ static ssize_t vfio_ccw_async_region_write(struct vfio_ccw_private *private,
4959
if (!mutex_trylock(&private->io_mutex))
5060
return -EAGAIN;
5161

62+
if (i >= private->num_regions) {
63+
ret = -EINVAL;
64+
goto out_unlock;
65+
}
66+
67+
i = array_index_nospec(i, private->num_regions);
5268
region = private->region[i].data;
5369
if (copy_from_user((void *)region + pos, buf, count)) {
5470
ret = -EFAULT;

‎drivers/s390/cio/vfio_ccw_chp.c‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
#include <linux/slab.h>
12+
#include <linux/nospec.h>
1213
#include <linux/vfio.h>
1314
#include "vfio_ccw_private.h"
1415

@@ -25,6 +26,13 @@ static ssize_t vfio_ccw_schib_region_read(struct vfio_ccw_private *private,
2526
return -EINVAL;
2627

2728
mutex_lock(&private->io_mutex);
29+
30+
if (i >= private->num_regions) {
31+
ret = -EINVAL;
32+
goto out;
33+
}
34+
35+
i = array_index_nospec(i, private->num_regions);
2836
region = private->region[i].data;
2937

3038
if (cio_update_schib(private->sch)) {
@@ -96,6 +104,12 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
96104
list_del(&crw->next);
97105

98106
mutex_lock(&private->io_mutex);
107+
if (i >= private->num_regions) {
108+
ret = -EINVAL;
109+
goto out;
110+
}
111+
112+
i = array_index_nospec(i, private->num_regions);
99113
region = private->region[i].data;
100114

101115
if (crw)
@@ -108,6 +122,7 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
108122

109123
region->crw = 0;
110124

125+
out:
111126
mutex_unlock(&private->io_mutex);
112127

113128
kfree(crw);

‎drivers/s390/cio/vfio_ccw_ops.c‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ static ssize_t vfio_ccw_mdev_read(struct mdev_device *mdev,
259259
return vfio_ccw_mdev_read_io_region(private, buf, count, ppos);
260260
default:
261261
index -= VFIO_CCW_NUM_REGIONS;
262+
index = array_index_nospec(index, private->num_regions);
262263
return private->region[index].ops->read(private, buf, count,
263264
ppos);
264265
}
@@ -312,6 +313,7 @@ static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev,
312313
return vfio_ccw_mdev_write_io_region(private, buf, count, ppos);
313314
default:
314315
index -= VFIO_CCW_NUM_REGIONS;
316+
index = array_index_nospec(index, private->num_regions);
315317
return private->region[index].ops->write(private, buf, count,
316318
ppos);
317319
}
@@ -359,11 +361,8 @@ static int vfio_ccw_mdev_get_region_info(struct vfio_region_info *info,
359361
VFIO_CCW_NUM_REGIONS + private->num_regions)
360362
return -EINVAL;
361363

362-
info->index = array_index_nospec(info->index,
363-
VFIO_CCW_NUM_REGIONS +
364-
private->num_regions);
365-
366364
i = info->index - VFIO_CCW_NUM_REGIONS;
365+
i = array_index_nospec(i, private->num_regions);
367366

368367
info->offset = VFIO_CCW_INDEX_TO_OFFSET(info->index);
369368
info->size = private->region[i].size;

0 commit comments

Comments
 (0)