Skip to content

Commit f5f3138

Browse files
Jianping-LiKomal-Bajaj
authored andcommitted
FROMLIST: misc: fastrpc: fix UAF and kernel panic during cleanup on process abort
When a userspace FastRPC client is abruptly terminated, FastRPC cleanup paths can race with device and session teardown. This results in kernel panics in different release paths: - fastrpc_release() when using remote heap, originating from fastrpc_buf_free() - fastrpc_device_release() when using system heap, originating from fastrpc_free_map() In addition, fastrpc_map_put() may trigger refcount use-after-free due to concurrent cleanup without proper synchronization. The root cause is that buffer and map cleanup paths may access map and buf resources after the associated device or session has already been released. Fix this by: - Introducing mutex protection for map and buf lifetime - Serializing buffer and map cleanup against device teardown - Skipping buffer and map operations when the device is already gone These changes ensure cleanup paths are safe against unexpected process aborts and prevent use-after-free and kernel panic scenarios. Link: https://lore.kernel.org/all/20260427105310.4056-1-jianping.li@oss.qualcomm.com/ Fixes: c68cfb7 ("misc: fastrpc: Add support for context Invoke method") Cc: stable@kernel.org Signed-off-by: Jianping Li <jianping.li@oss.qualcomm.com>
1 parent e0ba718 commit f5f3138

1 file changed

Lines changed: 53 additions & 5 deletions

File tree

drivers/misc/fastrpc.c

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ struct fastrpc_session_ctx {
271271
int sid;
272272
bool used;
273273
bool valid;
274+
bool allocated;
275+
struct mutex mutex;
274276
};
275277

