fastrpc_get_payload_size() accumulates the metadata and inline argument payload sizes before allocating the coherent invoke buffer. User-provided argument ranges can make this accumulator wrap, leaving a buffer smaller than the later serialization expects.
Return an error when the payload size arithmetic overflows or cannot be represented as an allocation size. This prevents an undersized DMA buffer from being used for invoke argument serialization. Signed-off-by: Yousef Alhouseen <[email protected]> --- drivers/misc/fastrpc.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 4eaecee1b..ed0041076 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -997,7 +997,8 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx) return size; } -static u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen) +static int fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen, + u64 *out_size) { u64 size = 0; int oix; @@ -1007,15 +1008,22 @@ static u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen) int i = ctx->olaps[oix].raix; if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1) { + u64 len = ctx->olaps[oix].mend - + ctx->olaps[oix].mstart; if (ctx->olaps[oix].offset == 0) size = ALIGN(size, FASTRPC_ALIGN); - size += (ctx->olaps[oix].mend - ctx->olaps[oix].mstart); + if (check_add_overflow(size, len, &size)) + return -EOVERFLOW; } } - return size; + if (size > SIZE_MAX) + return -EOVERFLOW; + + *out_size = size; + return 0; } static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx) @@ -1068,7 +1076,9 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) inbufs = REMOTE_SCALARS_INBUFS(ctx->sc); metalen = fastrpc_get_meta_size(ctx); - pkt_size = fastrpc_get_payload_size(ctx, metalen); + err = fastrpc_get_payload_size(ctx, metalen, &pkt_size); + if (err) + return err; err = fastrpc_create_maps(ctx); if (err) -- 2.54.0
