Re: [PATCH v4 3/9] s390/vfio_ccw: fix out of bounds check on CCW array
From: Matthew Rosato
Date: Sat Jul 25 2026 - 12:10:53 EST
On 7/25/26 11:26 AM, Eric Farman wrote:
> 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: 0a19e61e6d4c ("vfio: ccw: introduce channel program interfaces")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Eric Farman <farman@xxxxxxxxxxxxx>
Reviewed-by: Matthew Rosato <mjrosato@xxxxxxxxxxxxx>
> ---
> drivers/s390/cio/vfio_ccw_cp.c | 17 +++++------------
> 1 file changed, 5 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
> index 1c2890d139c6..af632f9d5453 100644
> --- a/drivers/s390/cio/vfio_ccw_cp.c
> +++ b/drivers/s390/cio/vfio_ccw_cp.c
> @@ -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;
> -
> - ccw++;
> - } while (cnt < CCWCHAIN_LEN_MAX + 1);
> -
> - if (cnt == CCWCHAIN_LEN_MAX + 1)
> - cnt = -EINVAL;
> + return cnt;
> + }
>
> - return cnt;
> + return -EINVAL;
> }
>
> static int tic_target_chain_exists(struct ccw1 *tic, struct channel_program *cp)