qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835
@ 2025-11-11 10:54 Alex Bennée
  2025-11-11 11:24 ` Peter Maydell
  2025-11-14 16:05 ` Yodel Eldar
  0 siblings, 2 replies; 7+ messages in thread
From: Alex Bennée @ 2025-11-11 10:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alex Bennée, Peter Maydell, Philippe Mathieu-Daudé,
	Fabiano Rosas, Laurent Vivier, Paolo Bonzini,
	open list:Raspberry Pi

The datasheet doesn't explicitly say that TXFR_LEN has to be word
aligned but the fact there is a DMA_D_WIDTH flag to select between 32
bit and 128 bit strongly implies that is how it works. The downstream
rpi kernel also goes to efforts to not write sub-4 byte lengths so
lets:

  - fail when mis-programmed and report GUEST_ERROR
  - catch setting D_WIDTH for 128 bit and report UNIMP
  - add comments that the DEBUG register isn't a straight write

This includes the test case from the reported bug which is of unknown
provenience but isn't particularly novel.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3201
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 hw/dma/bcm2835_dma.c           | 19 +++++++++++++++++++
 tests/qtest/bcm2835-dma-test.c | 22 ++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c
index a2771ddcb52..e03247796cf 100644
--- a/hw/dma/bcm2835_dma.c
+++ b/hw/dma/bcm2835_dma.c
@@ -86,6 +86,19 @@ static void bcm2835_dma_update(BCM2835DMAState *s, unsigned c)
         }
         xlen_td = xlen;
 
