Merge "msm: adsprpc: Handle UAF in fastrpc internal munmap"

This commit is contained in:
qctecmdr 2023-04-23 09:47:15 -07:00 committed by Gerrit - the friendly Code Review server
commit 489c7f8c5a

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* 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.
*/
/* Uncomment this block to log an error on every VERIFY failure */
@ -579,10 +579,11 @@ struct fastrpc_mmap {
bool is_persistent; /* Indicates whether map is persistent */
int frpc_md_index; /* Minidump unique index */
uintptr_t attr;
bool in_use; /* Indicates if persistent map is in use*/
bool in_use; /* Indicates if persistent map is in use */
struct timespec64 map_start_time;
struct timespec64 map_end_time;
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 */
};
enum fastrpc_perfkeys {
@ -1220,7 +1221,7 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, int fd, 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);
@ -1233,9 +1234,10 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, int fd, uintptr_t va,
return 0;
}
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
if (map->refs == 1 && map->raddr == va &&
map->raddr + map->len == va + len &&
/*Remove map if not used in process initialization*/
/* 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 */
!map->is_filemap) {
match = map;
hlist_del_init(&map->hn);
@ -1274,7 +1276,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags)
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
spin_lock(&me->hlock);
map->refs--;
if (!map->refs && !map->is_persistent)
if (!map->refs && !map->is_persistent && !map->ctx_refs)
hlist_del_init(&map->hn);
spin_unlock(&me->hlock);
if (map->refs > 0) {
@ -1290,7 +1292,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags)
}
} else {
map->refs--;
if (!map->refs)
if (!map->refs && !map->ctx_refs)
hlist_del_init(&map->hn);
if (map->refs > 0 && !flags)
return;
@ -1426,6 +1428,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
map->attr = attr;
map->frpc_md_index = -1;
map->is_filemap = false;
map->ctx_refs = 0;
ktime_get_real_ts64(&map->map_start_time);
if (mflags == ADSP_MMAP_HEAP_ADDR ||
mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
@ -2177,8 +2180,11 @@ 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) {
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);
@ -2485,6 +2491,8 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
err = 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);
if (err)
goto bail;
@ -2502,9 +2510,14 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
err = fastrpc_mmap_create(ctx->fl, ctx->fds[i],
FASTRPC_ATTR_NOVA, 0, 0, dmaflags,
&ctx->maps[i]);
if (!err && ctx->maps[i])
ctx->maps[i]->ctx_refs++;
if (err) {
for (j = bufs; j < i; j++)
for (j = bufs; j < i; j++) {
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;
}
@ -2835,6 +2848,8 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
}
} else {
mutex_lock(&ctx->fl->map_mutex);
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;
@ -2845,8 +2860,11 @@ 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, 0, &mmap)) {
if (mmap && mmap->ctx_refs)
mmap->ctx_refs--;
fastrpc_mmap_free(mmap, 0);
}
}
mutex_unlock(&ctx->fl->map_mutex);
if (ctx->crc && crclist && rpra)