diff options
author | Vamsi Krishna Gattupalli <quic_vgattupa@quicinc.com> | 2023-05-04 12:27:54 +0530 |
---|---|---|
committer | Alexander Grund <flamefire89@gmail.com> | 2023-12-23 19:42:17 +0100 |
commit | 1f5e1652174f8c66c94b37fdf5fa2a43fe246650 (patch) | |
tree | 4da7ec7624695981019fc4d5886a78011658ac05 | |
parent | de77a21b93eb19e5f3b4bd45614dd81f0fff7019 (diff) |
msm: adsprpc: Handle UAF in fastrpc internal munmap
Added reference count for contex map indicate memory under used
in remote call. And, this memory would not removed in internal
unmap to avoid UAF.
Change-Id: Ieb4ff6b298ff9c48953bc5b3539fdfe19a14b442
Acked-by: DEEPAK SANNAPAREDDY <sdeeredd@qti.qualcomm.com>
Signed-off-by: Vamsi Krishna Gattupalli <quic_vgattupa@quicinc.com>
-rw-r--r-- | drivers/char/adsprpc.c | 26 |
1 files changed, 18 insertions, 8 deletions
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 3f1ec8dab244..1662707f0d1a 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -299,7 +299,8 @@ struct fastrpc_mmap { int uncached; int secure; uintptr_t attr; - bool is_filemap; /*flag to indicate map used in process init*/ + bool is_filemap; /* flag to indicate map used in process init */ + unsigned int ctx_refs; /* Indicates reference count for context map */ }; struct fastrpc_perf { @@ -556,7 +557,7 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, hlist_for_each_entry_safe(map, n, &me->maps, hn) { if (map->refs == 1 && map->raddr == va && map->raddr + map->len == va + len && - /*Remove map if not used in process initialization*/ + /* Remove map if not used in process initialization */ !map->is_filemap) { match = map; hlist_del_init(&map->hn); @@ -569,9 +570,10 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, return 0; } hlist_for_each_entry_safe(map, n, &fl->maps, hn) { - if (map->refs == 1 && map->raddr == va && + /* Remove if only one reference map and no context map */ + if (map->refs == 1 && !map->ctx_refs && map->raddr == va && map->raddr + map->len == va + len && - /*Remove map if not used in process initialization*/ + /* Remove map if not used in process initialization */ !map->is_filemap) { match = map; hlist_del_init(&map->hn); @@ -609,11 +611,11 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map) if (map->flags == ADSP_MMAP_HEAP_ADDR || map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { map->refs--; - if (!map->refs) + if (!map->refs && !map->ctx_refs) hlist_del_init(&map->hn); } else { map->refs--; - if (!map->refs) + if (!map->refs && !map->ctx_refs) hlist_del_init(&map->hn); } if (map->refs > 0) @@ -706,6 +708,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned attr, map->fd = fd; map->attr = attr; map->is_filemap = false; + map->ctx_refs = 0; if (mflags == ADSP_MMAP_HEAP_ADDR || mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { DEFINE_DMA_ATTRS(rh_attrs); @@ -1124,8 +1127,11 @@ static void context_free(struct smq_invoke_ctx *ctx) hlist_del_init(&ctx->hn); spin_unlock(&ctx->fl->hlock); mutex_lock(&ctx->fl->map_mutex); - for (i = 0; i < nbufs; ++i) + for (i = 0; i < nbufs; ++i) { + if (ctx->maps[i] && ctx->maps[i]->ctx_refs) + ctx->maps[i]->ctx_refs--; fastrpc_mmap_free(ctx->maps[i]); + } mutex_unlock(&ctx->fl->map_mutex); fastrpc_buf_free(ctx->buf, 1); fastrpc_buf_free(ctx->lbuf, 1); @@ -1271,6 +1277,8 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) fastrpc_mmap_create(ctx->fl, ctx->fds[i], ctx->attrs[i], buf, len, mflags, &ctx->maps[i]); + if (ctx->maps[i]) + ctx->maps[i]->ctx_refs++; mutex_unlock(&ctx->fl->map_mutex); ipage += 1; } @@ -1489,6 +1497,8 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, goto bail; } else { mutex_lock(&ctx->fl->map_mutex); + if (ctx->maps[i]->ctx_refs) + ctx->maps[i]->ctx_refs--; fastrpc_mmap_free(ctx->maps[i]); mutex_unlock(&ctx->fl->map_mutex); ctx->maps[i] = NULL; |