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: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3203
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
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