Skip to content

Commit 97a6764

Browse files
Jianping-Liquic-vkatoch
authored andcommitted
FROMLIST: misc: fastrpc: Allocate entire reserved memory for Audio PD in probe
Allocating and freeing Audio PD memory from userspace is unsafe because the kernel cannot reliably determine when the DSP has finished using the memory. Userspace may free buffers while they are still in use by the DSP, and remote free requests cannot be safely trusted. Additionally, the current implementation allows userspace to repeatedly grow the Audio PD heap, but does not support shrinking it. This can lead to unbounded memory usage over time, effectively causing a memory leak. Fix this by allocating the entire Audio PD reserved-memory region during rpmsg probe and tying its lifetime to the rpmsg channel. This removes userspace-controlled alloc/free and ensures that memory is reclaimed only when the DSP process is torn down. Link: https://lore.kernel.org/all/20260526111124.515-5-jianping.li@oss.qualcomm.com/ Fixes: 0871561 ("misc: fastrpc: Add support for audiopd") Cc: stable@kernel.org Signed-off-by: Jianping Li <jianping.li@oss.qualcomm.com> Signed-off-by: Vinayak Katoch <vkatoch@qti.qualcomm.com>
1 parent 3845976 commit 97a6764

1 file changed

Lines changed: 50 additions & 53 deletions

File tree

drivers/misc/fastrpc.c

Lines changed: 50 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ struct fastrpc_channel_ctx {
294294
struct kref refcount;
295295
/* Flag if dsp attributes are cached */
296296
bool valid_attributes;
297+
/* Flag if audio PD init mem was allocated */
298+
bool audio_init_mem;
297299
u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES];
298300
struct fastrpc_device *secure_fdevice;
299301
struct fastrpc_device *fdevice;
@@ -1459,15 +1461,16 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
14591461
struct fastrpc_init_create_static init;
14601462
struct fastrpc_invoke_args *args;
14611463
struct fastrpc_phy_page pages[1];
1464+
struct fastrpc_channel_ctx *cctx = fl->cctx;
14621465
char *name;
14631466
int err;
1464-
bool scm_done = false;
14651467
struct {
14661468
int client_id;
14671469
u32 namelen;
14681470
u32 pageslen;
14691471
} inbuf;
14701472
u32 sc;
1473+
unsigned long flags;
14711474

14721475
if (!fl->cctx->remote_heap ||
14731476
!fl->cctx->remote_heap->dma_addr ||
@@ -1498,31 +1501,6 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
14981501
inbuf.client_id = fl->client_id;
14991502
inbuf.namelen = init.namelen;
15001503
inbuf.pageslen = 0;
1501-
if (!fl->cctx->remote_heap) {
1502-
err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
1503-
&fl->cctx->remote_heap);
1504-
if (err)
1505-
goto err_name;
1506-
1507-
/* Map if we have any heap VMIDs associated with this ADSP Static Process. */
1508-
if (fl->cctx->vmcount) {
1509-
u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
1510-
1511-
err = qcom_scm_assign_mem(fl->cctx->remote_heap->dma_addr,
1512-
(u64)fl->cctx->remote_heap->size,
1513-
&src_perms,
1514-
fl->cctx->vmperms, fl->cctx->vmcount);
1515-
if (err) {
1516-
dev_err(fl->sctx->dev,
1517-
"Failed to assign memory with dma_addr %pad size 0x%llx err %d\n",
1518-
&fl->cctx->remote_heap->dma_addr,
1519-
fl->cctx->remote_heap->size, err);
1520-
goto err_map;
1521-
}
1522-
scm_done = true;
1523-
inbuf.pageslen = 1;
1524-
}
1525-
}
15261504

15271505
fl->pd = USER_PD;
15281506

@@ -1534,8 +1512,24 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
15341512
args[1].length = inbuf.namelen;
15351513
args[1].fd = -1;
15361514

1537-
pages[0].addr = fl->cctx->remote_heap->dma_addr;
1538-
pages[0].size = fl->cctx->remote_heap->size;
1515+
spin_lock_irqsave(&cctx->lock, flags);
1516+
if (!fl->cctx->audio_init_mem) {
1517+
if (!fl->cctx->remote_heap ||
1518+
!fl->cctx->remote_heap->dma_addr ||
1519+
!fl->cctx->remote_heap->size) {
1520+
spin_unlock_irqrestore(&cctx->lock, flags);
1521+
err = -ENOMEM;
1522+
goto err;
1523+
}
1524+
pages[0].addr = fl->cctx->remote_heap->dma_addr;
1525+
pages[0].size = fl->cctx->remote_heap->size;
1526+
fl->cctx->audio_init_mem = true;
1527+
inbuf.pageslen = 1;
1528+
} else {
1529+
pages[0].addr = 0;
1530+
pages[0].size = 0;
1531+
}
1532+
spin_unlock_irqrestore(&cctx->lock, flags);
15391533

