dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Jianping Li" <jianping.li@oss.qualcomm.com>
Cc: dri-devel@lists.freedesktop.org, media-ci@linuxtv.org
Subject: Re: [PATCH v3] misc: fastrpc: avoid duplicate DMA mappings in fastrpc_create_maps()
Date: Wed, 05 Aug 2026 06:22:52 +0000	[thread overview]
Message-ID: <20260805062253.4D0481F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260805060940.41414-1-jianping.li@oss.qualcomm.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [Critical] Sharing DMA handle maps without taking a reference allows one invocation to unmap the memory while a concurrent invocation is still actively using it on the DSP, leading to IOMMU faults.
- [High] A Time-Of-Check to Time-Of-Use (TOCTOU) race condition in `fastrpc_get_args()` allows a concurrent thread to free a borrowed DMA handle map, leading to a Host-Side Use-After-Free.
- [High] A lockless Read-Modify-Write sequence on `mmap->flags` in `fastrpc_put_args()` creates a data race that can be exploited to double-free a DMA handle map.

Pre-existing issues:
- [High] DMA handle maps created during argument processing are permanently leaked if the fastrpc invocation fails on error paths or is interrupted by a signal.
--

--- Patch [1]: [PATCH v3] misc: fastrpc: avoid duplicate DMA mappings in fastrpc_create_maps() ---
commit 518577268f37fc91e27676af4609f0c0fa3363fc
Author: Jianping Li <jianping.li@oss.qualcomm.com>

misc: fastrpc: avoid duplicate DMA mappings in fastrpc_create_maps()

This patch changes DMA handle mappings to not take an extra reference
count and tags them with FASTRPC_MAP_DMA_HANDLE. It re-validates the map in
fastrpc_get_args() and modifies fastrpc_put_args() to only release maps
flagged as FASTRPC_MAP_DMA_HANDLE to avoid duplicate mappings.

Patch [v2]: https://lore.kernel.org/all/20260716113254.570-1-jianping.li@oss.qualcomm.com/

> diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
> index f3a49384586d1..59bf33cbed5af 100644
> --- a/drivers/misc/fastrpc.c
> +++ b/drivers/misc/fastrpc.c
> [ ... ]
> @@ -999,23 +1001,25 @@ static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx)
>  	int i, err;
>  
>  	for (i = 0; i < ctx->nscalars; ++i) {
> +		bool take_ref = i < ctx->nbufs;

[Severity: Critical]
By setting take_ref to false for DMA handles, does this allow concurrent
invocations to share a map without incrementing its reference count?

If one invocation finishes and drops the only reference in fastrpc_put_args(),
won't the SMMU mapping be torn down while another concurrent invocation is
still actively using it on the DSP?

> +		int mflags = 0;
>  
>  		if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1 ||
>  		    ctx->args[i].length == 0)
>  			continue;
>  
> -		if (i < ctx->nbufs)
> -			err = fastrpc_map_create(ctx->fl, ctx->args[i].fd,
> -				 ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]);
> -		else
> -			err = fastrpc_map_attach(ctx->fl, ctx->args[i].fd,
> -				 ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]);
> +		/* Set the DMA handle mapping flag for DMA handles */
> +		if (i >= ctx->nbufs)
> +			mflags = FASTRPC_MAP_DMA_HANDLE;
> +
> +		err = fastrpc_map_create(ctx->fl, ctx->args[i].fd, ctx->args[i].length,
> +					 ctx->args[i].attr, &ctx->maps[i], take_ref, mflags);

[Severity: High]
This is a pre-existing issue, but does this code permanently leak DMA
handles if an error occurs after map creation?

If an error happens or a signal interrupts the process, the cleanup path
fastrpc_context_free() intentionally omits freeing maps where
i >= ctx->nbufs:

drivers/misc/fastrpc.c:fastrpc_context_free() {
	...
	for (i = 0; i < ctx->nbufs; i++)
		fastrpc_map_put(ctx->maps[i]);
	...
}

Can an unprivileged user intentionally provide invalid arguments (e.g., bad
payload size) to trigger a failure after map creation, causing an unbounded
memory leak of orphaned DMA handles?

>  		if (err) {
>  			dev_err(dev, "Error Creating map %d\n", err);
>  			return -EINVAL;
>  		}
> -
>  	}
> +
>  	return 0;
>  }
> [ ... ]
> @@ -1143,6 +1147,16 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
>  		list[i].num = ctx->args[i].length ? 1 : 0;
>  		list[i].pgidx = i;
>  		if (ctx->maps[i]) {
> +			/* It is possible that map is created with
> +			 * mflags FASTRPC_MAP_DMA_HANDLE and take_ref
> +			 * is false. Check if map still exists or is
> +			 * being freed as take_ref is false
> +			 */
> +			if (fastrpc_map_lookup(ctx->fl, ctx->args[i].fd,
> +					       &ctx->maps[i], false)) {
> +				ctx->maps[i] = NULL;
> +				return -EINVAL;
> +			}
>  			pages[i].addr = ctx->maps[i]->dma_addr;

[Severity: High]
Is there a race condition between looking up the map and dereferencing it?

Since fastrpc_map_lookup() is called with take_ref = false, it locklessly
returns a pointer to the shared map without holding a reference. Could a
concurrent thread finish its invocation and free this shared map before
pages[i].addr = ctx->maps[i]->dma_addr is evaluated, resulting in a host-side
use-after-free?

> +			pages[i].size = ctx->maps[i]->size;
>  		}
> [ ... ]
> @@ -1199,8 +1213,17 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
>  	for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
>  		if (!fdlist[i])
>  			break;
> -		if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
> +		/*
> +		 * DMA handle maps are released when the DSP returns the corresponding fd in
> +		 * fdlist. The DSP is expected to return a specific fd only once in fdlist,
> +		 * so no two fastrpc_put_args() paths should clear the DMA_HANDLE flag for
> +		 * the same map concurrently.
> +		 */
> +		if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false) &&
> +		    mmap->flags == FASTRPC_MAP_DMA_HANDLE) {
> +			mmap->flags = 0;
>  			fastrpc_map_put(mmap);
> +		}

[Severity: High]
Does the lockless check of mmap->flags allow a double-free if concurrent
invocations share the same fd?

If two concurrent threads from the same user process share the same DMA
handle fd, they share the same map object. When both invocations finish, they
could execute fastrpc_put_args() concurrently.

If they reach this check at the same time, couldn't they both evaluate
mmap->flags == FASTRPC_MAP_DMA_HANDLE as true, clear the flag, and call
fastrpc_map_put() twice on the same map?

>  	}
>  
>  	return ret;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805060940.41414-1-jianping.li@oss.qualcomm.com?part=1

  reply	other threads:[~2026-08-05  6:22 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-05  6:09 [PATCH v3] misc: fastrpc: avoid duplicate DMA mappings in fastrpc_create_maps() Jianping Li
2026-08-05  6:22 ` sashiko-bot [this message]
2026-08-20  4:30 ` Ekansh Gupta
2026-09-11 11:41 ` Ekansh Gupta

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260805062253.4D0481F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jianping.li@oss.qualcomm.com \
    --cc=media-ci@linuxtv.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox