From e696574fb5308199a28e6a28aab430b6e6ae4104 Mon Sep 17 00:00:00 2001 From: Santosh Sakore Date: Sun, 23 Apr 2023 11:20:31 +0530 Subject: [PATCH] msm: adsprpc: block smmu unmap of buffer used in pending rpc call A dynamic SMMU mapping created as part of an RPC call can potentially be removed by a parallel munmap ioctl call before the RPC call is complete, leading to SMMU faults. Maintain a ref-count that indicates that the mapping is being used by a pending RPC call and allow the mapping to be removed only if this count is 0. Change-Id: Ieb4ff6b298ff9c48953bc5b3539fdfe19a14b442 Acked-by: Santosh Sakore Signed-off-by: Santosh Sakore --- dsp/adsprpc.c | 51 +++++++++++++++++++++++++++++++++++++++----- dsp/adsprpc_shared.h | 2 ++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/dsp/adsprpc.c b/dsp/adsprpc.c index 0f0f90d924..d92bda4a3f 100644 --- a/dsp/adsprpc.c +++ b/dsp/adsprpc.c @@ -957,6 +957,8 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, int fd, uintptr_t va, if ((fd < 0 || map->fd == fd) && map->raddr == va && map->raddr + map->len == va + len && map->refs == 1 && + /* Remove map only if it isn't being used in any pending RPC calls */ + !map->ctx_refs && /* Skip unmap if it is fastrpc shell memory */ !map->is_filemap) { match = map; @@ -997,7 +999,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { spin_lock_irqsave(&me->hlock, irq_flags); map->refs--; - if (!map->refs && !map->is_persistent) + if (!map->refs && !map->is_persistent && !map->ctx_refs) hlist_del_init(&map->hn); spin_unlock_irqrestore(&me->hlock, irq_flags); if (map->refs > 0) { @@ -1012,7 +1014,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) spin_unlock_irqrestore(&me->hlock, irq_flags); } else { map->refs--; - if (!map->refs) + if (!map->refs && !map->ctx_refs) hlist_del_init(&map->hn); if (map->refs > 0 && !flags) return; @@ -1953,8 +1955,15 @@ static void context_free(struct smq_invoke_ctx *ctx) spin_unlock(&ctx->fl->hlock); mutex_lock(&ctx->fl->map_mutex); - for (i = 0; i < nbufs; ++i) + for (i = 0; i < nbufs; ++i) { + /* + * Decrement ctx refs count before mmap free, + * indicate remote call no longer using it + */ + if (ctx->maps[i] && ctx->maps[i]->ctx_refs) + ctx->maps[i]->ctx_refs--; fastrpc_mmap_free(ctx->maps[i], 0); + } mutex_unlock(&ctx->fl->map_mutex); fastrpc_buf_free(ctx->buf, 1); @@ -2342,6 +2351,12 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) err = fastrpc_mmap_create(ctx->fl, ctx->fds[i], NULL, ctx->attrs[i], buf, len, mflags, &ctx->maps[i]); + /* + * Increment ctx refs count for in/out buffer if map created, + * indicate map under use in remote call + */ + if (ctx->maps[i]) + ctx->maps[i]->ctx_refs++; mutex_unlock(&ctx->fl->map_mutex); if (err) goto bail; @@ -2369,10 +2384,23 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) FASTRPC_ATTR_NOVA, 0, 0, dmaflags, &ctx->maps[i]); if (err) { - for (j = bufs; j < i; j++) + for (j = bufs; j < i; j++) { + /* + * Due to error decrement ctx refs count before mmap free + * for each in/out handle, if map created + */ + if (ctx->maps[j] && ctx->maps[j]->ctx_refs) + ctx->maps[j]->ctx_refs--; fastrpc_mmap_free(ctx->maps[j], 0); + } mutex_unlock(&ctx->fl->map_mutex); goto bail; + } else { + /* + * Increment ctx refs count for in/out handle if map created + * and no error, indicate map under use in remote call + */ + ctx->maps[i]->ctx_refs++; } ipage += 1; } @@ -2704,6 +2732,12 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, } } else { mutex_lock(&ctx->fl->map_mutex); + /* + * Decrement ctx refs count before mmap free, + * indicate remote call no longer using it + */ + if (ctx->maps[i]->ctx_refs) + ctx->maps[i]->ctx_refs--; fastrpc_mmap_free(ctx->maps[i], 0); mutex_unlock(&ctx->fl->map_mutex); ctx->maps[i] = NULL; @@ -2714,8 +2748,15 @@ 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], NULL, 0, 0, - 0, 0, &mmap)) + 0, 0, &mmap)) { + /* + * Decrement ctx refs count before mmap free, + * indicate remote call no longer using it + */ + if (mmap && mmap->ctx_refs) + mmap->ctx_refs--; fastrpc_mmap_free(mmap, 0); + } } mutex_unlock(&ctx->fl->map_mutex); if (ctx->crc && crclist && rpra) diff --git a/dsp/adsprpc_shared.h b/dsp/adsprpc_shared.h index 7fb2be94df..cea20a7d10 100644 --- a/dsp/adsprpc_shared.h +++ b/dsp/adsprpc_shared.h @@ -1031,6 +1031,8 @@ struct fastrpc_mmap { /* Mapping for fastrpc shell */ bool is_filemap; char *servloc_name; /* Indicate which daemon mapped this */ + /* Indicates map is being used by a pending RPC call */ + unsigned int ctx_refs; }; enum fastrpc_perfkeys {