Merge "dsp-kernel: use-after-free (UAF) in global maps"

This commit is contained in:
qctecmdr
2024-05-16 09:35:18 -07:00
committed by Gerrit - the friendly Code Review server

View File

@@ -825,54 +825,34 @@ static void fastrpc_remote_buf_list_free(struct fastrpc_file *fl)
} while (free); } while (free);
} }
static void fastrpc_mmap_add_global(struct fastrpc_mmap *map)
{
struct fastrpc_apps *me = &gfa;
unsigned long irq_flags = 0;
spin_lock_irqsave(&me->hlock, irq_flags);
hlist_add_head(&map->hn, &me->maps);
spin_unlock_irqrestore(&me->hlock, irq_flags);
}
static void fastrpc_mmap_add(struct fastrpc_mmap *map) static void fastrpc_mmap_add(struct fastrpc_mmap *map)
{ {
if (map->flags == ADSP_MMAP_HEAP_ADDR || struct fastrpc_file *fl = map->fl;
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
struct fastrpc_apps *me = &gfa;
unsigned long irq_flags = 0;
spin_lock_irqsave(&me->hlock, irq_flags); hlist_add_head(&map->hn, &fl->maps);
hlist_add_head(&map->hn, &me->maps);
spin_unlock_irqrestore(&me->hlock, irq_flags);
} else {
struct fastrpc_file *fl = map->fl;
hlist_add_head(&map->hn, &fl->maps);
}
} }
static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd,
struct dma_buf *buf, uintptr_t va, size_t len, int mflags, int refs, struct dma_buf *buf, uintptr_t va, size_t len, int mflags, int refs,
struct fastrpc_mmap **ppmap) struct fastrpc_mmap **ppmap)
{ {
struct fastrpc_apps *me = &gfa;
struct fastrpc_mmap *match = NULL, *map = NULL; struct fastrpc_mmap *match = NULL, *map = NULL;
struct hlist_node *n; struct hlist_node *n;
unsigned long irq_flags = 0;
if ((va + len) < va) if ((va + len) < va)
return -EFAULT; return -EFAULT;
if (mflags == ADSP_MMAP_HEAP_ADDR || if (mflags == ADSP_MMAP_DMA_BUFFER) {
mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
spin_lock_irqsave(&me->hlock, irq_flags);
hlist_for_each_entry_safe(map, n, &me->maps, hn) {
if (va >= map->va &&
va + len <= map->va + map->len &&
map->fd == fd) {
if (refs) {
if (map->refs + 1 == INT_MAX) {
spin_unlock_irqrestore(&me->hlock, irq_flags);
return -ETOOMANYREFS;
}
map->refs++;
}
match = map;
break;
}
}
spin_unlock_irqrestore(&me->hlock, irq_flags);
} else if (mflags == ADSP_MMAP_DMA_BUFFER) {
hlist_for_each_entry_safe(map, n, &fl->maps, hn) { hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
if (map->buf == buf) { if (map->buf == buf) {
if (refs) { if (refs) {
@@ -1493,8 +1473,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, struct dma_buf *
else else
fl->mem_snap.nonheap_bufs_size += map->size; fl->mem_snap.nonheap_bufs_size += map->size;
spin_unlock(&fl->hlock); spin_unlock(&fl->hlock);
if ((mflags != ADSP_MMAP_HEAP_ADDR) &&
fastrpc_mmap_add(map); (mflags != ADSP_MMAP_REMOTE_HEAP_ADDR))
fastrpc_mmap_add(map);
*ppmap = map; *ppmap = map;
bail: bail:
@@ -4411,6 +4392,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_file *fl,
spin_lock_irqsave(&me->hlock, irq_flags); spin_lock_irqsave(&me->hlock, irq_flags);
mem->in_use = true; mem->in_use = true;
spin_unlock_irqrestore(&me->hlock, irq_flags); spin_unlock_irqrestore(&me->hlock, irq_flags);
fastrpc_mmap_add_global(mem);
} }
VERIFY(err, mem); VERIFY(err, mem);
if (err) if (err)
@@ -5273,7 +5255,7 @@ static int fastrpc_mmap_dump(struct fastrpc_mmap *map, struct fastrpc_file *fl,
match->size, match->flags, 0); match->size, match->flags, 0);
else { else {
pr_err("Cannot communicate with DSP, ADSP is down\n"); pr_err("Cannot communicate with DSP, ADSP is down\n");
fastrpc_mmap_add(match); fastrpc_mmap_add_global(match);
} }
} }
if (err) if (err)
@@ -5345,7 +5327,7 @@ bail:
if (err && match) { if (err && match) {
if (!locked && fl) if (!locked && fl)
mutex_lock(&fl->map_mutex); mutex_lock(&fl->map_mutex);
fastrpc_mmap_add(match); fastrpc_mmap_add_global(match);
if (!locked && fl) if (!locked && fl)
mutex_unlock(&fl->map_mutex); mutex_unlock(&fl->map_mutex);
} }
@@ -5484,7 +5466,11 @@ int fastrpc_internal_munmap(struct fastrpc_file *fl,
bail: bail:
if (err && map) { if (err && map) {
mutex_lock(&fl->map_mutex); mutex_lock(&fl->map_mutex);
fastrpc_mmap_add(map); if ((map->flags == ADSP_MMAP_HEAP_ADDR) ||
(map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR))
fastrpc_mmap_add_global(map);
else
fastrpc_mmap_add(map);
mutex_unlock(&fl->map_mutex); mutex_unlock(&fl->map_mutex);
} }
mutex_unlock(&fl->internal_map_mutex); mutex_unlock(&fl->internal_map_mutex);
@@ -5571,6 +5557,9 @@ int fastrpc_internal_mem_map(struct fastrpc_file *fl,
if (err) if (err)
goto bail; goto bail;
ud->m.vaddrout = map->raddr; ud->m.vaddrout = map->raddr;
if (ud->m.flags == ADSP_MMAP_HEAP_ADDR ||
ud->m.flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
fastrpc_mmap_add_global(map);
bail: bail:
if (err) { if (err) {
ADSPRPC_ERR("failed to map fd %d, len 0x%x, flags %d, map %pK, err %d\n", ADSPRPC_ERR("failed to map fd %d, len 0x%x, flags %d, map %pK, err %d\n",
@@ -5635,7 +5624,11 @@ bail:
/* Add back to map list in case of error to unmap on DSP */ /* Add back to map list in case of error to unmap on DSP */
if (map) { if (map) {
mutex_lock(&fl->map_mutex); mutex_lock(&fl->map_mutex);
fastrpc_mmap_add(map); if ((map->flags == ADSP_MMAP_HEAP_ADDR) ||
(map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR))
fastrpc_mmap_add_global(map);
else
fastrpc_mmap_add(map);
mutex_unlock(&fl->map_mutex); mutex_unlock(&fl->map_mutex);
} }
} }
@@ -5709,6 +5702,9 @@ int fastrpc_internal_mmap(struct fastrpc_file *fl,
if (err) if (err)
goto bail; goto bail;
map->raddr = raddr; map->raddr = raddr;
if (ud->flags == ADSP_MMAP_HEAP_ADDR ||
ud->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
fastrpc_mmap_add_global(map);
} }
ud->vaddrout = raddr; ud->vaddrout = raddr;
bail: bail: