busdma: avoid buflen underflow

The loop condition in the dmamap_load_buffer() method is 'buflen > 0',
and buflen is an unsigned type (bus_size_t).

A recent change made it possible for sgsize to exceed the remaining
buflen, when the tag has a large alignment requirement. The result is
that we would not break out of the loop at the correct time. Fix this by
avoiding underflow in the subtraction at the end of the loop.

PR:		279383
Reported by:	Robert Morris <rtm@lcs.mit.edu>
Reviewed by:	jhibbits
Fixes:		a77e1f0f81 ("busdma: better handling of small segment bouncing")
Differential Revision:	https://reviews.freebsd.org/D45732
This commit is contained in:
Mitchell Horne 2024-07-08 11:51:31 -03:00
parent 4e148a7baa
commit 558c1b3733
5 changed files with 6 additions and 6 deletions

View File

@ -1035,7 +1035,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
segp))
break;
vaddr += sgsize;
buflen -= sgsize;
buflen -= MIN(sgsize, buflen); /* avoid underflow */
}
cleanup:

View File

@ -898,7 +898,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
segp))
break;
vaddr += sgsize;
buflen -= sgsize;
buflen -= MIN(sgsize, buflen); /* avoid underflow */
}
/*

View File

@ -656,7 +656,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
segp))
break;
vaddr += sgsize;
buflen -= sgsize;
buflen -= MIN(sgsize, buflen); /* avoid underflow */
}
/*

View File

@ -705,7 +705,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
segp))
break;
vaddr += sgsize;
buflen -= sgsize;
buflen -= MIN(sgsize, buflen); /* avoid underflow */
}
cleanup:

View File

@ -733,7 +733,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
segp))
break;
vaddr += sgsize;
buflen -= sgsize;
buflen -= MIN(sgsize, buflen); /* avoid underflow */
}
/*
@ -808,7 +808,7 @@ bounce_bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map,
break;
KASSERT(buflen >= sgsize,
("Segment length overruns original buffer"));
buflen -= sgsize;
buflen -= MIN(sgsize, buflen); /* avoid underflow */
if (((ma_offs + sgsize) & ~PAGE_MASK) != 0)
page_index++;
ma_offs = (ma_offs + sgsize) & PAGE_MASK;