[PATCH] misc: fastrpc: keep invoke copyout state private

From: Yousef Alhouseen

Date: Wed Jun 24 2026 - 14:57:59 EST


fastrpc_put_args() copies output buffers from the DSP-shared metadata
area using the pointer and length stored in rpra[]. The DSP can update
that coherent buffer before the CPU reads it back.

Keep the kernel-owned inline buffer address and original userspace
length in the invoke context, and use that state for output copies. This
prevents remote updates to the metadata from steering kernel reads or
expanding the copyout length.

Signed-off-by: Yousef Alhouseen <alhouseenyousef@xxxxxxxxx>
---
drivers/misc/fastrpc.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 8dd8315d5..c91d5da42 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -247,6 +247,7 @@ struct fastrpc_invoke_ctx {
struct fastrpc_map **maps;
struct fastrpc_buf *buf;
struct fastrpc_invoke_args *args;
+ uintptr_t *buf_pv;
struct fastrpc_buf_overlap *olaps;
struct fastrpc_channel_ctx *cctx;
};
@@ -570,6 +571,7 @@ static void fastrpc_context_free(struct kref *ref)
spin_unlock_irqrestore(&cctx->lock, flags);

kfree(ctx->maps);
+ kfree(ctx->buf_pv);
kfree(ctx->olaps);
kfree(ctx);

@@ -681,9 +683,17 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
kfree(ctx);
return ERR_PTR(-ENOMEM);
}
+ ctx->buf_pv = kzalloc_objs(*ctx->buf_pv, ctx->nscalars);
+ if (!ctx->buf_pv) {
+ kfree(ctx->olaps);
+ kfree(ctx->maps);
+ kfree(ctx);
+ return ERR_PTR(-ENOMEM);
+ }
ctx->args = args;
ret = fastrpc_get_buff_overlaps(ctx);
if (ret) {
+ kfree(ctx->buf_pv);
kfree(ctx->olaps);
kfree(ctx->maps);
kfree(ctx);
@@ -727,6 +737,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
fastrpc_user_put(user);
fastrpc_channel_ctx_put(cctx);
kfree(ctx->maps);
+ kfree(ctx->buf_pv);
kfree(ctx->olaps);
kfree(ctx);

@@ -1136,6 +1147,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
args = args + mlen;
rlen -= mlen;
}
+ ctx->buf_pv[i] = (uintptr_t)rpra[i].buf.pv;

if (i < inbufs && !ctx->maps[i]) {
void *dst = (void *)(uintptr_t)rpra[i].buf.pv;
@@ -1193,9 +1205,9 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,

for (i = inbufs; i < ctx->nbufs; ++i) {
if (!ctx->maps[i]) {
- void *src = (void *)(uintptr_t)rpra[i].buf.pv;
+ void *src = (void *)ctx->buf_pv[i];
void *dst = (void *)(uintptr_t)ctx->args[i].ptr;
- u64 len = rpra[i].buf.len;
+ u64 len = ctx->args[i].length;

if (!kernel) {
if (copy_to_user((void __user *)dst, src, len)) {
--
2.54.0