The channel subsystem will reject channel programs that incorporate 256 CCWs without a data transfer, but the existing check to account for this only does so for CCWs with a data address of zero. Other valid CCWs that wouldn't transfer data are not accounted for.
Rather than re-inventing the wheel, use the output of the datastream at the end of the entire CCW parsing tree to indicate whether data was moved or not. Cc: [email protected] Fixes: e8601dd5d0 ("s390x/css: catch ccw sequence errors") Signed-off-by: Eric Farman <[email protected]> --- hw/s390x/css.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 9da9128d88..65341c68c3 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1016,13 +1016,6 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); - if (!ccw.cda) { - if (sch->ccw_no_data_cnt == 255) { - return -EINVAL; - } - sch->ccw_no_data_cnt++; - } - /* Look at the command. */ ccw_dstream_init(&sch->cds, &ccw, &(sch->orb)); switch (ccw.cmd_code) { @@ -1103,6 +1096,20 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, } sch->last_cmd = ccw; sch->last_cmd_valid = true; + + /* + * A CCW that transfers no data is allowed, but ensure an upper limit + * is established to prevent long-running channel programs that don't + * move actual data. + */ + if (ret == 0 && sch->cds.at_byte == 0) { + if (sch->ccw_no_data_cnt == 255) { + ret = -EINVAL; + } else { + sch->ccw_no_data_cnt++; + } + } + if (ret == 0) { if (ccw.flags & CCW_FLAG_CC) { sch->channel_prog += 8; -- 2.53.0
