]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
misc: fastrpc: fix use-after-free race in fastrpc_map_create
authorZhenghang Xiao <kipreyyy@gmail.com>
Sat, 30 May 2026 20:45:28 +0000 (21:45 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Jun 2026 15:20:51 +0000 (17:20 +0200)
fastrpc_map_lookup returns a raw pointer after releasing fl->lock. The
caller fastrpc_map_create then calls fastrpc_map_get (kref_get_unless_zero)
on this unprotected pointer. A concurrent MEM_UNMAP can free the map
between the lock release and the kref operation, resulting in a
use-after-free on the freed slab object.

Restore the take_ref parameter to fastrpc_map_lookup so the reference
is acquired atomically under fl->lock before the pointer is exposed to
the caller.

Fixes: 10df039834f8 ("misc: fastrpc: Skip reference for DMA handles")
Cc: stable@vger.kernel.org
Signed-off-by: Zhenghang Xiao <kipreyyy@gmail.com>
Signed-off-by: Srinivas Kandagatla <srini@kernel.org>
Link: https://patch.msgid.link/20260530204528.116920-5-srini@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/fastrpc.c

index 47cf3d21b51db86a314a21f0f2f0a7e2bf8aa7d6..f3a49384586d1f07c6298811971ba811e9779c29 100644 (file)
@@ -388,7 +388,7 @@ static int fastrpc_map_get(struct fastrpc_map *map)
 
 
 static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
-                           struct fastrpc_map **ppmap)
+                           struct fastrpc_map **ppmap, bool take_ref)
 {
        struct fastrpc_map *map = NULL;
        struct dma_buf *buf;
@@ -403,6 +403,12 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
                if (map->fd != fd || map->buf != buf)
                        continue;
 
+               if (take_ref) {
+                       ret = fastrpc_map_get(map);
+                       if (ret)
+                               break;
+               }
+
                *ppmap = map;
                ret = 0;
                break;
@@ -920,19 +926,10 @@ get_err:
 static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
                              u64 len, u32 attr, struct fastrpc_map **ppmap)
 {
-       struct fastrpc_session_ctx *sess = fl->sctx;
-       int err = 0;
-
-       if (!fastrpc_map_lookup(fl, fd, ppmap)) {
-               if (!fastrpc_map_get(*ppmap))
-                       return 0;
-               dev_dbg(sess->dev, "%s: Failed to get map fd=%d\n",
-                       __func__, fd);
-       }
-
-       err = fastrpc_map_attach(fl, fd, len, attr, ppmap);
+       if (!fastrpc_map_lookup(fl, fd, ppmap, true))
+               return 0;
 
-       return err;
+       return fastrpc_map_attach(fl, fd, len, attr, ppmap);
 }
 
 /*
@@ -1202,7 +1199,7 @@ cleanup_fdlist:
        for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
                if (!fdlist[i])
                        break;
-               if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap))
+               if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
                        fastrpc_map_put(mmap);
        }