FASTRPC_IOCTL_MEM_UNMAP found a map under fl->lock, then dropped the lock.

It used that map until the DSP completed the unmap.

A second unmap can find the same map and race to fastrpc_map_put().

That can cause a use-after-free or double list deletion.

Remove the map from the lookup list before the remote unmap.

Reinsert it if the remote side reports an error.

Signed-off-by: Yousef Alhouseen <[email protected]>
---
 drivers/misc/fastrpc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 6a5239b1c..6ced210ca 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -365,7 +365,8 @@ static void fastrpc_free_map(struct kref *ref)
 
        if (map->fl) {
                spin_lock(&map->fl->lock);
-               list_del(&map->node);
+               if (!list_empty(&map->node))
+                       list_del_init(&map->node);
                spin_unlock(&map->fl->lock);
                map->fl = NULL;
        }
@@ -2064,6 +2065,7 @@ static int fastrpc_req_mem_unmap_impl(struct fastrpc_user 
*fl, struct fastrpc_me
        list_for_each_entry_safe(iter, m, &fl->maps, node) {
                if ((req->fd < 0 || iter->fd == req->fd) && (iter->raddr == 
req->vaddr)) {
                        map = iter;
+                       list_del_init(&map->node);
                        break;
                }
        }
@@ -2088,6 +2090,9 @@ static int fastrpc_req_mem_unmap_impl(struct fastrpc_user 
*fl, struct fastrpc_me
                                      &args[0]);
        if (err) {
                dev_err(dev, "unmmap\tpt fd = %d, 0x%09llx error\n",  map->fd, 
map->raddr);
+               spin_lock(&fl->lock);
+               list_add_tail(&map->node, &fl->maps);
+               spin_unlock(&fl->lock);
                return err;
        }
        fastrpc_map_put(map);
-- 
2.54.0

Reply via email to