@samitouri / QOSamiQemu / commits / 37c9f6fce5

hw/dma/pl080: Handle bogus swidth and dwidth in transfers

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 Reviewed-by: Jim MacArthur <jim.macarthur@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260306152140.2191653-1-peter.maydell@linaro.org

Peter Maydell committed Mar 6, 2026 at 15:21 UTC 37c9f6fce5c59db216e7f7ad961395b6e702bda9
1 file changed +15
hw/dma/pl080.c
+15
@@ -164,6 +164,21 @@ again:
164 destination widths are different. */
165 swidth = 1 << ((ch->ctrl >> 18) & 7);
166 dwidth = 1 << ((ch->ctrl >> 21) & 7);
167 +
168 + /* Only widths of 1, 2 or 4 are valid */
169 + if (swidth > 4) {
170 + qemu_log_mask(LOG_GUEST_ERROR,
171 + "pl080: channel %d: invalid SWidth %d\n",
172 + c, extract32(ch->ctrl, 18, 3));
173 + continue;
174 + }
175 + if (dwidth > 4) {
176 + qemu_log_mask(LOG_GUEST_ERROR,
177 + "pl080: channel %d: invalid DWidth %d\n",
178 + c, extract32(ch->ctrl, 21, 3));
179 + continue;
180 + }
181 +
182 for (n = 0; n < dwidth; n+= swidth) {
183 address_space_read(&s->downstream_as, ch->src,
184 MEMTXATTRS_UNSPECIFIED, buff + n, swidth);