Skip to content

Commit 14e526a

Browse files
author
Anandu Krishnan E
committed
FROMLIST: misc: fastrpc: Add reference counting for fastrpc_user structure
Add reference counting using kref to the fastrpc_user structure to prevent use-after-free issues when contexts are freed from workqueue after device release. The issue occurs when fastrpc_device_release() frees the user structure while invoke contexts are still pending in the workqueue. When the workqueue later calls fastrpc_context_free(), it attempts to access buf->fl->cctx in fastrpc_buf_free(), leading to a use-after-free: pc : fastrpc_buf_free+0x38/0x80 [fastrpc] lr : fastrpc_context_free+0xa8/0x1b0 [fastrpc] ... fastrpc_context_free+0xa8/0x1b0 [fastrpc] fastrpc_context_put_wq+0x78/0xa0 [fastrpc] process_one_work+0x180/0x450 worker_thread+0x26c/0x388 Implement proper reference counting to fix this: - Initialize kref in fastrpc_device_open() - Take a reference in fastrpc_context_alloc() for each context - Release the reference in fastrpc_context_free() when context is freed - Release the initial reference in fastrpc_device_release() This ensures the user structure remains valid as long as there are contexts holding references to it, preventing the race condition. Link: https://lore.kernel.org/all/20260226151121.818852-1-anandu.e@oss.qualcomm.com/ Signed-off-by: Anandu Krishnan E <anandu.e@oss.qualcomm.com>
1 parent 1cefa86 commit 14e526a

1 file changed

Lines changed: 31 additions & 4 deletions

File tree

drivers/misc/fastrpc.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,8 @@ struct fastrpc_user {
327327
spinlock_t lock;
328328
/* lock for allocations */
329329
struct mutex mutex;
330+
/* Reference count */
331+
struct kref refcount;
330332
};
331333

332334
static void fastrpc_free_map(struct kref *ref)
@@ -495,15 +497,36 @@ static void fastrpc_channel_ctx_put(struct fastrpc_channel_ctx *cctx)
495497
kref_put(&cctx->refcount, fastrpc_channel_ctx_free);
496498
}
497499

500+
static void fastrpc_user_free(struct kref *ref)
501+
{
502+
struct fastrpc_user *fl = container_of(ref, struct fastrpc_user, refcount);
503+
504+
fastrpc_channel_ctx_put(fl->cctx);
505+
mutex_destroy(&fl->mutex);
506+
kfree(fl);
507+
}
508+
509+
static void fastrpc_user_get(struct fastrpc_user *fl)
510+
{
511+
kref_get(&fl->refcount);
512+
}
513+
514+
static void fastrpc_user_put(struct fastrpc_user *fl)
515+
{
516+
kref_put(&fl->refcount, fastrpc_user_free);
517+
}
518+
498519
static void fastrpc_context_free(struct kref *ref)
499520
{
500521
struct fastrpc_invoke_ctx *ctx;
501522
struct fastrpc_channel_ctx *cctx;
523+
struct fastrpc_user *fl;
502524
unsigned long flags;
503525
int i;
504526

505527
ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount);
506528
cctx = ctx->cctx;
529+
fl = ctx->fl;
507530

508531
for (i = 0; i < ctx->nbufs; i++)
509532
fastrpc_map_put(ctx->maps[i]);
@@ -519,6 +542,8 @@ static void fastrpc_context_free(struct kref *ref)
519542
kfree(ctx->olaps);
520543
kfree(ctx);
521544

545+
/* Release the reference taken in fastrpc_context_alloc() */
546+
fastrpc_user_put(fl);
522547
fastrpc_channel_ctx_put(cctx);
523548
}
524549

@@ -628,6 +653,8 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
628653

629654
/* Released in fastrpc_context_put() */
630655
fastrpc_channel_ctx_get(cctx);
656+
/* Take a reference to user, released in fastrpc_context_free() */
657+
fastrpc_user_get(user);
631658

632659
ctx->sc = sc;
633660
ctx->retval = -1;
@@ -658,6 +685,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
658685
spin_lock(&user->lock);
659686
list_del(&ctx->node);
660687
spin_unlock(&user->lock);
688+
fastrpc_user_put(user);
661689
fastrpc_channel_ctx_put(cctx);
662690
kfree(ctx->maps);
663691
kfree(ctx->olaps);
@@ -1675,11 +1703,9 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
16751703
}
16761704

16771705
fastrpc_session_free(cctx, fl->sctx);
1678-
fastrpc_channel_ctx_put(cctx);
1679-
1680-
mutex_destroy(&fl->mutex);
1681-
kfree(fl);
16821706
file->private_data = NULL;
1707+
/* Release the reference taken in fastrpc_device_open */
1708+
fastrpc_user_put(fl);
16831709

16841710
return 0;
16851711
}
@@ -1723,6 +1749,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
17231749
spin_lock_irqsave(&cctx->lock, flags);
17241750
list_add_tail(&fl->user, &cctx->users);
17251751
spin_unlock_irqrestore(&cctx->lock, flags);
1752+
kref_init(&fl->refcount);
17261753

17271754
return 0;
17281755
}

0 commit comments

Comments
 (0)