Skip to content

Commit c29b2a8

Browse files
Anandu Krishnan Eekanshibu
authored andcommitted
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 54f1bd4 commit c29b2a8

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
@@ -328,6 +328,8 @@ struct fastrpc_user {
328328
spinlock_t lock;
329329
/* lock for allocations */
330330
struct mutex mutex;
331+
/* Reference count */
332+
struct kref refcount;
331333
};
332334

333335
/* Extract SMMU PA from consolidated IOVA */
@@ -515,15 +517,36 @@ static void fastrpc_channel_ctx_put(struct fastrpc_channel_ctx *cctx)
515517
kref_put(&cctx->refcount, fastrpc_channel_ctx_free);
516518
}
517519

520+
static void fastrpc_user_free(struct kref *ref)
521+
{
522+
struct fastrpc_user *fl = container_of(ref, struct fastrpc_user, refcount);
523+
524+
fastrpc_channel_ctx_put(fl->cctx);
525+
mutex_destroy(&fl->mutex);
526+
kfree(fl);
527+
}
528+
529+
static void fastrpc_user_get(struct fastrpc_user *fl)
530+
{
531+
kref_get(&fl->refcount);
532+
}
533+
534+
static void fastrpc_user_put(struct fastrpc_user *fl)
535+
{
536+
kref_put(&fl->refcount, fastrpc_user_free);
537+
}
538+
518539
static void fastrpc_context_free(struct kref *ref)
519540
{
520541
struct fastrpc_invoke_ctx *ctx;
521542
struct fastrpc_channel_ctx *cctx;
543+
struct fastrpc_user *fl;
522544
unsigned long flags;
523545
int i;
524546

525547
ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount);
526548
cctx = ctx->cctx;
549+
fl = ctx->fl;
527550

528551
for (i = 0; i < ctx->nbufs; i++)
529552
fastrpc_map_put(ctx->maps[i]);
@@ -539,6 +562,8 @@ static void fastrpc_context_free(struct kref *ref)
539562
kfree(ctx->olaps);
540563
kfree(ctx);
541564

565+
/* Release the reference taken in fastrpc_context_alloc() */
566+
fastrpc_user_put(fl);
542567
fastrpc_channel_ctx_put(cctx);
543568
}
544569

@@ -646,6 +671,8 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
646671

647672
/* Released in fastrpc_context_put() */
648673
fastrpc_channel_ctx_get(cctx);
674+
/* Take a reference to user, released in fastrpc_context_free() */
675+
fastrpc_user_get(user);
649676

650677
ctx->sc = sc;
651678
ctx->retval = -1;
@@ -676,6 +703,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
676703
spin_lock(&user->lock);
677704
list_del(&ctx->node);
678705
spin_unlock(&user->lock);
706+
fastrpc_user_put(user);
679707
fastrpc_channel_ctx_put(cctx);
680708
kfree(ctx->maps);
681709
kfree(ctx->olaps);
@@ -1700,11 +1728,9 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
17001728
}
17011729

17021730
fastrpc_session_free(cctx, fl->sctx);
1703-
fastrpc_channel_ctx_put(cctx);
1704-
1705-
mutex_destroy(&fl->mutex);
1706-
kfree(fl);
17071731
file->private_data = NULL;
1732+
/* Release the reference taken in fastrpc_device_open */
1733+
fastrpc_user_put(fl);
17081734

17091735
return 0;
17101736
}
@@ -1748,6 +1774,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
17481774
spin_lock_irqsave(&cctx->lock, flags);
17491775
list_add_tail(&fl->user, &cctx->users);
17501776
spin_unlock_irqrestore(&cctx->lock, flags);
1777+
kref_init(&fl->refcount);
17511778

17521779
return 0;
17531780
}

0 commit comments

Comments
 (0)