From 6dab51a3af6f217c1729452fa963d0d3568058ec Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Tue, 5 Mar 2024 17:19:52 +0530 Subject: [PATCH] dsp-kernel: use-after-free (UAF) in global maps Currently, remote heap maps get added to the global list before the fastrpc_internal_mmap function completes the mapping. Meanwhile, the fastrpc_internal_munmap function accesses the map, starts unmapping, and frees the map before the fastrpc_internal_mmap function completes, resulting in a use-after-free (UAF) issue. Add the map to the list after the fastrpc_internal_mmap function completes the mapping. Signed-off-by: Abhishek Singh Change-Id: I8aa23cf215e53d0613774c2b2657954bca6c72f4 --- dsp/adsprpc.c | 74 ++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/dsp/adsprpc.c b/dsp/adsprpc.c index 08b51bd95d..48f7771937 100644 --- a/dsp/adsprpc.c +++ b/dsp/adsprpc.c @@ -822,54 +822,34 @@ static void fastrpc_remote_buf_list_free(struct fastrpc_file *fl) } 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) { - if (map->flags == ADSP_MMAP_HEAP_ADDR || - map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - struct fastrpc_apps *me = &gfa; - unsigned long irq_flags = 0; + struct fastrpc_file *fl = map->fl; - spin_lock_irqsave(&me->hlock, irq_flags); - 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); - hlist_add_head(&map->hn, &fl->maps); - } } 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 fastrpc_mmap **ppmap) { - struct fastrpc_apps *me = &gfa; struct fastrpc_mmap *match = NULL, *map = NULL; struct hlist_node *n; - unsigned long irq_flags = 0; if ((va + len) < va) return -EFAULT; - if (mflags == ADSP_MMAP_HEAP_ADDR || - 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) { + if (mflags == ADSP_MMAP_DMA_BUFFER) { hlist_for_each_entry_safe(map, n, &fl->maps, hn) { if (map->buf == buf) { if (refs) { @@ -1490,8 +1470,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, struct dma_buf * else fl->mem_snap.nonheap_bufs_size += map->size; spin_unlock(&fl->hlock); - - fastrpc_mmap_add(map); + if ((mflags != ADSP_MMAP_HEAP_ADDR) && + (mflags != ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add(map); *ppmap = map; bail: @@ -4382,6 +4363,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_file *fl, spin_lock_irqsave(&me->hlock, irq_flags); mem->in_use = true; spin_unlock_irqrestore(&me->hlock, irq_flags); + fastrpc_mmap_add_global(mem); } VERIFY(err, mem); if (err) @@ -5244,7 +5226,7 @@ static int fastrpc_mmap_dump(struct fastrpc_mmap *map, struct fastrpc_file *fl, match->size, match->flags, 0); else { pr_err("Cannot communicate with DSP, ADSP is down\n"); - fastrpc_mmap_add(match); + fastrpc_mmap_add_global(match); } } if (err) @@ -5316,7 +5298,7 @@ bail: if (err && match) { if (!locked && fl) mutex_lock(&fl->map_mutex); - fastrpc_mmap_add(match); + fastrpc_mmap_add_global(match); if (!locked && fl) mutex_unlock(&fl->map_mutex); } @@ -5455,7 +5437,11 @@ int fastrpc_internal_munmap(struct fastrpc_file *fl, bail: if (err && map) { 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->internal_map_mutex); @@ -5542,6 +5528,9 @@ int fastrpc_internal_mem_map(struct fastrpc_file *fl, if (err) goto bail; 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: if (err) { ADSPRPC_ERR("failed to map fd %d, len 0x%x, flags %d, map %pK, err %d\n", @@ -5606,7 +5595,11 @@ bail: /* Add back to map list in case of error to unmap on DSP */ if (map) { 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); } } @@ -5680,6 +5673,9 @@ int fastrpc_internal_mmap(struct fastrpc_file *fl, if (err) goto bail; 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; bail: