Skip to content

Commit 9446fa1

Browse files
abelvesagregkh
authored andcommitted
misc: fastrpc: Fix use-after-free and race in fastrpc_map_find
Currently, there is a race window between the point when the mutex is unlocked in fastrpc_map_lookup and the reference count increasing (fastrpc_map_get) in fastrpc_map_find, which can also lead to use-after-free. So lets merge fastrpc_map_find into fastrpc_map_lookup which allows us to both protect the maps list by also taking the &fl->lock spinlock and the reference count, since the spinlock will be released only after. Add take_ref argument to make this suitable for all callers. Fixes: 8f6c1d8 ("misc: fastrpc: Add fdlist implementation") Cc: stable <stable@kernel.org> Co-developed-by: Ola Jeppsson <ola@snap.com> Signed-off-by: Ola Jeppsson <ola@snap.com> Signed-off-by: Abel Vesa <abel.vesa@linaro.org> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Link: https://lore.kernel.org/r/20221124174941.418450-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 5023adc commit 9446fa1

File tree

1 file changed

+21
-20
lines changed

1 file changed

+21
-20
lines changed

drivers/misc/fastrpc.c

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -351,30 +351,31 @@ static void fastrpc_map_get(struct fastrpc_map *map)
351351

352352

353353
static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
354-
struct fastrpc_map **ppmap)
354+
struct fastrpc_map **ppmap, bool take_ref)
355355
{
356+
struct fastrpc_session_ctx *sess = fl->sctx;
356357
struct fastrpc_map *map = NULL;
358+
int ret = -ENOENT;
357359

358-
mutex_lock(&fl->mutex);
360+
spin_lock(&fl->lock);
359361
list_for_each_entry(map, &fl->maps, node) {
360-
if (map->fd == fd) {
361-
*ppmap = map;
362-
mutex_unlock(&fl->mutex);
363-
return 0;
364-
}
365-
}
366-
mutex_unlock(&fl->mutex);
367-
368-
return -ENOENT;
369-
}
362+
if (map->fd != fd)
363+
continue;
370364

371-
static int fastrpc_map_find(struct fastrpc_user *fl, int fd,
372-
struct fastrpc_map **ppmap)
373-
{
374-
int ret = fastrpc_map_lookup(fl, fd, ppmap);
365+
if (take_ref) {
366+
ret = fastrpc_map_get(map);
367+
if (ret) {
368+
dev_dbg(sess->dev, "%s: Failed to get map fd=%d ret=%d\n",
369+
__func__, fd, ret);
370+
break;
371+
}
372+
}
375373

376-
if (!ret)
377-
fastrpc_map_get(*ppmap);
374+
*ppmap = map;
375+
ret = 0;
376+
break;
377+
}
378+
spin_unlock(&fl->lock);
378379

379380
return ret;
380381
}
@@ -746,7 +747,7 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
746747
struct fastrpc_map *map = NULL;
747748
int err = 0;
748749

749-
if (!fastrpc_map_find(fl, fd, ppmap))
750+
if (!fastrpc_map_lookup(fl, fd, ppmap, true))
750751
return 0;
751752

752753
map = kzalloc(sizeof(*map), GFP_KERNEL);
@@ -1070,7 +1071,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
10701071
for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
10711072
if (!fdlist[i])
10721073
break;
1073-
if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap))
1074+
if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
10741075
fastrpc_map_put(mmap);
10751076
}
10761077

0 commit comments

Comments
 (0)