The PL080 TRM states that the DWidth and SWidth fields of the channel control registers can only validly specify widths up to 32 bits (i.e. values from 0 to 2) and all other values are reserved.
Currently we don't check this, so if the guest specifies an invalid value we will transfer more data into our local 'buff[]' array than it can hold. Check the widths; since the TRM doesn't clearly specify any behaviour for what to do on invalid values, we choose to log them and then ignore the channel for transfers. Cc: [email protected] Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3203 Signed-off-by: Peter Maydell <[email protected]> --- hw/dma/pl080.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index 3f8acb03de..6262c3f3df 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -164,6 +164,21 @@ again: destination widths are different. */ swidth = 1 << ((ch->ctrl >> 18) & 7); dwidth = 1 << ((ch->ctrl >> 21) & 7); + + /* Only widths of 1, 2 or 4 are valid */ + if (swidth > 4) { + qemu_log_mask(LOG_GUEST_ERROR, + "pl080: channel %d: invalid SWidth %d\n", + c, extract32(ch->ctrl, 18, 3)); + continue; + } + if (dwidth > 4) { + qemu_log_mask(LOG_GUEST_ERROR, + "pl080: channel %d: invalid DWidth %d\n", + c, extract32(ch->ctrl, 21, 3)); + continue; + } + for (n = 0; n < dwidth; n+= swidth) { address_space_read(&s->downstream_as, ch->src, MEMTXATTRS_UNSPECIFIED, buff + n, swidth); -- 2.43.0
