Re: [PATCH v7] dma-buf: Fix silent overflow for phys vec to sgt
David Hu <[email protected]>
| Newsgroups | dev.linux.lists.iommu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-media,org.kernel.vger.stable |
|---|---|
| Message-ID | <CAPd9Lg_30aqB6x342xLeFAc4exgXwWzwBc4KWh6+3p-N=yAwsw@mail.gmail.com> |
On Tue, Jun 9, 2026 at 12:40 PM David Hu <[email protected]> wrote: > > In case MMIO size is bigger than 4G and peer2peer DMA goes > through host bridge, we trigger a code path that assigns the > total linked IOVA (which is greater than 4G) to mapped_len. > > Previously, `mapped_len` was declared as 32-bit `unsigned int`. > When accumulating `size_t` lengths, this leads to a silent wrap-around. > This truncation causes truncated lengths to be passed to functions > like `fill_sg_entry()`. > > Fix this by changing `mapped_len` to `size_t` (64-bit). While > at it, fix similar potential overflow issues in `calc_sg_nents` > by using `check_add_overflow()` for `nents` and using > `unsigned int` for the loop iterator in `fill_sg_entry` to match. > > Fixes: 3aa31a8bb11e ("dma-buf: provide phys_vec to scatter-gather mapping routine") > Cc: [email protected] > Cc: [email protected] > Reviewed-by: Pranjal Shrivastava <[email protected]> > Reviewed-by: Kevin Tian <[email protected]> > Reviewed-by: Leon Romanovsky <[email protected]> > Signed-off-by: David Hu <[email protected]> > --- > Changes in v7: > - Added a missing blank line after local variable declaration in > `calc_sg_nents()` (Leon). > - Collected Reviewed-by from Leon Romanovsky. > > Changes in v6: > - Used `check_add_overflow()` in `calc_sg_nents()` for safer > accumulation (Leon). > - Dropped explicit `!nents` check and added a comment noting that > `sg_alloc_table` handles `nents == 0` (Leon). > - Collected Reviewed-by from Kevin Tian. > > Changes in v5: > - Removed WARN_ON_ONCE from calc_sg_nents() to avoid log noise (Jason). > - Added explicit check for `!nents` in dma_buf_phys_vec_to_sgt() to > cleanly return -EINVAL on overflow (Jason). > > Changes in v4: > - Added WARN_ON_ONCE() to the nents overflow check to prevent silent > failures (Claude Bot). > > Changes in v3: > - Removed leftover sentence fragment from the commit message. > - Kept `nents = 0` initialization (previously stated as removed in the > v2 changelog) as it is strictly required for the `+=` accumulation > loop in `calc_sg_nents()`. > > Changes in v2: > - Fixed 'IVOA' -> 'IOVA' typo and expanded commit message (Claude Bot). > - Added Reverse Xmas tree formatting (Pranjal). > - Folded in extra bounds checking for calc_sg_nents() (Pranjal). > - Folded in type consistency fix for fill_sg_entry() (Pranjal). > - Collected Reviewed-by from Pranjal Shrivastava. > > drivers/dma-buf/dma-buf-mapping.c | 16 ++++++++++++---- > 1 file changed, 12 insertions(+), 4 deletions(-) > > diff --git a/drivers/dma-buf/dma-buf-mapping.c b/drivers/dma-buf/dma-buf-mapping.c > index 794acff2546a..80f6ab2f4809 100644 > --- a/drivers/dma-buf/dma-buf-mapping.c > +++ b/drivers/dma-buf/dma-buf-mapping.c > @@ -5,12 +5,13 @@ > */ > #include <linux/dma-buf-mapping.h> > #include <linux/dma-resv.h> > +#include <linux/overflow.h> > > static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length, > dma_addr_t addr) > { > unsigned int len, nents; > - int i; > + unsigned int i; > > nents = DIV_ROUND_UP(length, UINT_MAX); > for (i = 0; i < nents; i++) { > @@ -40,8 +41,12 @@ static unsigned int calc_sg_nents(struct dma_iova_state *state, > size_t i; > > if (!state || !dma_use_iova(state)) { > - for (i = 0; i < nr_ranges; i++) > - nents += DIV_ROUND_UP(phys_vec[i].len, UINT_MAX); > + for (i = 0; i < nr_ranges; i++) { > + unsigned int added = DIV_ROUND_UP(phys_vec[i].len, UINT_MAX); > + > + if (check_add_overflow(nents, added, &nents)) > + return 0; > + } > } else { > /* > * In IOVA case, there is only one SG entry which spans > @@ -95,9 +100,10 @@ struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach, > size_t nr_ranges, size_t size, > enum dma_data_direction dir) > { > - unsigned int nents, mapped_len = 0; > struct dma_buf_dma *dma; > struct scatterlist *sgl; > + size_t mapped_len = 0; > + unsigned int nents; > dma_addr_t addr; > size_t i; > int ret; > @@ -133,6 +139,8 @@ struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach, > } > > nents = calc_sg_nents(dma->state, phys_vec, nr_ranges, size); > + > + /* sg_alloc_table will cleanly fail and return -EINVAL if nents == 0 */ > ret = sg_alloc_table(&dma->sgt, nents, GFP_KERNEL | __GFP_ZERO); > if (ret) > goto err_free_state; > -- > 2.54.0.1064.gd145956f57-goog > Hi Christian et al, Gentle nudge on this. LMK if there is anything else needed. Regards, David