276278
struct fastrpc_soc_data {
@@ -355,9 +357,14 @@ static inline u64 fastrpc_sid_offset(struct fastrpc_channel_ctx *cctx,
355357
static void fastrpc_free_map(struct kref *ref)
356358
{
357359
struct fastrpc_map *map;
360+
struct fastrpc_user *fl;
358361

359362
map = container_of(ref, struct fastrpc_map, refcount);
360363

364+
fl = map->fl;
365+
if (!fl)
366+
return;
367+
361368
if (map->table) {
362369
if (map->attr & FASTRPC_ATTR_SECUREMAP) {
363370
struct qcom_scm_vmperm perm;
@@ -376,10 +383,16 @@ static void fastrpc_free_map(struct kref *ref)
376383
return;
377384
}
378385
}
386+
mutex_lock(&fl->sctx->mutex);
387+
if (!fl->sctx->dev) {
388+
mutex_unlock(&fl->sctx->mutex);
389+
return;
390+
}
379391
dma_buf_unmap_attachment_unlocked(map->attach, map->table,
380392
DMA_BIDIRECTIONAL);
381393
dma_buf_detach(map->buf, map->attach);
382394
dma_buf_put(map->buf);
395+
mutex_unlock(&fl->sctx->mutex);
383396
}
384397

385398
if (map->fl) {
@@ -439,9 +452,18 @@ static void fastrpc_buf_free(struct fastrpc_buf *buf)
439452
if (!buf)
440453
return;
441454

442-
dma_free_coherent(buf->dev, buf->size, buf->virt,
443-
fastrpc_ipa_to_dma_addr(buf->fl->cctx, buf->dma_addr));
444-
kfree(buf);
455+
struct fastrpc_user *fl = buf->fl;
456+
457+
if (!fl)
458+
return;
459+
mutex_lock(&fl->sctx->mutex);
460+
if (fl->sctx->dev) {
461+
dma_free_coherent(buf->dev, buf->size, buf->virt,
462+
fastrpc_ipa_to_dma_addr(buf->fl->cctx,
463+
buf->dma_addr));
464+
kfree(buf);
465+
}
466+
mutex_unlock(&fl->sctx->mutex);
445467
}
446468

447469
static int __fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
@@ -464,8 +486,11 @@ static int __fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
464486
buf->dev = dev;
465487
buf->raddr = 0;
466488

467-
buf->virt = dma_alloc_coherent(dev, buf->size, &buf->dma_addr,
468-
GFP_KERNEL);
489+
mutex_lock(&fl->sctx->mutex);
490+
if (fl->sctx->dev)
491+
buf->virt = dma_alloc_coherent(dev, buf->size, &buf->dma_addr,
492+
GFP_KERNEL);
493+
mutex_unlock(&fl->sctx->mutex);
469494
if (!buf->virt) {
470495
mutex_destroy(&buf->lock);
471496
kfree(buf);
@@ -508,6 +533,10 @@ static void fastrpc_channel_ctx_free(struct kref *ref)
508533
struct fastrpc_channel_ctx *cctx;
509534

510535
cctx = container_of(ref, struct fastrpc_channel_ctx, refcount);
536+
for (int i = 0; i < FASTRPC_MAX_SESSIONS; i++) {
537+
if (cctx->session[i].allocated)
538+
mutex_destroy(&cctx->session[i].mutex);
539+
}
511540

512541
kfree(cctx);
513542
}
@@ -850,19 +879,29 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
850879
goto get_err;
851880
}
852881

882+
mutex_lock(&fl->sctx->mutex);
883+
if (!fl->sctx->dev) {
884+
err = -ENODEV;
885+
mutex_unlock(&fl->sctx->mutex);
886+
goto attach_err;
887+
}
888+
853889
map->attach = dma_buf_attach(map->buf, sess->dev);
854890
if (IS_ERR(map->attach)) {
855891
dev_err(sess->dev, "Failed to attach dmabuf\n");
856892
err = PTR_ERR(map->attach);
893+
mutex_unlock(&fl->sctx->mutex);
857894
goto attach_err;
858895
}
859896

860897
table = dma_buf_map_attachment_unlocked(map->attach, DMA_BIDIRECTIONAL);
861898
if (IS_ERR(table)) {
862899
err = PTR_ERR(table);
900+
mutex_unlock(&fl->sctx->mutex);
863901
goto map_err;
864902
}
865903
map->table = table;
904+
mutex_unlock(&fl->sctx->mutex);
866905

867906
if (attr & FASTRPC_ATTR_SECUREMAP)
868907
map->dma_addr = sg_phys(map->table->sgl);
@@ -2350,6 +2389,8 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
23502389
sess->used = false;
23512390
sess->valid = true;
23522391
sess->dev = dev;
2392+
mutex_init(&sess->mutex);
2393+
sess->allocated = true;
23532394
dev_set_drvdata(dev, sess);
23542395

23552396
if (cctx->domain_id == CDSP_DOMAIN_ID)
@@ -2366,6 +2407,8 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
23662407
break;
23672408
dup_sess = &cctx->session[cctx->sesscount++];
23682409
memcpy(dup_sess, sess, sizeof(*dup_sess));
2410+
mutex_init(&dup_sess->mutex);
2411+
dup_sess->allocated = true;
23692412
}
23702413
}
23712414
spin_unlock_irqrestore(&cctx->lock, flags);
@@ -2388,6 +2431,11 @@ static void fastrpc_cb_remove(struct platform_device *pdev)
23882431
spin_lock_irqsave(&cctx->lock, flags);
23892432
for (i = 0; i < FASTRPC_MAX_SESSIONS; i++) {
23902433
if (cctx->session[i].sid == sess->sid) {
2434+
spin_unlock_irqrestore(&cctx->lock, flags);
2435+
mutex_lock(&cctx->session[i].mutex);
2436+
cctx->session[i].dev = NULL;
2437+
mutex_unlock(&cctx->session[i].mutex);
2438+
spin_lock_irqsave(&cctx->lock, flags);
23912439
cctx->session[i].valid = false;
23922440
cctx->sesscount--;
23932441
}

0 commit comments

Comments
 (0)