Re: [PATCH v2 62/64] dmaengine: hidma: defer callbacks via channel BH
[email protected] Mon, 27 Jul 2026 21:25:43 +0000
| Newsgroups | org.kernel.vger.dmaengine |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: New issues: - [Critical] The per-channel bottom-half (BH) is cancelled too late during driver unbind, allowing it to execute after the hardware context is destroyed and dereference a NULL pointer. - [High] Missing synchronization and cancellation of BH during channel termination leads to use-after-free and memory leaks. Pre-existing issues: - [Critical] List manipulation without holding the channel lock in `hidma_terminate_channel` causes list corruption and data races. - [High] Sleeping function called in atomic context and unsafe PM hardware access. - [High] Unbalanced pm_runtime usage counter causing premature device suspension. - [High] Invalid pointer dereference due to missing list emptiness check in `hidma_callback`. -- --- Patch [62]: [PATCH v2 62/64] dmaengine: hidma: defer callbacks via channel BH --- commit 3c9c3e0127e064313b46165b6ad21a91d6575ed1 Author: Allen Pais <[email protected]> Subject: dmaengine: hidma: defer callbacks via channel BH Move descriptor callback processing out of the low-level completion path and schedule it through per-channel BH work. Drain that work while freeing channels so callbacks cannot outlive channel storage. > diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c > index c939635be21d2..1f875a499ab3f 100644 > --- a/drivers/dma/qcom/hidma.c > +++ b/drivers/dma/qcom/hidma.c > @@ -90,7 +90,13 @@ static inline struct hidma_chan *to_hidma_chan(struct dma_chan *dmach) > > static void hidma_free(struct hidma_dev *dmadev) > { > - INIT_LIST_HEAD(&dmadev->ddev.channels); > + struct hidma_chan *mchan, *next; > + > + list_for_each_entry_safe(mchan, next, &dmadev->ddev.channels, > + chan.device_node) { > + dma_chan_kill_bh(&mchan->chan); [Severity: Critical] Does flushing the bottom half here happen too late in the teardown sequence? During driver unbind, hidma_remove() calls hidma_ll_uninit() before hidma_free(). hidma_ll_uninit() explicitly sets lldev->trepool = NULL. When hidma_free() then calls dma_chan_kill_bh(), it synchronously flushes the pending bottom half: hidma_chan_bh() hidma_process_completed() hidma_ll_status() tre = &lldev->trepool[tre_ch]; Since trepool is already NULL, won't this cause a deterministic NULL pointer dereference? > + list_del(&mchan->chan.device_node); > + } > } > > static unsigned int nr_desc_prm; [ ... ] > @@ -155,6 +161,13 @@ static void hidma_process_completed(struct hidma_chan *mchan) > } > } > > +static void hidma_chan_bh(struct dma_chan *chan) > +{ > + struct hidma_chan *mchan = to_hidma_chan(chan); > + > + hidma_process_completed(mchan); > +} > + [Severity: High] Does the bottom half work need to be cancelled when a client terminates the channel? When a client calls dma_release_channel() or dmaengine_terminate_sync(), the framework eventually calls hidma_free_chan_resources(), which frees the descriptors. If the bottom half executes concurrently or after this teardown: hidma_chan_bh() hidma_process_completed() list_for_each_entry_safe(mdesc, next, &list, node) { dmaengine_desc_callback_invoke(&cb, &result); } Won't it dereference descriptors that were just freed, causing a use-after-free, and subsequently leak orphaned descriptors onto mchan->free? > /* > * Called once for each submitted descriptor. > * PM is locked once for each descriptor that is currently > @@ -181,7 +194,7 @@ static void hidma_callback(void *data) > } > spin_unlock_irqrestore(&mchan->lock, irqflags); [Severity: Critical] This is a pre-existing issue, but does hidma_terminate_channel() safely handle concurrent callbacks? In hidma_terminate_channel(), the lock is dropped before the hardware is paused: hidma_terminate_channel() spin_unlock_irqrestore(&mchan->lock, irqflags); rc = hidma_ll_disable(dmadev->lldev); During this window, a completed transaction can trigger hidma_callback() which modifies the list without holding a lock on the local list: hidma_callback() if (mdesc->node.next) { list_move_tail(&mdesc->node, &mchan->completed); } Since hidma_terminate_channel() subsequently modifies the same list locklessly, can this race with hidma_prep_dma_memcpy() and cause severe list corruption? [Severity: High] This is a pre-existing issue, but does hidma_callback() correctly handle an empty active list? When updating the running descriptor, the code uses list_first_entry(): hidma_callback() mchan->running = list_first_entry(&mchan->active, struct hidma_desc, node); If mchan->active is empty, list_first_entry() does not return NULL but rather an invalid pointer computed from the list head itself. If hidma_tx_status() is subsequently called, won't it dereference this invalid pointer via mchan->running->desc.cookie and cause an out-of-bounds memory read? > - hidma_process_completed(mchan); > + dma_chan_schedule_bh(&mchan->chan); > > if (queued) { > pm_runtime_mark_last_busy(dmadev->ddev.dev); > pm_runtime_put_autosuspend(dmadev->ddev.dev); [Severity: High] This isn't a bug introduced by this patch, but is the pm_runtime usage counter decrement balanced with the increment? In hidma_issue_pending(), pm_runtime_get() is called only once per submitted batch of descriptors. However, the hardware triggers hidma_callback() for each individual descriptor, and pm_runtime_put_autosuspend() is unconditionally called here for every single descriptor. If a client submits a batch of multiple descriptors, won't this underflow the PM usage count and trigger device auto-suspension while hardware operations are still in flight? [Severity: High] This is a pre-existing issue, but does the tasklet safely call sleeping PM functions? The driver implements hidma_issue_task() as a tasklet, which runs in softirq (atomic) context, but it calls pm_runtime_get_sync(): hidma_issue_task() pm_runtime_get_sync(dmadev->ddev.dev); Since pm_runtime_get_sync() will sleep if the device is suspended, doesn't this trigger a sleeping in atomic bug? Furthermore, in hidma_issue_pending(), if the asynchronous pm_runtime_get() returns 0, the code falls through and immediately calls hidma_ll_start(). Doesn't this access hardware registers while the device is still unclocked or powered off? > } -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=62