The branch main has been updated by mhorne:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=60fce0e22147e7378e5585258aea0645e2274528

commit 60fce0e22147e7378e5585258aea0645e2274528
Author:     Mitchell Horne <mho...@freebsd.org>
AuthorDate: 2025-08-09 18:04:27 +0000
Commit:     Mitchell Horne <mho...@freebsd.org>
CommitDate: 2025-08-09 18:42:33 +0000

    busdma: another fix for small bounce transfers
    
    More fallout from a77e1f0f81df.
    
    When the tag has an alignment requirement but a small (remaining)
    transfer size, the transfer will be rounded up to exceed its bounds,
    resulting in memory corruption.
    
    The issue is observed on powerpc as noted in the pull request:
    https://github.com/freebsd/freebsd-src/pull/1415
    
    I also observe the issue locally on riscv hardware, with an 8-byte
    transfer having 64-byte alignment.
    
    There is some uncertainty about the purpose/need for the alignment
    roundup; both its original intention and present effect. Notably, it is
    no longer present at all in arm/arm64 implementations. Possibly, this
    roundup can be removed altogether, but this requires more careful
    analysis of the edge-cases and history of the property.
    
    For now, simply clamp sgsize to be no larger than the remaining buflen,
    as this is certain to be correct within the current scheme and fixes
    the affected transfers.
    
    Discussed with: jhb, markj
    MFC after:      3 weeks
    Fixes:  a77e1f0f81df ("busdma: better handling of small segment bouncing")
    Sponsored by:   The FreeBSD Foundation
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/1415
    Signed-off-by:  Chattrapat Sangmanee <aomsi...@hotmail.co.th>
    Co-authored-by: Chattrapat Sangmanee <aomsi...@hotmail.co.th>
    Differential Revision:  https://reviews.freebsd.org/D47807
---
 sys/powerpc/powerpc/busdma_machdep.c | 1 +
 sys/riscv/riscv/busdma_bounce.c      | 1 +
 sys/x86/x86/busdma_bounce.c          | 1 +
 3 files changed, 3 insertions(+)

diff --git a/sys/powerpc/powerpc/busdma_machdep.c 
b/sys/powerpc/powerpc/busdma_machdep.c
index 65f90aa4affa..65a07c7ebc39 100644
--- a/sys/powerpc/powerpc/busdma_machdep.c
+++ b/sys/powerpc/powerpc/busdma_machdep.c
@@ -648,6 +648,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
                sgsize = MIN(buflen, PAGE_SIZE - (curaddr & PAGE_MASK));
                if (map->pagesneeded != 0 && must_bounce(dmat, curaddr)) {
                        sgsize = roundup2(sgsize, dmat->alignment);
+                       sgsize = MIN(sgsize, buflen);
                        curaddr = add_bounce_page(dmat, map, kvaddr, curaddr,
                            sgsize);
                }
diff --git a/sys/riscv/riscv/busdma_bounce.c b/sys/riscv/riscv/busdma_bounce.c
index f652f08bf5dc..9d9556fc72f9 100644
--- a/sys/riscv/riscv/busdma_bounce.c
+++ b/sys/riscv/riscv/busdma_bounce.c
@@ -672,6 +672,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, 
bus_dmamap_t map, void *buf,
                    map->pagesneeded != 0 &&
                    addr_needs_bounce(dmat, curaddr)) {
                        sgsize = roundup2(sgsize, dmat->common.alignment);
+                       sgsize = MIN(sgsize, buflen);
                        curaddr = add_bounce_page(dmat, map, kvaddr, curaddr,
                            sgsize);
                } else if ((dmat->bounce_flags & BF_COHERENT) == 0) {
diff --git a/sys/x86/x86/busdma_bounce.c b/sys/x86/x86/busdma_bounce.c
index 040174113104..e86279aa9c98 100644
--- a/sys/x86/x86/busdma_bounce.c
+++ b/sys/x86/x86/busdma_bounce.c
@@ -726,6 +726,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, 
bus_dmamap_t map, void *buf,
                    map->pagesneeded != 0 &&
                    must_bounce(dmat, curaddr)) {
                        sgsize = roundup2(sgsize, dmat->common.alignment);
+                       sgsize = MIN(sgsize, buflen);
                        curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, 0,
                            sgsize);
                }

Reply via email to