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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.