From: sashiko-bot@kernel.org
To: "Jianping Li" <jianping.li@oss.qualcomm.com>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v2] misc: fastrpc: fix UAF and kernel panic during cleanup on process abort
Date: Tue, 30 Jun 2026 06:46:51 +0000 [thread overview]
Message-ID: <20260630064651.977561F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260630063409.475-1-jianping.li@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [Critical] `fastrpc_cb_remove` locks uninitialized mutexes when matching unallocated sessions.
- [High] The patch intentionally leaks DMA allocations, dmabufs, and tracking structures to avoid a use-after-free on device unbind.
- [High] The error path in `fastrpc_map_attach` calls `dma_buf_detach` without holding `fl->sctx->mutex`, circumventing the synchronization intended to prevent use-after-free.
Pre-existing issues:
- [High] The error handling path in `fastrpc_map_attach` triggers double-detach and double-put of dmabufs.
- [High] Preexisting memory leak in `fastrpc_free_map` during secure memory assignment failure.
- [High] Array overwrite and race condition vulnerability due to blind decrement of `sesscount` in `fastrpc_cb_remove` without array compaction.
- [High] Probe failure leaves a dangling device pointer in the active session array.
--
commit 70c262510b69042fa36e0aa92b5ee69b7cc10c62
Author: Jianping Li <jianping.li@oss.qualcomm.com>
misc: fastrpc: fix UAF and kernel panic during cleanup on process abort
This commit introduces mutex protection for map and buffer lifetimes to fix
use-after-free issues when a FastRPC client is aborted. It serializes cleanup
against device teardown and skips operations when the device is gone.
> diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
> --- a/drivers/misc/fastrpc.c
> +++ b/drivers/misc/fastrpc.c
> @@ -335,9 +337,14 @@ static void fastrpc_free_map(struct kref *ref)
[ ... ]
> if (map->attr & FASTRPC_ATTR_SECUREMAP) {
> struct qcom_scm_vmperm perm;
[ ... ]
> err = qcom_scm_assign_mem(map->dma_addr, map->len,
> &src_perms, &perm, 1);
> if (err) {
> dev_err(map->fl->sctx->dev,
> "Failed to assign memory dma_addr %pad size 0x%llx err %d\n",
> &map->dma_addr, map->len, err);
> return;
[Severity: High]
This is a pre-existing issue, but does this early return completely abandon
the release sequence?
If qcom_scm_assign_mem() fails, it looks like this returns immediately,
bypassing all subsequent teardown logic and permanently leaking the map on the
linked list along with the dmabuf references.
> }
> }
> + mutex_lock(&fl->sctx->mutex);
> + if (!fl->sctx->dev) {
> + mutex_unlock(&fl->sctx->mutex);
> + return;
[Severity: High]
Can this early return permanently leak the map and dmabuf?
If a process terminates after a device unbinds, fastrpc_cb_remove() sets dev
to NULL. When fastrpc_free_map() runs, it hits this early return and
completely bypasses the mandatory resource deallocation such as kfree(),
list_del(), and dma_buf_put().
> + }
> dma_buf_unmap_attachment_unlocked(map->attach, map->table,
> DMA_BIDIRECTIONAL);
> dma_buf_detach(map->buf, map->attach);
> dma_buf_put(map->buf);
> + mutex_unlock(&fl->sctx->mutex);
> }
[ ... ]
> @@ -422,9 +435,18 @@ static void fastrpc_buf_free(struct fastrpc_buf *buf)
> struct fastrpc_user *fl = buf->fl;
>
> if (!fl)
> return;
> + mutex_lock(&fl->sctx->mutex);
> + if (fl->sctx->dev) {
> + dma_free_coherent(buf->dev, buf->size, buf->virt,
> + fastrpc_ipa_to_dma_addr(buf->fl->cctx,
> + buf->dma_addr));
> + kfree(buf);
> + }
> + mutex_unlock(&fl->sctx->mutex);
[Severity: High]
Could the absence of an else-branch permanently leak the buffer memory?
Similar to fastrpc_free_map(), if the device is gone, skipping the
dma_free_coherent() and kfree() leaves the memory permanently leaked
instead of safely handling the cleanup.
> }
[ ... ]
> @@ -855,19 +884,28 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
[ ... ]
> table = dma_buf_map_attachment_unlocked(map->attach, DMA_BIDIRECTIONAL);
> if (IS_ERR(table)) {
> err = PTR_ERR(table);
> + mutex_unlock(&fl->sctx->mutex);
> goto map_err;
[Severity: High]
This is a pre-existing issue, but does jumping to map_err cause a double
detach and put of the dmabuf?
If we take this error path after map->table has been assigned, we execute:
fastrpc_map_attach()
goto map_err;
map_err:
dma_buf_detach(map->buf, map->attach);
...
fastrpc_map_put(map);
Because map->table is non-NULL, the kref release function fastrpc_free_map()
will re-execute dma_buf_detach() and dma_buf_put() on the identical
structures.
[Severity: High]
Would unlocking the mutex here expose the error path to a use-after-free?
By explicitly unlocking sctx->mutex before jumping to map_err, dma_buf_detach()
is called completely unprotected. A concurrent fastrpc_cb_remove() can run
between the unlock and detach, clearing the device and leading to a
use-after-free in dma_buf_detach() when it accesses attach->dev.
> }
> map->table = table;
> + mutex_unlock(&fl->sctx->mutex);
[ ... ]
> @@ -2246,6 +2284,8 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
[ ... ]
> sess = &cctx->session[cctx->sesscount++];
> sess->used = false;
> sess->valid = true;
> sess->dev = dev;
> + mutex_init(&sess->mutex);
> + sess->allocated = true;
[Severity: High]
This is a pre-existing issue, but does appending to sesscount here
blindly overwrite a trailing active session?
When fastrpc_cb_remove() executes, it decrements sesscount blindly without
shifting downstream array elements to close the gap. A subsequent probe
uses the decremented sesscount as an append index, corrupting the active
session.
With this patch, the newly added mutex_init() will now reinitialize an
in-use lock on that overwritten session.
> dev_set_drvdata(dev, sess);
> sess->sid = sid;
[ ... ]
> @@ -2260,6 +2300,8 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
[ ... ]
> dup_sess = &cctx->session[cctx->sesscount++];
> memcpy(dup_sess, sess, sizeof(*dup_sess));
> + mutex_init(&dup_sess->mutex);
> + dup_sess->allocated = true;
> }
> }
> spin_unlock_irqrestore(&cctx->lock, flags);
[Severity: High]
This isn't a bug introduced by this patch, but does a probe failure
leave a dangling device pointer in the active session array?
Just below this hunk, dma_set_mask() is called. If that call fails, it
returns an error and aborts the probe. The driver core will destroy the
device, but FastRPC has already permanently registered the dangling dev
pointer into its session array.
> @@ -2282,6 +2324,11 @@ static void fastrpc_cb_remove(struct platform_device *pdev)
> spin_lock_irqsave(&cctx->lock, flags);
> for (i = 0; i < FASTRPC_MAX_SESSIONS; i++) {
> if (cctx->session[i].sid == sess->sid) {
> + spin_unlock_irqrestore(&cctx->lock, flags);
> + mutex_lock(&cctx->session[i].mutex);
[Severity: Critical]
Will this loop lock uninitialized mutexes when matching unallocated sessions?
The elements beyond sesscount in cctx->session are zero-initialized.
If sess->sid is 0 (the default if a DT lacks a 'reg' property), the loop
condition cctx->session[i].sid == sess->sid will match all unused slots.
This attempts to acquire an uninitialized, all-zero mutex, which might
lead to a panic or lockdep crash. Should this loop check
cctx->session[i].allocated?
> + cctx->session[i].dev = NULL;
> + mutex_unlock(&cctx->session[i].mutex);
> + spin_lock_irqsave(&cctx->lock, flags);
> cctx->session[i].valid = false;
> cctx->sesscount--;
[Severity: High]
This is a pre-existing issue, but does decrementing sesscount without
moving elements create a discrepancy between the index and active entries?
As mentioned earlier, this blind decrement leaves a gap in the array that
leads to state corruption during the next probe.
> }
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260630063409.475-1-jianping.li@oss.qualcomm.com?part=1
prev parent reply other threads:[~2026-06-30 6:46 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-30 6:34 [PATCH v2] misc: fastrpc: fix UAF and kernel panic during cleanup on process abort Jianping Li
2026-06-30 6:46 ` sashiko-bot [this message]
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=20260630064651.977561F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=jianping.li@oss.qualcomm.com \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.