summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVamsi Krishna Gattupalli <quic_vgattupa@quicinc.com>2023-05-04 12:27:54 +0530
committerAlexander Grund <flamefire89@gmail.com>2023-12-23 19:42:17 +0100
commit1f5e1652174f8c66c94b37fdf5fa2a43fe246650 (patch)
tree4da7ec7624695981019fc4d5886a78011658ac05
parentde77a21b93eb19e5f3b4bd45614dd81f0fff7019 (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.c26
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;