Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5431f20f authored by Santosh Sakore's avatar Santosh Sakore Committed by Sumangala P
Browse files

msm: adsprpc: 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.

Change-Id: I73c536718f3228b7cbb7a19b76270e0dd3e32bd1
Acked-by: default avatarAbhishek Singh <abhishes@qti.qualcomm.com>
Signed-off-by: default avatarSantosh Sakore <quic_ssakore@quicinc.com>
(cherry picked from commit 6f39d9be)
parent 3f88a820
Loading
Loading
Loading
Loading
+36 −47
Original line number Diff line number Diff line
@@ -751,52 +751,33 @@ static void fastrpc_remote_buf_list_free(struct fastrpc_file *fl)
	} while (free);
}

static void fastrpc_mmap_add(struct fastrpc_mmap *map)
static void fastrpc_mmap_add_global(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;

		spin_lock(&me->hlock);
	spin_lock_irqsave(&me->hlock, irq_flags);
	hlist_add_head(&map->hn, &me->maps);
		spin_unlock(&me->hlock);
	} else {
	spin_unlock_irqrestore(&me->hlock, irq_flags);
}

static void fastrpc_mmap_add(struct fastrpc_mmap *map)
{
	struct fastrpc_file *fl = map->fl;

	hlist_add_head(&map->hn, &fl->maps);
}
}

static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd,
		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;

	if ((va + len) < va)
		return -EOVERFLOW;
	if (mflags == ADSP_MMAP_HEAP_ADDR ||
				 mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
		spin_lock(&me->hlock);
		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(&me->hlock);
						return -ETOOMANYREFS;
					}
					map->refs++;
				}
				match = map;
				break;
			}
		}
		spin_unlock(&me->hlock);
	} else {

	hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
		if (va >= map->va &&
			va + len <= map->va + map->len &&
@@ -810,7 +791,6 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd,
			break;
		}
	}
	}
	if (match) {
		*ppmap = match;
		return 0;
@@ -1173,7 +1153,8 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
		map->va = va;
	}
	map->len = len;

	if ((mflags != ADSP_MMAP_HEAP_ADDR) &&
			(mflags != ADSP_MMAP_REMOTE_HEAP_ADDR))
		fastrpc_mmap_add(map);
	*ppmap = map;

@@ -2787,6 +2768,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
			mutex_unlock(&fl->map_mutex);
			if (err)
				goto bail;
			fastrpc_mmap_add_global(mem);
			phys = mem->phys;
			size = mem->size;
			if (me->channel[fl->cid].rhvm.vmid) {
@@ -3357,7 +3339,7 @@ static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl, int locked)
	me->enable_ramdump = false;
bail:
	if (err && match)
		fastrpc_mmap_add(match);
		fastrpc_mmap_add_global(match);
	return err;
}

@@ -3479,6 +3461,10 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
bail:
	if (err && map) {
		mutex_lock(&fl->map_mutex);
		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);
	}
@@ -3589,6 +3575,9 @@ static 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: