6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ling Xu quic_lxu5@quicinc.com
commit 10df039834f84a297c72ec962c0f9b7c8c5ca31a upstream.
If multiple dma handles are passed with same fd over a remote call the kernel driver takes a reference and expects that put for the map will be called as many times to free the map. But DSP only updates the fd one time in the fd list when the DSP refcount goes to zero and hence kernel make put call only once for the fd. This can cause SMMU fault issue as the same fd can be used in future for some other call.
Fixes: 35a82b87135d ("misc: fastrpc: Add dma handle implementation") Cc: stable@kernel.org Co-developed-by: Ekansh Gupta ekansh.gupta@oss.qualcomm.com Signed-off-by: Ekansh Gupta ekansh.gupta@oss.qualcomm.com Signed-off-by: Ling Xu quic_lxu5@quicinc.com Reviewed-by: Dmitry Baryshkov dmitry.baryshkov@oss.qualcomm.com Signed-off-by: Srinivas Kandagatla srini@kernel.org Link: https://lore.kernel.org/r/20250912131236.303102-5-srini@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/misc/fastrpc.c | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-)
--- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -363,9 +363,8 @@ static int fastrpc_map_get(struct fastrp
static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd, - struct fastrpc_map **ppmap, bool take_ref) + struct fastrpc_map **ppmap) { - struct fastrpc_session_ctx *sess = fl->sctx; struct fastrpc_map *map = NULL; struct dma_buf *buf; int ret = -ENOENT; @@ -379,15 +378,6 @@ static int fastrpc_map_lookup(struct fas if (map->fd != fd || map->buf != buf) continue;
- if (take_ref) { - ret = fastrpc_map_get(map); - if (ret) { - dev_dbg(sess->dev, "%s: Failed to get map fd=%d ret=%d\n", - __func__, fd, ret); - break; - } - } - *ppmap = map; ret = 0; break; @@ -757,7 +747,7 @@ static const struct dma_buf_ops fastrpc_ .release = fastrpc_release, };
-static int fastrpc_map_create(struct fastrpc_user *fl, int fd, +static int fastrpc_map_attach(struct fastrpc_user *fl, int fd, u64 len, u32 attr, struct fastrpc_map **ppmap) { struct fastrpc_session_ctx *sess = fl->sctx; @@ -766,9 +756,6 @@ static int fastrpc_map_create(struct fas struct scatterlist *sgl = NULL; int err = 0, sgl_index = 0;
- if (!fastrpc_map_lookup(fl, fd, ppmap, true)) - return 0; - map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) return -ENOMEM; @@ -853,6 +840,24 @@ get_err: return err; }
+static int fastrpc_map_create(struct fastrpc_user *fl, int fd, + u64 len, u32 attr, struct fastrpc_map **ppmap) +{ + struct fastrpc_session_ctx *sess = fl->sctx; + int err = 0; + + if (!fastrpc_map_lookup(fl, fd, ppmap)) { + if (!fastrpc_map_get(*ppmap)) + return 0; + dev_dbg(sess->dev, "%s: Failed to get map fd=%d\n", + __func__, fd); + } + + err = fastrpc_map_attach(fl, fd, len, attr, ppmap); + + return err; +} + /* * Fastrpc payload buffer with metadata looks like: * @@ -925,8 +930,12 @@ static int fastrpc_create_maps(struct fa ctx->args[i].length == 0) continue;
- err = fastrpc_map_create(ctx->fl, ctx->args[i].fd, - ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]); + if (i < ctx->nbufs) + err = fastrpc_map_create(ctx->fl, ctx->args[i].fd, + ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]); + else + err = fastrpc_map_attach(ctx->fl, ctx->args[i].fd, + ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]); if (err) { dev_err(dev, "Error Creating map %d\n", err); return -EINVAL; @@ -1116,7 +1125,7 @@ cleanup_fdlist: for (i = 0; i < FASTRPC_MAX_FDLIST; i++) { if (!fdlist[i]) break; - if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false)) + if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap)) fastrpc_map_put(mmap); }