15401534
args[2].ptr = (u64)(uintptr_t) pages;
15411535
args[2].length = sizeof(*pages);
@@ -1553,27 +1547,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
15531547

15541548
return 0;
15551549
err_invoke:
1556-
if (fl->cctx->vmcount && scm_done) {
1557-
u64 src_perms = 0;
1558-
struct qcom_scm_vmperm dst_perms;
1559-
u32 i;
1560-
1561-
for (i = 0; i < fl->cctx->vmcount; i++)
1562-
src_perms |= BIT(fl->cctx->vmperms[i].vmid);
1563-
1564-
dst_perms.vmid = QCOM_SCM_VMID_HLOS;
1565-
dst_perms.perm = QCOM_SCM_PERM_RWX;
1566-
err = qcom_scm_assign_mem(fl->cctx->remote_heap->dma_addr,
1567-
(u64)fl->cctx->remote_heap->size,
1568-
&src_perms, &dst_perms, 1);
1569-
if (err)
1570-
dev_err(fl->sctx->dev, "Failed to assign memory dma_addr %pad size 0x%llx err %d\n",
1571-
&fl->cctx->remote_heap->dma_addr, fl->cctx->remote_heap->size, err);
1572-
}
1573-
err_map:
1574-
fastrpc_buf_free(fl->cctx->remote_heap);
1575-
fl->cctx->remote_heap = NULL;
1576-
err_name:
1550+
fl->cctx->audio_init_mem = false;
15771551
kfree(name);
15781552
err:
15791553
kfree(args);
@@ -2594,20 +2568,28 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
25942568
}
25952569
}
25962570

2597-
if (domain_id == SDSP_DOMAIN_ID) {
2571+
if (domain_id == SDSP_DOMAIN_ID || domain_id == ADSP_DOMAIN_ID) {
25982572
struct resource res;
25992573
u64 src_perms;
26002574

26012575
err = of_reserved_mem_region_to_resource(rdev->of_node, 0, &res);
26022576
if (!err) {
2577+
if (domain_id == ADSP_DOMAIN_ID) {
2578+
data->remote_heap =
2579+
kzalloc_obj(*data->remote_heap, GFP_KERNEL);
2580+
if (!data->remote_heap)
2581+
return -ENOMEM;
2582+
2583+
data->remote_heap->dma_addr = res.start;
2584+
data->remote_heap->size = resource_size(&res);
2585+
}
26032586
src_perms = BIT(QCOM_SCM_VMID_HLOS);
26042587

26052588
err = qcom_scm_assign_mem(res.start, resource_size(&res), &src_perms,
26062589
data->vmperms, data->vmcount);
26072590
if (err)
26082591
goto err_free_data;
26092592
}
2610-
26112593
}
26122594

26132595
secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain"));
@@ -2688,6 +2670,7 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
26882670
struct fastrpc_buf *buf, *b;
26892671
struct fastrpc_user *user;
26902672
unsigned long flags;
2673+
int err;
26912674

26922675
/* No invocations past this point */
26932676
spin_lock_irqsave(&cctx->lock, flags);
@@ -2705,8 +2688,22 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
27052688
list_for_each_entry_safe(buf, b, &cctx->invoke_interrupted_mmaps, node)
27062689
list_del(&buf->node);
27072690

2708-
if (cctx->remote_heap)
2709-
fastrpc_buf_free(cctx->remote_heap);
2691+
if (cctx->remote_heap && cctx->vmcount) {
2692+
u64 src_perms = 0;
2693+
struct qcom_scm_vmperm dst_perms;
2694+
2695+
for (u32 i = 0; i < cctx->vmcount; i++)
2696+
src_perms |= BIT(cctx->vmperms[i].vmid);
2697+
2698+
dst_perms.vmid = QCOM_SCM_VMID_HLOS;
2699+
dst_perms.perm = QCOM_SCM_PERM_RWX;
2700+
2701+
err = qcom_scm_assign_mem(cctx->remote_heap->dma_addr,
2702+
cctx->remote_heap->size, &src_perms,
2703+
&dst_perms, 1);
2704+
if (!err)
2705+
kfree(cctx->remote_heap);
2706+
}
27102707

27112708
of_platform_depopulate(&rpdev->dev);
27122709

0 commit comments

Comments
 (0)