mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
s390/vfio_ccw: Fix out of bounds check on CCW array
The routine ccwchain_calc_length() counts the number of channel
command words (CCWs) that are chained together in a single channel
program, and rejects anything larger than CCWCHAIN_LEN_MAX (256) CCWs.
The loop itself is "do..while (count < 257)", and while the logic in
is_cpa_within_range() correctly adjusts between the 0-index array of
CCWs and the count of CCWs starting at 1, this means it would look
at a possible 257th CCW before ending the loop and (correctly)
returning an error.
Fix this by restructuring the loop to break as soon as 256 CCWs
(thus indexes 0-255) are examined, without looking at memory
outside the range.
Fixes: 0a19e61e6d ("vfio: ccw: introduce channel program interfaces")
Cc: stable@vger.kernel.org
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
5405c90d6a
commit
a005b7f1a4
|
|
@ -377,11 +377,9 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx)
|
|||
static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
|
||||
{
|
||||
struct ccw1 *ccw = cp->guest_cp;
|
||||
int cnt = 0;
|
||||
|
||||
do {
|
||||
cnt++;
|
||||
int cnt;
|
||||
|
||||
for (cnt = 1; cnt <= CCWCHAIN_LEN_MAX; cnt++, ccw++) {
|
||||
/*
|
||||
* We want to keep counting if the current CCW has the
|
||||
* command-chaining flag enabled, or if it is a TIC CCW
|
||||
|
|
@ -391,15 +389,10 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
|
|||
* after the TIC, depending on the results of its operation.
|
||||
*/
|
||||
if (!ccw_is_chain(ccw) && !is_tic_within_range(ccw, iova, cnt))
|
||||
break;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
ccw++;
|
||||
} while (cnt < CCWCHAIN_LEN_MAX + 1);
|
||||
|
||||
if (cnt == CCWCHAIN_LEN_MAX + 1)
|
||||
cnt = -EINVAL;
|
||||
|
||||
return cnt;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int tic_target_chain_exists(struct ccw1 *tic, struct channel_program *cp)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user