+        if (ch->ti & BCM2708_DMA_D_WIDTH) {
+            qemu_log_mask(LOG_UNIMP, "%s: 128bit transfers not yet supported", __func__);
+            ch->cs |= BCM2708_DMA_ERR;
+            break;
+        }
+
+        /* datasheet implies 32bit or 128bit transfers only */
+        if (xlen & 0x3) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: bad transfer size\n", __func__);
+            ch->cs |= BCM2708_DMA_ERR;
+            break;
+        }
+
         while (ylen != 0) {
             /* Normal transfer mode */
             while (xlen != 0) {
@@ -229,6 +242,12 @@ static void bcm2835_dma_write(BCM2835DMAState *s, hwaddr offset,
         ch->conblk_ad = value;
         break;
     case BCM2708_DMA_DEBUG:
+        /* this needs masking
+         * 31:29 - WAZRI
+         * 28:04 - RO
+         *    03 - WAZRI
+         * 00:02 - W1CLR
+         */
         ch->debug = value;
         break;
     default:
diff --git a/tests/qtest/bcm2835-dma-test.c b/tests/qtest/bcm2835-dma-test.c
index 18901b76d21..4b100480f25 100644
--- a/tests/qtest/bcm2835-dma-test.c
+++ b/tests/qtest/bcm2835-dma-test.c
@@ -105,12 +105,34 @@ static void bcm2835_dma_test_interrupts(void)
     bcm2835_dma_test_interrupt(14, 11);
 }
 
+static void test_cve_underflow_txfr_len_1(void)
+{
+    uint64_t dma_base = RASPI3_DMA_BASE; // 0x3f007000
+    uint32_t cb_addr = 0x1000;
+    uint32_t src_addr = 0x2000;
+    uint32_t dst_addr = 0x3000;
+    /* Prepare DMA Control Block with VULNERABLE configuration */
+    writel(cb_addr + 0, BCM2708_DMA_S_INC | BCM2708_DMA_D_INC); /* TI */
+    writel(cb_addr + 4, src_addr); /* source address */
+    writel(cb_addr + 8, dst_addr); /* destination address */
+    writel(cb_addr + 12, 1); /* ⚠️ txfr_len = 1 (TRIGGER!) */
+    writel(cb_addr + 16, 0); /* stride */
+    writel(cb_addr + 20, 0); /* next CB = NULL */
+    /* Set control block address */
+    writel(dma_base + BCM2708_DMA_ADDR, cb_addr);
+    /* Trigger DMA - this will cause the vulnerability */
+    writel(dma_base + BCM2708_DMA_CS, BCM2708_DMA_ACTIVE);
+    /* Without the fix, QEMU process will hang at 100% CPU */
+}
+
 int main(int argc, char **argv)
 {
     int ret;
     g_test_init(&argc, &argv, NULL);
     qtest_add_func("/bcm2835/dma/test_interrupts",
                    bcm2835_dma_test_interrupts);
+    qtest_add_func("/bcm2835/dma/test_underflow_txfr",
+                   test_cve_underflow_txfr_len_1);
     qtest_start("-machine raspi3b");
     ret = g_test_run();
     qtest_end();
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835
  2025-11-11 10:54 [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835 Alex Bennée
@ 2025-11-11 11:24 ` Peter Maydell
  2025-11-14 16:05 ` Yodel Eldar
  1 sibling, 0 replies; 7+ messages in thread
From: Peter Maydell @ 2025-11-11 11:24 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Philippe Mathieu-Daudé, Fabiano Rosas,
	Laurent Vivier, Paolo Bonzini, open list:Raspberry Pi

On Tue, 11 Nov 2025 at 10:54, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> The datasheet doesn't explicitly say that TXFR_LEN has to be word
> aligned but the fact there is a DMA_D_WIDTH flag to select between 32
> bit and 128 bit strongly implies that is how it works. The downstream
> rpi kernel also goes to efforts to not write sub-4 byte lengths so
> lets:
>
>   - fail when mis-programmed and report GUEST_ERROR
>   - catch setting D_WIDTH for 128 bit and report UNIMP
>   - add comments that the DEBUG register isn't a straight write
>
> This includes the test case from the reported bug which is of unknown
> provenience but isn't particularly novel.

The emoji in the comment seems like a bit of a flag that
it might be AI-generated :-)

I would at least clean up the comments to be more in
line with our usual style and degree of detail.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835
  2025-11-11 10:54 [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835 Alex Bennée
  2025-11-11 11:24 ` Peter Maydell
@ 2025-11-14 16:05 ` Yodel Eldar
  2025-11-14 16:15   ` Peter Maydell
  2025-11-14 16:43   ` Alex Bennée
  1 sibling, 2 replies; 7+ messages in thread
From: Yodel Eldar @ 2025-11-14 16:05 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Peter Maydell, Philippe Mathieu-Daudé, Fabiano Rosas,
	Laurent Vivier, Paolo Bonzini, open list:Raspberry Pi,
	Yodel Eldar


On 11/11/2025 04:54, Alex Bennée wrote:
> The datasheet doesn't explicitly say that TXFR_LEN has to be word
> aligned but the fact there is a DMA_D_WIDTH flag to select between 32
> bit and 128 bit strongly implies that is how it works. The downstream

At the bottom of page 38, the datasheet [1] states "the DMA can deal
with byte aligned transfers and will minimise bus traffic by buffering
and packing misaligned accesses."

IIUC, the *_WIDTH info fields are implied as maxima.

[1] https://datasheets.raspberrypi.com/bcm2835/bcm2835-peripherals.pdf

Regards,
Yodel

> rpi kernel also goes to efforts to not write sub-4 byte lengths so
> lets:


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835
  2025-11-14 16:05 ` Yodel Eldar
@ 2025-11-14 16:15   ` Peter Maydell
  2025-11-14 16:43   ` Alex Bennée
  1 sibling, 0 replies; 7+ messages in thread
From: Peter Maydell @ 2025-11-14 16:15 UTC (permalink / raw)
  To: Yodel Eldar
  Cc: Alex Bennée, qemu-devel, Philippe Mathieu-Daudé,
	Fabiano Rosas, Laurent Vivier, Paolo Bonzini,
	open list:Raspberry Pi

On Fri, 14 Nov 2025 at 16:06, Yodel Eldar <yodel.eldar@yodel.dev> wrote:
>
>
> On 11/11/2025 04:54, Alex Bennée wrote:
> > The datasheet doesn't explicitly say that TXFR_LEN has to be word
> > aligned but the fact there is a DMA_D_WIDTH flag to select between 32
> > bit and 128 bit strongly implies that is how it works. The downstream
>
> At the bottom of page 38, the datasheet [1] states "the DMA can deal
> with byte aligned transfers and will minimise bus traffic by buffering
> and packing misaligned accesses."

Yeah, I read that, but my interpretation of it is that it says
it's OK to provide non-4-aligned source and destination addresses.
It doesn't say anything either way about whether the transfer
size can be a non-multiple of 4.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835
  2025-11-14 16:05 ` Yodel Eldar
  2025-11-14 16:15   ` Peter Maydell
@ 2025-11-14 16:43   ` Alex Bennée
  2025-11-14 16:51     ` Florian Kauer
  2025-11-16 13:48     ` Yodel Eldar
  1 sibling, 2 replies; 7+ messages in thread
From: Alex Bennée @ 2025-11-14 16:43 UTC (permalink / raw)
  To: Yodel Eldar
  Cc: qemu-devel, Peter Maydell, Philippe Mathieu-Daudé,
	Fabiano Rosas, Laurent Vivier, Paolo Bonzini,
	open list:Raspberry Pi, Florian Meier, Florian Fainelli

Yodel Eldar <yodel.eldar@yodel.dev> writes:

(add Florians to CC)

> On 11/11/2025 04:54, Alex Bennée wrote:
>> The datasheet doesn't explicitly say that TXFR_LEN has to be word
>> aligned but the fact there is a DMA_D_WIDTH flag to select between 32
>> bit and 128 bit strongly implies that is how it works. The downstream
>
> At the bottom of page 38, the datasheet [1] states "the DMA can deal
> with byte aligned transfers and will minimise bus traffic by buffering
> and packing misaligned accesses."
>
> IIUC, the *_WIDTH info fields are implied as maxima.
>
> [1] https://datasheets.raspberrypi.com/bcm2835/bcm2835-peripherals.pdf

That reads ambiguously - you could start a misaligned n*WIDTH transfer
and the hardware will write bytes until aligned?

If it does indeed work with byte accesses maybe we can just do:

  if (xlen & 0x3) {
    .. do one byte ..
    xlen -= 1;
  } else {
    .. existing 32 bit code ..
  }

but I guess we need to handle unaligned accesses as well.

Florian,

Can you help clarify what the datasheet means here?

Thanks,

<snip>

>> rpi kernel also goes to efforts to not write sub-4 byte lengths so
>> lets:

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835
  2025-11-14 16:43   ` Alex Bennée
@ 2025-11-14 16:51     ` Florian Kauer
  2025-11-16 13:48     ` Yodel Eldar
  1 sibling, 0 replies; 7+ messages in thread
From: Florian Kauer @ 2025-11-14 16:51 UTC (permalink / raw)
  To: Alex Bennée, Yodel Eldar
  Cc: qemu-devel, Peter Maydell, Philippe Mathieu-Daudé,
	Fabiano Rosas, Laurent Vivier, Paolo Bonzini,
	open list:Raspberry Pi, Florian Meier, Florian Fainelli



On 11/14/25 17:43, Alex Bennée wrote:
> Yodel Eldar <yodel.eldar@yodel.dev> writes:
> 
> (add Florians to CC)
> 
>> On 11/11/2025 04:54, Alex Bennée wrote:
>>> The datasheet doesn't explicitly say that TXFR_LEN has to be word
>>> aligned but the fact there is a DMA_D_WIDTH flag to select between 32
>>> bit and 128 bit strongly implies that is how it works. The downstream
>>
>> At the bottom of page 38, the datasheet [1] states "the DMA can deal
>> with byte aligned transfers and will minimise bus traffic by buffering
>> and packing misaligned accesses."
>>
>> IIUC, the *_WIDTH info fields are implied as maxima.
>>
>> [1] https://datasheets.raspberrypi.com/bcm2835/bcm2835-peripherals.pdf
> 
> That reads ambiguously - you could start a misaligned n*WIDTH transfer
> and the hardware will write bytes until aligned?
> 
> If it does indeed work with byte accesses maybe we can just do:
> 
>   if (xlen & 0x3) {
>     .. do one byte ..
>     xlen -= 1;
>   } else {
>     .. existing 32 bit code ..
>   }
> 
> but I guess we need to handle unaligned accesses as well.
> 
> Florian,
> 
> Can you help clarify what the datasheet means here?


Sorry, I won't be of big help here. I have no further insights apart from what the datasheet says.
I implemented this driver many years ago and it worked for my specific use case (enabling the I2S interface of the Raspberry Pi) this way,
but I cannot make a confident statement about unaligned access :-(

Greetings,
Florian


> 
> Thanks,
> 
> <snip>
> 
>>> rpi kernel also goes to efforts to not write sub-4 byte lengths so
>>> lets:
> 



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835
  2025-11-14 16:43   ` Alex Bennée
  2025-11-14 16:51     ` Florian Kauer
@ 2025-11-16 13:48     ` Yodel Eldar
  1 sibling, 0 replies; 7+ messages in thread
From: Yodel Eldar @ 2025-11-16 13:48 UTC (permalink / raw)
  To: Alex Bennée, Yodel Eldar
  Cc: yodel.eldar, qemu-devel, Peter Maydell,
	Philippe Mathieu-Daudé, Fabiano Rosas, Laurent Vivier,
	Paolo Bonzini, open list:Raspberry Pi, Florian Meier,
	Florian Fainelli


On 14/11/2025 10:43, Alex Bennée wrote:
> Yodel Eldar <yodel.eldar@yodel.dev> writes:
> 
> (add Florians to CC)
> 
>> On 11/11/2025 04:54, Alex Bennée wrote:
>>> The datasheet doesn't explicitly say that TXFR_LEN has to be word
>>> aligned but the fact there is a DMA_D_WIDTH flag to select between 32
>>> bit and 128 bit strongly implies that is how it works. The downstream
>>
>> At the bottom of page 38, the datasheet [1] states "the DMA can deal
>> with byte aligned transfers and will minimise bus traffic by buffering
>> and packing misaligned accesses."
>>
>> IIUC, the *_WIDTH info fields are implied as maxima.
>>
>> [1] https://datasheets.raspberrypi.com/bcm2835/bcm2835-peripherals.pdf
> 
> That reads ambiguously - you could start a misaligned n*WIDTH transfer
> and the hardware will write bytes until aligned?
> 
> If it does indeed work with byte accesses maybe we can just do:
> 
>    if (xlen & 0x3) {
>      .. do one byte ..
>      xlen -= 1;
>    } else {
>      .. existing 32 bit code ..
>    }
> 
> but I guess we need to handle unaligned accesses as well.
> 
> Florian,
> 
> Can you help clarify what the datasheet means here?
> 
> Thanks,
> 
> <snip>
> 
>>> rpi kernel also goes to efforts to not write sub-4 byte lengths so
>>> lets:
> 

Sorry for the lagged response: I was reviewing the datasheet and,
failing to find clarity there, familiarizing myself with the AXI
protocol spec and relevant driver code. Unfortunately, I'm still
uncertain about how the DMA controller handles unaligned values in
TXFR_LEN.XLENGTH, but below I've listed some of my abridged findings in
the hope that it may be of some help. Given my ambivalence regarding
the answer to the question, I defer to Alex and the community.

In alignment with Peter's comment, the AXI spec clearly explicates
support of unaligned start address transfers [1] but doesn't appear to
require support of unaligned ending transfers, although, that doesn't
preclude them either.

On the other hand, we know the BCM2835 supports write strobes at least
for triggering cache prefetching [2], and that this "allows memory
structures to be implemented that can be written using byte and half
word accesses" [3]. The specification also states "[a]ll [manager]
interfaces and interconnect must provide correct write strobes" and
that subordinate components can choose to: fully use them, ignore them
(i.e., "treat all writes as being the full data bus width"), or detect
unsupported write strobe combinations and provide an error response.
Moreover, "[a]ny [subordinate] component that is providing memory-like
behavior must fully support write strobes" [3]. To me, this suggests
that the BCM2835 has what it needs to be able to invalidate the bytes
past the TXFR_LEN bytes in the final beat of a DMA write transaction...
but IIUC it's possible to forego that and remain AXI-compliant.

Section 4.2 of {A}, Burst Length, also mentions the use of write strobes
for partial write transactions and extends it to cover read transactions
via discarding, too:

     No component can terminate a burst early to reduce the number of
     data transfers. During a write burst, the [manager] can disable
     further writing by deasserting all the write strobes, but it
     must complete the remaining transfers in the burst. During a
     read burst, the [manager] can discard further read data, but it
     must complete the remaining transfers in the burst. [4]

As a counterpoint, however, perhaps only whole transfers of a read
transaction can be discarded, or the BCM2835 forewent it altogether.

Narrow Transfers, section 9.3, also mentions the generation of transfers
that are narrower than the data bus of the manager [5].

All of the above are taken from the AXI spec, but as mentioned earlier
some of these features are opt-in, and the BCM2835 could have skipped
them. So, lastly, let's consider TXFR_LEN from the datasheet [6]: It's
described as "specif[ying] the amount of data to be transferred in
bytes." Moreover, all of the bits of its bitfield are accounted,
including TXFR_LEN[31:30]: "Reserved - Write as 0, read as don't care."
It could be an unfortunate oversight that the authors' didn't describe
TXFR_LEN[1:0] with the same description, or it could be intentional. If
XLENGTH's two LSBs are always 0 (or just ignored), then couldn't
TXFR_LEN simply indicate the number of transfers instead of the total
number of bytes transferred in a transaction, like YLENGTH in 2D mode?

I'm inclined to think that the line about the DMA dealing with byte
aligned transfers means that both unaligned start addresses and
a partial terminal data transfers via packing, buffering, discarding,
and the application of write strobes on full-width transfers are
possible, but without more precise language or a test on hardware (not
planned anytime soon), I can't be sure. Also, please let me know if
I misunderstood any of the source material or important details I
may have missed.

In the absence of certainty and for the sake of addressing the DoS issue
that inspired the patch, perhaps it's better to leave the patch as is
with a comment soliciting further investigation on actual behavior?

{A} AMBA AXI Protocol Version: 2.0 Specification
     https://documentation-service.arm.com/static/64256e84314e245d086bc88f

{B} BCM2835 ARM Peripherals
     https://datasheets.raspberrypi.com/bcm2835/bcm2835-peripherals.pdf

[1] {A} (p. 10-2)
[2] {B} (p. 51)
[3] {A} (p. 14-5)
[4] {A} (p. 4-3)
[5] {A} (p. 9-4)
[6] {B} (p. 53)

Thanks,
Yodel

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-11-16 13:49 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-11 10:54 [RFC PATCH] hw/dma: don't allow weird transfer lengths for bcm2835 Alex Bennée
2025-11-11 11:24 ` Peter Maydell
2025-11-14 16:05 ` Yodel Eldar
2025-11-14 16:15   ` Peter Maydell
2025-11-14 16:43   ` Alex Bennée
2025-11-14 16:51     ` Florian Kauer
2025-11-16 13:48     ` Yodel Eldar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).