From: Claude Code Review Bot <claude-review@example.com>
To: dri-devel-reviews@example.com
Subject: Claude review: misc: fastrpc: fix UAF and kernel panic during cleanup on process abort
Date: Tue, 28 Apr 2026 14:37:42 +1000 [thread overview]
Message-ID: <review-patch1-20260427105310.4056-1-jianping.li@oss.qualcomm.com> (raw)
In-Reply-To: <20260427105310.4056-1-jianping.li@oss.qualcomm.com>
Patch Review
**Critical: Won't compile — `buf->phys` and `FASTRPC_PHYS` don't exist**
The `fastrpc_buf` struct (line 192) has a field `dma_addr` of type `dma_addr_t`, but the patch introduces references to a nonexistent `buf->phys` field and an undefined `FASTRPC_PHYS` macro:
In `__fastrpc_buf_alloc`:
```c
buf->virt = dma_alloc_coherent(dev, buf->size, (dma_addr_t *)&buf->phys, GFP_KERNEL);
```
In `fastrpc_buf_free`:
```c
dma_free_coherent(buf->dev, buf->size, buf->virt,
FASTRPC_PHYS(buf->phys));
```
Neither `buf->phys` nor `FASTRPC_PHYS` are defined anywhere. The original code correctly uses `buf->dma_addr` and calls `fastrpc_ipa_to_dma_addr()` to extract the SMMU physical address. This is a clear build failure. It appears the patch was developed against an out-of-tree or vendor kernel with a different `fastrpc_buf` definition.
**Bug: Memory leak in `fastrpc_buf_free` when device is gone**
```c
static void fastrpc_buf_free(struct fastrpc_buf *buf)
{
...
mutex_lock(&fl->sctx->mutex);
if (fl->sctx->dev) {
dma_free_coherent(buf->dev, buf->size, buf->virt,
FASTRPC_PHYS(buf->phys));
kfree(buf);
}
mutex_unlock(&fl->sctx->mutex);
}
```
When `fl->sctx->dev` is NULL, `kfree(buf)` is never called. The `buf` allocation is leaked. The DMA memory may be reasonably left alone (the device is gone), but the `struct fastrpc_buf` itself must still be freed. `kfree(buf)` should be moved outside the `if` block.
**Bug: Resource leak in `fastrpc_free_map` when device is gone**
```c
mutex_lock(&fl->sctx->mutex);
if (!fl->sctx->dev) {
mutex_unlock(&fl->sctx->mutex);
return;
}
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);
```
When `fl->sctx->dev` is NULL, the function returns early without: (1) putting the dma_buf reference (`dma_buf_put`), (2) removing the map from the user's list, or (3) freeing the map struct via `kfree(map)`. These happen later in the function at lines 376–383, but the early return skips them. This will leak both the `fastrpc_map` and hold dma_buf references indefinitely. The early return should jump past the DMA operations but still execute the list removal and kfree.
**Issue: `fastrpc_cb_remove` drops and re-acquires spinlock in a loop**
```c
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);
cctx->session[i].dev = NULL;
mutex_unlock(&cctx->session[i].mutex);
spin_lock_irqsave(&cctx->lock, flags);
cctx->session[i].valid = false;
cctx->sesscount--;
}
}
spin_unlock_irqrestore(&cctx->lock, flags);
```
Dropping the spinlock mid-loop means another thread could modify the session array while the loop is iterating. Since the loop checks `sid` to identify matching sessions, and other code could change session state while the lock is dropped, this introduces a TOCTOU window. Additionally, `sesscount` is modified without consistent lock protection (decremented under the spinlock but after the mutex-protected `dev = NULL` already occurred without it). This pattern is fragile. A cleaner approach would be to collect matching session indices first, then release the spinlock and take each mutex individually.
**Issue: `allocated` flag is redundant**
The new `allocated` boolean tracks whether `mutex_init` was called so that `mutex_destroy` can be called conditionally in `fastrpc_channel_ctx_free`. However, `mutex_destroy` on an uninitialized (zero-filled) mutex is a no-op in production kernels (it's only meaningful with `CONFIG_DEBUG_MUTEXES`). Since `fastrpc_channel_ctx` is allocated with `kzalloc`, the sessions array is zeroed. The `allocated` flag adds complexity without clear benefit. If it's kept, it should at least be set under the spinlock consistently with other session initialization.
**Issue: `memcpy` of session copies the mutex**
```c
dup_sess = &cctx->session[cctx->sesscount++];
memcpy(dup_sess, sess, sizeof(*dup_sess));
mutex_init(&dup_sess->mutex);
dup_sess->allocated = true;
```
The `memcpy` copies the entire `fastrpc_session_ctx` including the now-embedded mutex, then immediately re-initializes it. While the `mutex_init` overwrites the copied mutex data, copying a live mutex is technically undefined behavior and may trigger lockdep warnings with `CONFIG_DEBUG_MUTEXES`. The initialization order should be explicit: copy the relevant fields individually, or at minimum document that the mutex is intentionally re-initialized after the copy.
**Minor: `(dma_addr_t *)&buf->phys` cast**
Even ignoring the wrong field name, casting an address to `(dma_addr_t *)` is a type-punning concern if the underlying field isn't actually `dma_addr_t`. The original code correctly passes `&buf->dma_addr` without a cast.
**Summary**: The patch addresses a real problem (race between cleanup paths and device teardown), but introduces compilation failures (`buf->phys`, `FASTRPC_PHYS`), memory/resource leaks (buf and map not freed when device is gone), and questionable locking patterns. It needs significant rework before it's suitable for merging.
---
Generated by Claude Code Patch Reviewer
prev parent reply other threads:[~2026-04-28 4:37 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-27 10:53 [PATCH] misc: fastrpc: fix UAF and kernel panic during cleanup on process abort Jianping Li
2026-04-28 4:37 ` Claude review: " Claude Code Review Bot
2026-04-28 4:37 ` Claude Code Review 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=review-patch1-20260427105310.4056-1-jianping.li@oss.qualcomm.com \
--to=claude-review@example.com \
--cc=dri-devel-reviews@example.com \
/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