From e11076b7dfe33a2056930f63dd20a6e5c189029a Mon Sep 17 00:00:00 2001 From: Zahir Shabbir Khan Date: Tue, 4 Mar 2025 12:03:30 +0530 Subject: [PATCH 1/4] dmaengine: msm_gpi: fix to avoid null pointer access A null pointer dereference is possible in gpi_prep_slave_sg. Client drivers will allocate buffer and initiate bus xfer through qup over i2c. I2c geni driver will queue the buffer address to TRE'S using scatter-gather. Clients can pass NULL buffer, so added null pointer check before accessing the TRE. This is leading to dereferencing null pointer issue. To solve this, add check for null in transfer ring. Change-Id: I3a25a7da0d38c58f725e0996c458b1fb64c0fe09 Signed-off-by: Anil Veshala Veshala Signed-off-by: Somesh Dey Signed-off-by: Zahir Shabbir Khan --- drivers/dma/qcom/gpi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 44e2e7de129e..eb9aea7851ff 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2524,6 +2525,12 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, for_each_sg(sgl, sg, sg_len, i) { tre = sg_virt(sg); + if (!tre) { + kfree(gpi_desc); + GPII_ERR(gpii, gpii_chan->chid, "TRE address is null\n"); + return NULL; + } + if (sg_len == 1) { tre_type = MSM_GPI_TRE_TYPE(((struct msm_gpi_tre *)tre)); From 568fea2103684e538a8299d85837fc106bcb8373 Mon Sep 17 00:00:00 2001 From: Abhinav Parihar Date: Tue, 3 Jun 2025 13:22:30 +0530 Subject: [PATCH 2/4] msm: adsprpc: Prevent refcount increment for duplicate dmahandles When user passes same fd more than once in same remote call, it results in mapping refcount of dma handle being greater than one. Once DSP is done and passes dma handle fd in fdlist to unmap, it decrements the refcount by one and tries to delete the map. As the refcount is still greater than zero the mapping isn't deleted. This leads to stale mapping information. Avoid incrementing the map refcount when the same dmahandle is passed multiple times in a single remote call. This prevents stale mappings caused by non-zero refcounts after DSP unmaps the handle. Mapping removal should depend solely on DSP releasing all references, not on how many times the fd was passed. Change-Id: I69e98e98a6d494b5ffe0a845fd4579fe632edeeb Signed-off-by: Abhinav Parihar --- drivers/char/adsprpc.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index e8ba4bed8572..39bdf863b597 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ /* Uncomment this block to log an error on every VERIFY failure */ @@ -62,6 +62,7 @@ #define TZ_PIL_AUTH_QDSP6_PROC 1 #define FASTRPC_DMAHANDLE_NOMAP (16) +#define FASTRPC_MAP_DMA_HANDLE 0x20000 #define FASTRPC_ENOSUCH 39 #define DEBUGFS_SIZE 3072 @@ -1128,7 +1129,7 @@ static void fastrpc_mmap_add(struct fastrpc_mmap *map) } static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, - uintptr_t va, size_t len, int mflags, int refs, + uintptr_t va, size_t len, int mflags, bool refs, struct fastrpc_mmap **ppmap) { struct fastrpc_mmap *match = NULL, *map = NULL; @@ -1306,7 +1307,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) dma_free_attrs(me->dev, map->size, (void *)map->va, (dma_addr_t)map->phys, (unsigned long)map->attr); } - } else if (map->flags == FASTRPC_DMAHANDLE_NOMAP) { + } else if (map->flags & FASTRPC_DMAHANDLE_NOMAP) { trace_fastrpc_dma_unmap(cid, map->phys, map->size); if (!IS_ERR_OR_NULL(map->table)) dma_buf_unmap_attachment(map->attach, map->table, @@ -1391,6 +1392,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned long flags; int err = 0, vmid, sgl_index = 0; struct scatterlist *sgl = NULL; + bool take_ref = true; if (!fl) { err = -EBADF; @@ -1404,7 +1406,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, } chan = &apps->channel[cid]; - if (!fastrpc_mmap_find(fl, fd, va, len, mflags, 1, ppmap)) + if (mflags & FASTRPC_MAP_DMA_HANDLE) + take_ref = false; + if (!fastrpc_mmap_find(fl, fd, va, len, mflags, take_ref, ppmap)) return 0; map = kzalloc(sizeof(*map), GFP_KERNEL); VERIFY(err, !IS_ERR_OR_NULL(map)); @@ -1442,7 +1446,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, if (err) goto bail; } - } else if (mflags == FASTRPC_DMAHANDLE_NOMAP) { + } else if (mflags & FASTRPC_DMAHANDLE_NOMAP) { VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd))); if (err) { ADSPRPC_ERR("dma_buf_get failed for fd %d ret %ld\n", @@ -2496,10 +2500,10 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc); mutex_lock(&ctx->fl->map_mutex); for (i = bufs; i < bufs + handles; i++) { - int dmaflags = 0; + int dmaflags = FASTRPC_MAP_DMA_HANDLE; if (ctx->attrs && (ctx->attrs[i] & FASTRPC_ATTR_NOMAP)) - dmaflags = FASTRPC_DMAHANDLE_NOMAP; + dmaflags |= FASTRPC_DMAHANDLE_NOMAP; if (ctx->fds && (ctx->fds[i] != -1)) err = fastrpc_mmap_create(ctx->fl, ctx->fds[i], FASTRPC_ATTR_NOVA, 0, 0, dmaflags, @@ -2660,7 +2664,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (ctx->maps[i]) { /* check if map still exist */ if (!fastrpc_mmap_find(ctx->fl, ctx->fds[i], 0, 0, - 0, 0, &mmap)) { + 0, false, &mmap)) { if (mmap) { pages[i].addr = mmap->phys; pages[i].size = mmap->size; @@ -2875,7 +2879,7 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, if (!fdlist[i]) break; if (!fastrpc_mmap_find(ctx->fl, (int)fdlist[i], 0, 0, - 0, 0, &mmap)) { + 0, false, &mmap)) { if (mmap && mmap->dma_handle_refs) { mmap->dma_handle_refs = 0; fastrpc_mmap_free(mmap, 0); @@ -4955,7 +4959,7 @@ static int fastrpc_internal_munmap_fd(struct fastrpc_file *fl, } mutex_lock(&fl->internal_map_mutex); mutex_lock(&fl->map_mutex); - err = fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map); + err = fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, false, &map); if (err) { ADSPRPC_ERR( "mapping not found to unmap fd 0x%x, va 0x%llx, len 0x%x, err %d\n", From 4f37e589d976ba56a3dd87c06409aea7a35f2746 Mon Sep 17 00:00:00 2001 From: Vishakha Malik Date: Mon, 9 Jun 2025 15:31:59 +0530 Subject: [PATCH 3/4] crypto: qcedev - fix UAF in crypto-qti driver userspace to QCEDEV_IOCTL_MAP_BUF_REQ and QCEDEV_IOCTL_UNMAP_BUF_REQ, which can have a race condition resulting in a use-after-free (UAF). Change-Id: Iff51a098bbf9746e256e40a20fc37c5404f8aa22 Signed-off-by: Vishakha Malik --- drivers/crypto/msm/qcedev_smmu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/msm/qcedev_smmu.c b/drivers/crypto/msm/qcedev_smmu.c index 8d4844becc85..7039bce67c5c 100644 --- a/drivers/crypto/msm/qcedev_smmu.c +++ b/drivers/crypto/msm/qcedev_smmu.c @@ -329,10 +329,6 @@ int qcedev_check_and_map_buffer(void *handle, mapped_size = binfo->ion_buf.mapped_buf_size; atomic_inc(&binfo->ref_count); - /* Add buffer mapping information to regd buffer list */ - mutex_lock(&qce_hndl->registeredbufs.lock); - list_add_tail(&binfo->list, &qce_hndl->registeredbufs.list); - mutex_unlock(&qce_hndl->registeredbufs.lock); } /* Make sure the offset is within the mapped range */ @@ -344,6 +340,13 @@ int qcedev_check_and_map_buffer(void *handle, goto unmap; } + if (!found) { + /* Add buffer mapping information to regd buffer list */ + mutex_lock(&qce_hndl->registeredbufs.lock); + list_add_tail(&binfo->list, &qce_hndl->registeredbufs.list); + mutex_unlock(&qce_hndl->registeredbufs.lock); + } + /* return the mapped virtual address adjusted by offset */ *vaddr += offset; @@ -352,9 +355,6 @@ int qcedev_check_and_map_buffer(void *handle, unmap: if (!found) { qcedev_unmap_buffer(handle, mem_client, binfo); - mutex_lock(&qce_hndl->registeredbufs.lock); - list_del(&binfo->list); - mutex_unlock(&qce_hndl->registeredbufs.lock); } error: From 695a2b9f1df15cd1f562344041700997b602a861 Mon Sep 17 00:00:00 2001 From: Bibek Kumar Patro Date: Fri, 10 Jan 2025 10:53:44 +0530 Subject: [PATCH 4/4] dma-mapping-fast: Fix PMD offset calculation for non-2M aligned start aperture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify PMD offset calculation for domains with start apertures not 2M aligned. Currently, when this happens, the PMD offset is calculated to the next PMD, and hence each IOVA is mapped as IOVA + offset, causing the IOVA to be tagged to the wrong PA. Issue occurrence - With the following sample aperture settings by a fastmap client: qcom,iommu-dma-addr-pool = <0x87f10000 0x07f00000>; qcom,iommu-geometry = <0x87f10000 0x07f00000>; The effective IOVA range is bounded to iova_base: 0x87f10000, iova_end: 0x8FE10000, which makes the IOVA base not aligned to a 2MB boundary. While calculating PTE, this adds an extra “default offset” to the PMD base (since all PMD pages’ base addresses are 2MB aligned), which further gets added on top of the actual offset obtained by (iova - base). This causes the final PMD offset to have an additional delta, causing the IOVA to be tagged to the wrong PA. ALIGN_DOWN(base, SZ_2M) helps to remove the extra “default offset,” helping to tag the IOVA to the right PA. ┌────────┐ PMD 1 base │ ├──────►┌┬──────┬┐◄── │ │ ││ ││ ALIGN_DOWN(base, SZ_2M) │PGD page├─┐ ││ old ││ │ │ │ ││offset││ │ │ │────►│└─ ││◄──── └────────┘ │wrong│ new ││ base │iova │offset─┘│◄──── │ └────────┘ right │ iova │ PMD 2 base └────►┌────────┐◄──── │ │ ALIGN_UP(base, SZ_2M) │ │ │ │ │ │ │ │ └┬───────┘ │PMD n base ┌┴───────┐ │ │ │ │ │ │ │ │ │ │ └────────┘ Change-Id: Ie320816ee91710fe06cf2337816d0fb8638ccbcb Fixes: 2e87440c3e6f ("iommu/io-pgtable-fast: optimize statically allocated pages") Signed-off-by: Bibek Kumar Patro Signed-off-by: Srinivasarao Pathipati --- drivers/iommu/io-pgtable-fast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c index f07e93b33f05..67ca5c20c521 100644 --- a/drivers/iommu/io-pgtable-fast.c +++ b/drivers/iommu/io-pgtable-fast.c @@ -133,7 +133,7 @@ typeof(base) __base = (base); \ typeof(pmds) __pmds = (pmds); \ (__iova < __base) ? ERR_PTR(-EINVAL) : \ - __pmds + ((__iova - __base) >> AV8L_FAST_PAGE_SHIFT); \ + __pmds + ((__iova - ALIGN_DOWN(__base, SZ_2M)) >> AV8L_FAST_PAGE_SHIFT); \ }) static inline dma_addr_t av8l_dma_addr(void *addr)