* [PATCH v2 0/5] accel/ethosu: fix probe and job cleanup errors
@ 2026-07-17 6:11 GuoHan Zhao
2026-07-17 6:11 ` [PATCH v2 1/5] accel/ethosu: check DMA mask setup GuoHan Zhao
` (4 more replies)
0 siblings, 5 replies; 11+ messages in thread
From: GuoHan Zhao @ 2026-07-17 6:11 UTC (permalink / raw)
To: Rob Herring (Arm), Tomeu Vizoso, dri-devel
Cc: Oded Gabbay, Thomas Zimmermann, Frank Li
Fix error handling and cleanup issues in the Arm Ethos-U driver.
Sashiko reported the original probe, SRAM, and fence cleanup issues while
reviewing the Ethos-U MMIO mapping fix. A follow-up review of v1 found two
more lifecycle issues in scheduler initialization and IRQ teardown, along
with an unchecked DMA mask setup error.
The first two patches handle DMA mask setup and order scheduler and IRQ
lifetimes. The remaining patches unwind probe state, propagate SRAM setup
errors, and fix completion fence ownership.
The reports are available at:
https://sashiko.dev/#/patchset/20260716065219.931088-1-zhaoguohan@kylinos.cn?part=1
https://sashiko.dev/#/patchset/20260716082530.1023538-1-zhaoguohan@kylinos.cn?part=1
---
Changes in v2:
- Add DMA mask error handling.
- Initialize the scheduler before requesting the IRQ and release the IRQ
before scheduler teardown.
- Disable clocks directly on probe failure when runtime PM is unavailable.
- Move the former v1 patches 1/3, 2/3, and 3/3 to patches 3/5, 4/5, and
5/5, respectively.
- Rebase on the current drm-misc-fixes branch.
v1: https://lore.kernel.org/all/20260716082530.1023538-1-zhaoguohan@kylinos.cn/
GuoHan Zhao (5):
accel/ethosu: check DMA mask setup
accel/ethosu: fix scheduler and IRQ lifetime
accel/ethosu: clean up resources on probe failure
accel/ethosu: propagate SRAM initialization errors
accel/ethosu: fix job completion fence cleanup
drivers/accel/ethosu/ethosu_drv.c | 52 ++++++++++++++++++++++++++-----
drivers/accel/ethosu/ethosu_job.c | 25 +++++++++------
2 files changed, 60 insertions(+), 17 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v2 1/5] accel/ethosu: check DMA mask setup 2026-07-17 6:11 [PATCH v2 0/5] accel/ethosu: fix probe and job cleanup errors GuoHan Zhao @ 2026-07-17 6:11 ` GuoHan Zhao 2026-07-17 6:23 ` sashiko-bot 2026-07-17 6:11 ` [PATCH v2 2/5] accel/ethosu: fix scheduler and IRQ lifetime GuoHan Zhao ` (3 subsequent siblings) 4 siblings, 1 reply; 11+ messages in thread From: GuoHan Zhao @ 2026-07-17 6:11 UTC (permalink / raw) To: Rob Herring (Arm), Tomeu Vizoso, dri-devel Cc: Oded Gabbay, Thomas Zimmermann, Frank Li dma_set_mask_and_coherent() can fail when platform DMA operations do not support the requested 40-bit address mask. Ignoring the error leaves the previous DMA configuration in place. Probe then continues without ensuring that DMA addresses are suitable for the NPU. Return the error so the driver does not bind with an unsupported DMA configuration. Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver") Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260716082530.1023538-1-zhaoguohan@kylinos.cn?part=1 Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> --- New in v2. Sashiko report: > This is a pre-existing issue, but does this code ignore the return value of > dma_set_mask_and_coherent() which is called earlier in ethosu_probe()? > > If the platform only supports 32-bit DMA and the call fails, the default > 32-bit mask is retained. The DRM core and driver might proceed assuming > 40-bit DMA is active, handing the NPU physical addresses greater than 4 GB, > which could lead to silent DMA address truncation and memory corruption. drivers/accel/ethosu/ethosu_drv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ethosu/ethosu_drv.c b/drivers/accel/ethosu/ethosu_drv.c index ed9c748a54ad..f3920185389d 100644 --- a/drivers/accel/ethosu/ethosu_drv.c +++ b/drivers/accel/ethosu/ethosu_drv.c @@ -339,7 +339,9 @@ static int ethosu_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, ethosudev); - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + if (ret) + return ret; ethosudev->regs = devm_platform_ioremap_resource(pdev, 0); -- 2.43.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/5] accel/ethosu: check DMA mask setup 2026-07-17 6:11 ` [PATCH v2 1/5] accel/ethosu: check DMA mask setup GuoHan Zhao @ 2026-07-17 6:23 ` sashiko-bot 0 siblings, 0 replies; 11+ messages in thread From: sashiko-bot @ 2026-07-17 6:23 UTC (permalink / raw) To: GuoHan Zhao; +Cc: dri-devel Thank you for your contribution! Sashiko AI review found 12 potential issue(s) to consider: Pre-existing issues: - [Critical] Validation mismatch allows jobs to run with stale NPU region pointers (UAF / OOB DMA). - [High] Missing IS_ERR check for devm_platform_ioremap_resource() in ethosu_probe(). - [High] Ignored ethosu_sram_init() failure leaves stale sram_size, causing the NPU to DMA to physical address 0x0. - [High] ethosu_probe error paths leak DRM scheduler, PM runtime references, and SRAM, leading to a UAF. - [High] Calling drm_sched_fini on a failed drm_sched_init causes a crash. - [High] WARN_ON(ret) in ethosu_job_open evaluates to 1 on error, bypassing VFS error checks and causing NULL pointer dereferences later. - [High] The job's done_fence is leaked on all error paths in ethosu_ioctl_submit_job. - [High] ethosu_job_run leaves done_fence uninitialized if the job is aborted, causing a refcount underflow later. - [High] Hardirq handler reads unclocked MMIO registers when IRQ fires early or during runtime suspend. - [High] Out-of-bounds array read in ethosu_job_timedout using unvalidated hardware register value. - [High] Potential AB-BA deadlock due to calling pm_runtime_resume_and_get while holding dma_resv locks. - [High] Uninitialized SRAM memory disclosure via runtime PM race. -- --- Patch [1]: [PATCH v2 1/5] accel/ethosu: check DMA mask setup --- commit ea4ab7f2e2a6b6cb0faa43a971f991179714158a Author: GuoHan Zhao <zhaoguohan@kylinos.cn> Subject: accel/ethosu: check DMA mask setup This patch checks the return value of dma_set_mask_and_coherent() to avoid proceeding with an unsupported DMA configuration. If it fails, the probe function now properly returns the error. Link: https://sashiko.dev/#/patchset/20260716082530.1023538-1-zhaoguohan@kylinos.cn?part=1 > diff --git a/drivers/accel/ethosu/ethosu_drv.c b/drivers/accel/ethosu/ethosu_drv.c > index ed9c748a54ad5..f3920185389de 100644 > --- a/drivers/accel/ethosu/ethosu_drv.c > +++ b/drivers/accel/ethosu/ethosu_drv.c > @@ -339,7 +339,9 @@ static int ethosu_probe(struct platform_device *pdev) > return -ENOMEM; > platform_set_drvdata(pdev, ethosudev); > > - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); > + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); > + if (ret) > + return ret; > > ethosudev->regs = devm_platform_ioremap_resource(pdev, 0); [Severity: High] This is a pre-existing issue, but does this code check the return value of devm_platform_ioremap_resource()? If devm_platform_ioremap_resource() fails, it returns an ERR_PTR. Because this is not checked, ethosu_init() subsequently calls ethosu_device_resume() which calls ethosu_reset(), passing the error pointer to writel_relaxed(), resulting in a fatal page fault: ethosu_reset() writel_relaxed(RESET_PENDING_CSL, ethosudev->regs + NPU_REG_RESET); Could we add an IS_ERR check here? [Severity: High] This isn't a bug introduced by this patch, but does the error path in ethosu_probe() clean up the DRM scheduler properly? If ethosu_probe() fails after ethosu_job_init() (which initializes the scheduler), it seems to return directly without calling ethosu_job_fini(): ret = ethosu_init(ethosudev); if (ret) return ret; Since ethosudev is devres-managed, it is freed upon probe failure, but the active scheduler kthreads might remain running and attempt to access the freed memory. While reviewing this driver, I also noticed a few other pre-existing issues outside of this patch's context: [Severity: Critical] This isn't a bug introduced by this patch, but does the validation logic in ethosu_ioctl_submit_job() incorrectly permit jobs with sram_size = 0? ethosu_ioctl_submit_job() if (i == ETHOSU_SRAM_REGION) { if (cmd_info->region_size[i] <= edev->npu_info.sram_size) continue; If a user sets job->sram_size to 0, validation passes. However, ethosu_job_hw_submit() uses job->sram_size to conditionally update the base: ethosu_job_hw_submit() if (job->sram_size) { writel_relaxed(lower_32_bits(dev->sramphys), ...); } Since it is 0, the base pointer update is skipped. Can this allow the NPU to execute the command stream using a stale pointer left over from a previous job, resulting in out-of-bounds DMA? [Severity: High] This is a pre-existing issue, but does ethosu_init() ignore the return value of ethosu_sram_init()? If ethosu_sram_init() fails, ethosudev->sramphys remains 0, but ethosudev->npu_info.sram_size was already populated. Since ethosu_init() doesn't check the return value, it permits the driver to proceed: ethosu_init() ethosu_sram_init(ethosudev); dev_info(ethosudev->base.dev, ...); If userspace submits a job requesting SRAM, ethosu_job_hw_submit() programs the NPU using dev->sramphys: ethosu_job_hw_submit() writel_relaxed(lower_32_bits(dev->sramphys), dev->regs + NPU_REG_BASEP(ETHOSU_SRAM_REGION)); Can this cause the hardware to DMA to physical address 0x0? [Severity: High] This is a pre-existing issue, but can the error path in ethosu_job_init() cause a crash if drm_sched_init() fails? ethosu_job_init() ret = drm_sched_init(&edev->sched, ...); if (ret) goto err_sched; ... err_sched: drm_sched_fini(&edev->sched); return ret; If drm_sched_init() fails, it cleans up internally. Does calling drm_sched_fini() on it again attempt to stop non-existent workqueues or kthreads, resulting in a NULL pointer dereference? [Severity: High] This isn't a bug introduced by this patch, but does ethosu_job_open() return a positive value on error? ethosu_job_open() ret = drm_sched_entity_init(...); if (ret) return WARN_ON(ret); WARN_ON() evaluates to 1. When ethosu_open() propagates this to VFS, it might bypass the VFS error checks since 1 is treated as success: ethosu_open() ret = ethosu_job_open(priv); if (ret) goto err_put_mod; Could this bypass assigning file->driver_priv, leading to a NULL pointer dereference later when ethosu_postclose() passes it to ethosu_job_close()? [Severity: High] This is a pre-existing issue, but is the done_fence leaked on error paths in ethosu_ioctl_submit_job()? ethosu_ioctl_submit_job() ejob->done_fence = kzalloc_obj(*ejob->done_fence); If the submission fails later, ethosu_job_err_cleanup() is called, but it seems to omit freeing the done_fence: ethosu_job_err_cleanup() ... drm_gem_object_put(job->cmd_bo); kfree(job); Can an unprivileged user trigger this leak repeatedly by passing invalid parameters? [Severity: High] This is a pre-existing issue, but can ethosu_job_run() skip initializing the fence, leading to a refcount underflow? ethosu_job_run() if (unlikely(job->base.s_fence->finished.error)) return NULL; dma_fence_init(fence, ðosu_fence_ops, &dev->fence_lock, ...); If it returns early, job->done_fence remains zero-initialized. Later, ethosu_job_cleanup() unconditionally calls dma_fence_put(job->done_fence), which could attempt to decrement a 0-refcount object. [Severity: High] This isn't a bug introduced by this patch, but is the IRQ requested before the device clocks are turned on? ethosu_job_init() ret = devm_request_threaded_irq(dev, edev->irq, ethosu_job_irq_handler, ...); If the device shares this IRQ, and the IRQ fires before ethosu_init() enables the clocks, ethosu_job_irq_handler() will immediately access MMIO: ethosu_job_irq_handler() u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS); Can accessing unclocked MMIO registers cause a fatal bus lockup? [Severity: High] This is a pre-existing issue, but does ethosu_job_timedout() use an unvalidated hardware register value as an array index? ethosu_job_timedout() cmdaddr = readl_relaxed(dev->regs + NPU_REG_QREAD); ... dev_err(dev->base.dev, "...", cmdaddr, bocmds[cmdaddr / 4]); If a malicious command stream causes a timeout with an out-of-bounds address in QREAD, could this perform an out-of-bounds kernel memory read? [Severity: High] This is a pre-existing issue, but can ethosu_job_push() cause an AB-BA deadlock by calling pm_runtime_resume_and_get() while holding dma_resv locks? ethosu_job_push() ret = drm_gem_lock_reservations(job->region_bo, ...); if (ret) return ret; ... ret = pm_runtime_resume_and_get(job->dev->base.dev); If memory reclaim runs and attempts to shrink shared BOs, the shrinker will try to acquire the same dma_resv locks. Since pm_runtime can block on allocations or power domains, could this invert lock ordering? [Severity: High] This is a pre-existing issue, but does ethosu_init() expose uninitialized SRAM via a runtime PM race? ethosu_init() ret = ethosu_device_resume(ethosudev->base.dev); ... ethosu_sram_init(ethosudev); Because ethosu_device_resume() is called before ethosu_sram_init() allocates the SRAM, the memset_io() zeroing logic is skipped. The device is then marked active. If a job is submitted immediately, pm_runtime_resume_and_get() might skip ethosu_device_resume(), allowing the job to run with uncleared SRAM memory. Could this leak sensitive data to userspace? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260717061145.1478139-1-zhaoguohan@kylinos.cn?part=1 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 2/5] accel/ethosu: fix scheduler and IRQ lifetime 2026-07-17 6:11 [PATCH v2 0/5] accel/ethosu: fix probe and job cleanup errors GuoHan Zhao 2026-07-17 6:11 ` [PATCH v2 1/5] accel/ethosu: check DMA mask setup GuoHan Zhao @ 2026-07-17 6:11 ` GuoHan Zhao 2026-07-17 6:24 ` sashiko-bot 2026-07-17 6:11 ` [PATCH v2 3/5] accel/ethosu: clean up resources on probe failure GuoHan Zhao ` (2 subsequent siblings) 4 siblings, 1 reply; 11+ messages in thread From: GuoHan Zhao @ 2026-07-17 6:11 UTC (permalink / raw) To: Rob Herring (Arm), Tomeu Vizoso, dri-devel Cc: Oded Gabbay, Thomas Zimmermann, Frank Li ethosu_job_init() requests the managed IRQ before initializing the DRM scheduler. If drm_sched_init() fails, the error path calls drm_sched_fini() on a partially initialized scheduler. The IRQ also remains registered until devres cleanup after normal or probe-error paths destroy the scheduler. Initialize the scheduler before requesting the IRQ. Scheduler setup failure then needs no teardown, while IRQ setup failure can tear down a valid scheduler. Free the IRQ explicitly before drm_sched_fini() to prevent interrupt handlers from accessing scheduler state during teardown. Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver") Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260716082530.1023538-1-zhaoguohan@kylinos.cn?part=1 Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> --- New in v2. Sashiko reports: > This is a pre-existing issue, but does the error handling path for > drm_sched_init() cause a panic if it fails? > > drivers/accel/ethosu/ethosu_job.c:ethosu_job_init() { > ... > ret = drm_sched_init(&edev->sched, &args); > if (ret) { > dev_err(dev, "Failed to create scheduler: %d\n", ret); > goto err_sched; > } > return 0; > > err_sched: > drm_sched_fini(&edev->sched); > return ret; > } > > If drm_sched_init() fails, it cleans up its own state. The error path > then branches to err_sched and calls drm_sched_fini() on the partially > initialized scheduler. > > Because the waitqueue head was either destroyed or never initialized, > its list pointers are NULL. Will drm_sched_fini() invoking > wake_up_all(&sched->job_scheduled) cause an immediate crash? > This is a pre-existing issue, but can the devm-managed shared IRQ handler > outlive the DRM scheduler here? > > The IRQ is requested using devm_request_threaded_irq(). During > ethosu_remove() (and on probe failure), the driver explicitly calls > ethosu_job_fini(), which destroys the DRM scheduler. > > Because the IRQ is managed by devm, it remains fully active until the > remove function completes. If an interrupt fires in this window, could > ethosu_job_irq_handler() execute and access the destroyed dev->sched or > dev->in_flight_job structures, leading to a use-after-free? drivers/accel/ethosu/ethosu_job.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c index b76924645aaa..5847433e87e7 100644 --- a/drivers/accel/ethosu/ethosu_job.c +++ b/drivers/accel/ethosu/ethosu_job.c @@ -315,6 +315,14 @@ int ethosu_job_init(struct ethosu_device *edev) if (edev->irq < 0) return edev->irq; + edev->fence_context = dma_fence_context_alloc(1); + + ret = drm_sched_init(&edev->sched, &args); + if (ret) { + dev_err(dev, "Failed to create scheduler: %d\n", ret); + return ret; + } + ret = devm_request_threaded_irq(dev, edev->irq, ethosu_job_irq_handler, ethosu_job_irq_handler_thread, @@ -322,14 +330,6 @@ int ethosu_job_init(struct ethosu_device *edev) edev); if (ret) { dev_err(dev, "failed to request irq\n"); - return ret; - } - - edev->fence_context = dma_fence_context_alloc(1); - - ret = drm_sched_init(&edev->sched, &args); - if (ret) { - dev_err(dev, "Failed to create scheduler: %d\n", ret); goto err_sched; } @@ -342,6 +342,7 @@ int ethosu_job_init(struct ethosu_device *edev) void ethosu_job_fini(struct ethosu_device *dev) { + devm_free_irq(dev->base.dev, dev->irq, dev); drm_sched_fini(&dev->sched); } -- 2.43.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/5] accel/ethosu: fix scheduler and IRQ lifetime 2026-07-17 6:11 ` [PATCH v2 2/5] accel/ethosu: fix scheduler and IRQ lifetime GuoHan Zhao @ 2026-07-17 6:24 ` sashiko-bot 0 siblings, 0 replies; 11+ messages in thread From: sashiko-bot @ 2026-07-17 6:24 UTC (permalink / raw) To: GuoHan Zhao; +Cc: dri-devel Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider: Pre-existing issues: - [Critical] ethosu_init() ignores the return value of ethosu_sram_init(). - [Critical] The driver leaves NPU_REG_BASEP(ETHOSU_SRAM_REGION) unmodified when job->sram_size == 0 and no BO handle is provided for the SRAM region, allowing an attacker to force the NPU to use a stale DMA address from a previously freed BO. - [High] The ethosu_probe() error paths lack cleanup for resources initialized during probe, leading to memory leaks and leaked DRM scheduler workqueues. - [High] The return value of devm_platform_ioremap_resource() is not checked for errors, leading to a crash on failure. - [High] Calling drm_sched_job_cleanup() on an uninitialized job causes a null pointer dereference. - [High] Racing ethosu_ioctl_submit with device unbind causes kernel panics due to missing drm_dev_enter() and incorrect scheduler lifetime. - [High] The job->done_fence allocated during job submission is leaked on error paths and causes a refcount underflow warning during scheduler teardown if the job is cancelled. - [High] Shared IRQ handler accesses hardware registers while clocks are disabled. -- --- Patch [2]: [PATCH v2 2/5] accel/ethosu: fix scheduler and IRQ lifetime --- commit 5c0b05e99c708b0d7c384370684640c706d58902 Author: GuoHan Zhao <zhaoguohan@kylinos.cn> accel/ethosu: fix scheduler and IRQ lifetime ethosu_job_init() requests the managed IRQ before initializing the DRM scheduler. If drm_sched_init() fails, the error path calls drm_sched_fini() on a partially initialized scheduler. The IRQ also remains registered until devres cleanup after normal or probe-error paths destroy the scheduler. Initialize the scheduler before requesting the IRQ. Scheduler setup failure then needs no teardown, while IRQ setup failure can tear down a valid scheduler. Free the IRQ explicitly before drm_sched_fini() to prevent interrupt handlers from accessing scheduler state during teardown. Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver") Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260716082530.1023538-1-zhaoguohan@kylinos.cn?part=1 Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> > diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c > index b76924645aaaf..5847433e87e7e 100644 > --- a/drivers/accel/ethosu/ethosu_job.c > +++ b/drivers/accel/ethosu/ethosu_job.c > @@ -315,6 +315,14 @@ int ethosu_job_init(struct ethosu_device *edev) > if (edev->irq < 0) > return edev->irq; > > + edev->fence_context = dma_fence_context_alloc(1); > + > + ret = drm_sched_init(&edev->sched, &args); > + if (ret) { > + dev_err(dev, "Failed to create scheduler: %d\n", ret); > + return ret; > + } > + > ret = devm_request_threaded_irq(dev, edev->irq, [ ... ] [Severity: High] This is a pre-existing issue, but the ethosu_probe() error paths lack cleanup for resources initialized during probe: drivers/accel/ethosu/ethosu_drv.c:ethosu_probe() { ... ret = ethosu_init(ethosudev); if (ret) return ret; ... } If ethosu_init() or drm_dev_register() fails, the function returns directly without calling ethosu_job_fini(). Does this leak the DRM scheduler initialized by ethosu_job_init(), including the scheduler's submit_wq workqueue and threads? [Severity: High] This is a pre-existing issue, but the return value of devm_platform_ioremap_resource() is not checked for errors: drivers/accel/ethosu/ethosu_drv.c:ethosu_probe() { ... ethosudev->regs = devm_platform_ioremap_resource(pdev, 0); ethosudev->num_clks = devm_clk_bulk_get_all(&pdev->dev, ðosudev->clks); ... } If devm_platform_ioremap_resource() fails, it returns an ERR_PTR. Because the return value is not checked with IS_ERR(), could ethosudev->regs hold an invalid error pointer that causes a crash when dereferenced later in ethosu_reset()? [Severity: High] This is a pre-existing issue, but drm_sched_job_cleanup() might be called on an uninitialized job: drivers/accel/ethosu/ethosu_job.c:ethosu_ioctl_submit_job() { ... ejob->done_fence = kzalloc_obj(*ejob->done_fence); if (!ejob->done_fence) { ret = -ENOMEM; goto out_cleanup_job; } ... out_cleanup_job: if (ret) drm_sched_job_cleanup(&ejob->base); ... } If the allocation for ejob->done_fence fails, the error path calls drm_sched_job_cleanup() on ejob->base. However, drm_sched_job_init() was never called, meaning ejob->base.s_fence is NULL. Will this cause a null pointer dereference when drm_sched_job_cleanup() attempts to read the refcount? [Severity: Critical] This is a pre-existing issue, but ethosu_init() ignores the return value of ethosu_sram_init(): drivers/accel/ethosu/ethosu_drv.c:ethosu_init() { ... ethosudev->npu_info.id = id = readl_relaxed(ethosudev->regs + NPU_REG_ID); ethosudev->npu_info.config = config = readl_relaxed(ethosudev->regs + NPU_REG_CONFIG); ethosu_sram_init(ethosudev); ... } If gen_pool_dma_alloc() fails inside ethosu_sram_init(), it returns -ENOMEM, but ethosu_init() completely ignores this return code. Could the driver proceed as if SRAM is fully available, programming physical address 0 into the NPU SRAM base registers when a job runs? [Severity: High] This is a pre-existing issue, but ethosu_ioctl_submit() appears to lack drm_dev_enter() and drm_dev_exit() protection: drivers/accel/ethosu/ethosu_job.c:ethosu_ioctl_submit() { struct drm_ethosu_submit *args = data; ... While ethosu_remove() tears down the scheduler: drivers/accel/ethosu/ethosu_drv.c:ethosu_remove() { ... drm_dev_unregister(ðosudev->base); ethosu_job_fini(ethosudev); ... } Since ethosu_remove() destroys the DRM scheduler synchronously via ethosu_job_fini(), userspace might continue invoking submit ioctls on open file descriptors. Can this result in a use-after-free if submissions are pushed to the scheduler entity and attempt to use the destroyed dev->sched workqueues and locks? [Severity: High] This is a pre-existing issue, but the job->done_fence allocated during job submission seems to be leaked on error paths: drivers/accel/ethosu/ethosu_job.c:ethosu_job_err_cleanup() { unsigned int i; for (i = 0; i < job->region_cnt; i++) drm_gem_object_put(job->region_bo[i]); drm_gem_object_put(job->cmd_bo); kfree(job); } If job submission fails after ejob->done_fence is allocated, ethosu_job_err_cleanup() frees the job but never frees the done_fence. Additionally, if a job is cancelled before execution, dma_fence_init() is never called, leaving the fence refcount at 0. drivers/accel/ethosu/ethosu_job.c:ethosu_job_cleanup() { ... dma_fence_put(job->done_fence); ... } Could dma_fence_put() then trigger a refcount underflow warning during scheduler teardown? [Severity: Critical] This is a pre-existing issue, but the NPU SRAM base address might remain unmodified when job->sram_size is 0: drivers/accel/ethosu/ethosu_job.c:ethosu_ioctl_submit_job() { ... /* Can only omit a BO handle if the region is not used or used for SRAM */ if (!job->region_bo_handles[i]) { if (!cmd_info->region_size[i]) continue; if (i == ETHOSU_SRAM_REGION) { if (cmd_info->region_size[i] <= edev->npu_info.sram_size) continue; ... } drivers/accel/ethosu/ethosu_job.c:ethosu_job_hw_submit() { ... if (job->sram_size) { writel_relaxed(lower_32_bits(dev->sramphys), dev->regs + NPU_REG_BASEP(ETHOSU_SRAM_REGION)); ... } The ioctl validation allows an empty BO handle for ETHOSU_SRAM_REGION if the command stream region size fits in the hardware SRAM. However, ethosu_job_hw_submit() only programs the hardware SRAM base if job->sram_size is greater than 0. If a user submits a job with a command stream that accesses the SRAM region while setting job->sram_size to 0, does this leave a stale DMA address in the hardware register from a previously freed BO, potentially allowing arbitrary use-after-free DMA access? [Severity: High] This is a pre-existing issue, but the shared IRQ handler accesses hardware registers unconditionally: drivers/accel/ethosu/ethosu_job.c:ethosu_job_irq_handler() { struct ethosu_device *dev = data; u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS); ... } The driver requests the IRQ using IRQF_SHARED and supports runtime PM. If another device on the same shared IRQ line triggers an interrupt while this device is runtime-suspended and its clocks are disabled, could reading dev->regs + NPU_REG_STATUS cause a synchronous external abort (bus fault)? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260717061145.1478139-1-zhaoguohan@kylinos.cn?part=2 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 3/5] accel/ethosu: clean up resources on probe failure 2026-07-17 6:11 [PATCH v2 0/5] accel/ethosu: fix probe and job cleanup errors GuoHan Zhao 2026-07-17 6:11 ` [PATCH v2 1/5] accel/ethosu: check DMA mask setup GuoHan Zhao 2026-07-17 6:11 ` [PATCH v2 2/5] accel/ethosu: fix scheduler and IRQ lifetime GuoHan Zhao @ 2026-07-17 6:11 ` GuoHan Zhao 2026-07-17 6:27 ` sashiko-bot 2026-07-17 6:11 ` [PATCH v2 4/5] accel/ethosu: propagate SRAM initialization errors GuoHan Zhao 2026-07-17 6:11 ` [PATCH v2 5/5] accel/ethosu: fix job completion fence cleanup GuoHan Zhao 4 siblings, 1 reply; 11+ messages in thread From: GuoHan Zhao @ 2026-07-17 6:11 UTC (permalink / raw) To: Rob Herring (Arm), Tomeu Vizoso, dri-devel Cc: Oded Gabbay, Thomas Zimmermann, Frank Li ethosu_job_init() creates a scheduler before ethosu_init() and drm_dev_register(). Errors from either later step return directly, leaving the scheduler workqueue allocated. A drm_dev_register() failure also leaves the optional SRAM allocation behind. Unwind runtime PM, SRAM, and scheduler state in reverse order on probe failure. Disable the clocks directly when runtime PM is unavailable or its setup fails. Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver") Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260716065219.931088-1-zhaoguohan@kylinos.cn?part=1 Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> --- Changes in v2: - Apply after the scheduler and IRQ lifetime fix so probe cleanup releases the IRQ before destroying the scheduler. - Disable clocks directly when runtime PM is unavailable. Sashiko report: > This is a pre-existing issue, but was not introduced by this patch. > > If ethosu_init() or drm_dev_register() fail, the function returns > directly without calling ethosu_job_fini() or freeing the sram pool. > > Because the job scheduler is embedded in the devm-allocated > ethosu_device, it will be freed when devm cleans up. However, the drm > scheduler kthreads and timers remain active and will access the freed > memory. > > Can this cause a use-after-free regression leading to a kernel panic? drivers/accel/ethosu/ethosu_drv.c | 41 ++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ethosu/ethosu_drv.c b/drivers/accel/ethosu/ethosu_drv.c index f3920185389d..6b97d22444a7 100644 --- a/drivers/accel/ethosu/ethosu_drv.c +++ b/drivers/accel/ethosu/ethosu_drv.c @@ -272,6 +272,17 @@ static int ethosu_device_suspend(struct device *dev) return 0; } +static void ethosu_runtime_suspend(struct ethosu_device *ethosudev) +{ + struct device *dev = ethosudev->base.dev; + + pm_runtime_dont_use_autosuspend(dev); + if (pm_runtime_enabled(dev)) + pm_runtime_put_sync_suspend(dev); + else + ethosu_device_suspend(dev); +} + static int ethosu_sram_init(struct ethosu_device *ethosudev) { ethosudev->npu_info.sram_size = 0; @@ -293,6 +304,14 @@ static int ethosu_sram_init(struct ethosu_device *ethosudev) return 0; } +static void ethosu_sram_fini(struct ethosu_device *ethosudev) +{ + if (ethosudev->sram) + gen_pool_free(ethosudev->srampool, + (unsigned long)ethosudev->sram, + ethosudev->npu_info.sram_size); +} + static int ethosu_init(struct ethosu_device *ethosudev) { int ret; @@ -306,7 +325,7 @@ static int ethosu_init(struct ethosu_device *ethosudev) pm_runtime_use_autosuspend(ethosudev->base.dev); ret = devm_pm_runtime_set_active_enabled(ethosudev->base.dev); if (ret) - return ret; + goto err_suspend; pm_runtime_get_noresume(ethosudev->base.dev); ethosudev->npu_info.id = id = readl_relaxed(ethosudev->regs + NPU_REG_ID); @@ -326,6 +345,11 @@ static int ethosu_init(struct ethosu_device *ethosudev) ethosudev->npu_info.sram_size / 1024); return 0; + +err_suspend: + pm_runtime_dont_use_autosuspend(ethosudev->base.dev); + ethosu_device_suspend(ethosudev->base.dev); + return ret; } static int ethosu_probe(struct platform_device *pdev) @@ -355,13 +379,20 @@ static int ethosu_probe(struct platform_device *pdev) ret = ethosu_init(ethosudev); if (ret) - return ret; + goto err_job_fini; ret = drm_dev_register(ðosudev->base, 0); if (ret) - pm_runtime_dont_use_autosuspend(ethosudev->base.dev); + goto err_runtime_suspend; pm_runtime_put_autosuspend(ethosudev->base.dev); + return 0; + +err_runtime_suspend: + ethosu_runtime_suspend(ethosudev); + ethosu_sram_fini(ethosudev); +err_job_fini: + ethosu_job_fini(ethosudev); return ret; } @@ -371,9 +402,7 @@ static void ethosu_remove(struct platform_device *pdev) drm_dev_unregister(ðosudev->base); ethosu_job_fini(ethosudev); - if (ethosudev->sram) - gen_pool_free(ethosudev->srampool, (unsigned long)ethosudev->sram, - ethosudev->npu_info.sram_size); + ethosu_sram_fini(ethosudev); } static const struct of_device_id dt_match[] = { -- 2.43.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 3/5] accel/ethosu: clean up resources on probe failure 2026-07-17 6:11 ` [PATCH v2 3/5] accel/ethosu: clean up resources on probe failure GuoHan Zhao @ 2026-07-17 6:27 ` sashiko-bot 0 siblings, 0 replies; 11+ messages in thread From: sashiko-bot @ 2026-07-17 6:27 UTC (permalink / raw) To: GuoHan Zhao; +Cc: dri-devel Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: Pre-existing issues: - [High] The shared interrupt handler accesses hardware registers without verifying if the device is active, risking a synchronous external abort. - [High] Runtime suspend disables hardware clocks without calling synchronize_irq() for the shared interrupt. - [High] Missing IS_ERR() check on the return value of devm_platform_ioremap_resource() causes an error pointer dereference. - [High] The shared IRQ is requested before the hardware is powered on, risking a crash if a shared interrupt fires early. - [High] Destroying the DRM scheduler in ethosu_remove() creates a Use-After-Free risk for open file descriptors. - [High] An untrusted hardware register value is used as an array index without bounds checking, potentially leaking kernel memory to the log. -- --- Patch [3]: [PATCH v2 3/5] accel/ethosu: clean up resources on probe failure --- commit 596a2469c9dadb88b1da94803fdbc80b578983ef Author: GuoHan Zhao <zhaoguohan@kylinos.cn> accel/ethosu: clean up resources on probe failure ethosu_job_init() creates a scheduler before ethosu_init() and drm_dev_register(). Errors from either later step return directly, leaving the scheduler workqueue allocated. A drm_dev_register() failure also leaves the optional SRAM allocation behind. Unwind runtime PM, SRAM, and scheduler state in reverse order on probe failure. Disable the clocks directly when runtime PM is unavailable or its setup fails. Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver") Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260716065219.931088-1-zhaoguohan@kylinos.cn?part=1 Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> > diff --git a/drivers/accel/ethosu/ethosu_drv.c b/drivers/accel/ethosu/ethosu_drv.c > index f3920185389de..6b97d22444a7c 100644 > --- a/drivers/accel/ethosu/ethosu_drv.c > +++ b/drivers/accel/ethosu/ethosu_drv.c > @@ -272,6 +272,17 @@ static int ethosu_device_suspend(struct device *dev) [Severity: High] This is a pre-existing issue, but ethosu_device_suspend() disables hardware clocks without calling synchronize_irq() for the shared interrupt: drivers/accel/ethosu/ethosu_drv.c:ethosu_device_suspend() { struct ethosu_device *ethosudev = dev_get_drvdata(dev); clk_bulk_disable_unprepare(ethosudev->num_clks, ethosudev->clks); return 0; } Could this cause a synchronous external abort if the device enters runtime suspend while the interrupt handler is actively executing on another CPU? > return 0; > } > > +static void ethosu_runtime_suspend(struct ethosu_device *ethosudev) > +{ > + struct device *dev = ethosudev->base.dev; > + > + pm_runtime_dont_use_autosuspend(dev); > + if (pm_runtime_enabled(dev)) > + pm_runtime_put_sync_suspend(dev); > + else > + ethosu_device_suspend(dev); > +} > + > static int ethosu_sram_init(struct ethosu_device *ethosudev) [ ... ] > @@ -355,13 +379,20 @@ static int ethosu_probe(struct platform_device *pdev) [Severity: High] This is a pre-existing issue, but devm_platform_ioremap_resource() returns an ERR_PTR on failure, not NULL. In ethosu_probe(), its return value is assigned directly without an IS_ERR check: drivers/accel/ethosu/ethosu_drv.c:ethosu_probe() { ... ethosudev->regs = devm_platform_ioremap_resource(pdev, 0); ethosudev->num_clks = devm_clk_bulk_get_all(&pdev->dev, ðosudev->clks); ... } If the resource mapping fails, would a subsequent call to readl_relaxed() in ethosu_init() dereference the error pointer? [Severity: High] This is a pre-existing issue, but the shared IRQ is requested before the hardware is powered on in ethosu_probe(): drivers/accel/ethosu/ethosu_drv.c:ethosu_probe() { ... ret = ethosu_job_init(ethosudev); if (ret) return ret; ret = ethosu_init(ethosudev); ... } If another device on the same shared IRQ line triggers an interrupt between ethosu_job_init() and ethosu_init(), could the interrupt handler attempt to access MMIO registers while the clocks are still disabled, causing a crash? > > ret = ethosu_init(ethosudev); > if (ret) > - return ret; > + goto err_job_fini; > > ret = drm_dev_register(ðosudev->base, 0); > if (ret) > - pm_runtime_dont_use_autosuspend(ethosudev->base.dev); > + goto err_runtime_suspend; > > pm_runtime_put_autosuspend(ethosudev->base.dev); > + return 0; > + > +err_runtime_suspend: > + ethosu_runtime_suspend(ethosudev); > + ethosu_sram_fini(ethosudev); > +err_job_fini: > + ethosu_job_fini(ethosudev); > return ret; > } > > @@ -371,9 +402,7 @@ static void ethosu_remove(struct platform_device *pdev) > > drm_dev_unregister(ðosudev->base); > ethosu_job_fini(ethosudev); [Severity: High] This is a pre-existing issue, but destroying the DRM scheduler here in ethosu_remove() might create a use-after-free risk. drm_dev_unregister() hides the device node but doesn't revoke existing open file descriptors. If a userspace process still holds an open file descriptor when the driver is unbound, and subsequently submits an ioctl, will it access the destroyed scheduler kthreads and freed SRAM? > - if (ethosudev->sram) > - gen_pool_free(ethosudev->srampool, (unsigned long)ethosudev->sram, > - ethosudev->npu_info.sram_size); > + ethosu_sram_fini(ethosudev); > } [Severity: High] This isn't a bug introduced by this patch, but I found a pre-existing issue in ethosu_job_irq_handler(). The shared interrupt handler accesses hardware registers without verifying if the device is active: drivers/accel/ethosu/ethosu_job.c:ethosu_job_irq_handler() { ... u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS); ... } Because the handler is registered with IRQF_SHARED, couldn't another device on the same IRQ line trigger an interrupt while the NPU is runtime-suspended? Accessing clock-gated MMIO here could trigger a synchronous external abort. [Severity: High] This is a pre-existing issue, but I found a potential out-of-bounds read in ethosu_job_timedout(). An untrusted hardware register value is used as an array index without bounds checking: drivers/accel/ethosu/ethosu_job.c:ethosu_job_timedout() { ... cmdaddr, bocmds[cmdaddr / 4]); ... } If a malformed job forces a timeout and leaves a large offset in the NPU_REG_QREAD register, could cmdaddr exceed the bounds of the cmd_bo buffer and leak kernel memory to the log? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260717061145.1478139-1-zhaoguohan@kylinos.cn?part=3 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 4/5] accel/ethosu: propagate SRAM initialization errors 2026-07-17 6:11 [PATCH v2 0/5] accel/ethosu: fix probe and job cleanup errors GuoHan Zhao ` (2 preceding siblings ...) 2026-07-17 6:11 ` [PATCH v2 3/5] accel/ethosu: clean up resources on probe failure GuoHan Zhao @ 2026-07-17 6:11 ` GuoHan Zhao 2026-07-17 6:24 ` sashiko-bot 2026-07-17 6:11 ` [PATCH v2 5/5] accel/ethosu: fix job completion fence cleanup GuoHan Zhao 4 siblings, 1 reply; 11+ messages in thread From: GuoHan Zhao @ 2026-07-17 6:11 UTC (permalink / raw) To: Rob Herring (Arm), Tomeu Vizoso, dri-devel Cc: Oded Gabbay, Thomas Zimmermann, Frank Li ethosu_sram_init() returns -ENOMEM if allocation from a declared SRAM pool fails. ethosu_init() ignores the error after recording the pool size. Probe then registers a device with a nonzero SRAM size and a zero sramphys address, allowing jobs to program address zero for SRAM. Propagate the error and synchronously suspend the device before the probe path releases the scheduler. Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver") Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260716065219.931088-1-zhaoguohan@kylinos.cn?part=1 Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> --- Changes in v2: - Renumber from patch 2/3 to 4/5. - Use the common runtime suspend helper when SRAM setup fails. Sashiko report: > This is a pre-existing issue, but was not introduced by this patch. > > In ethosu_sram_init(), if gen_pool_dma_alloc() fails, it returns an > error. However, ethosu_init() ignores this return value. > > Because npu_info.sram_size was already set to gen_pool_size(), it remains > non-zero while sramphys remains 0. > > When a user submits a job requesting sram, the size check passes, and > ethosu_job_hw_submit() configures the hardware to use physical sram > address 0x0. > > Could this result in a memory corruption regression or an IOMMU fault? drivers/accel/ethosu/ethosu_drv.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ethosu/ethosu_drv.c b/drivers/accel/ethosu/ethosu_drv.c index 6b97d22444a7..c825b67e9cba 100644 --- a/drivers/accel/ethosu/ethosu_drv.c +++ b/drivers/accel/ethosu/ethosu_drv.c @@ -331,7 +331,9 @@ static int ethosu_init(struct ethosu_device *ethosudev) ethosudev->npu_info.id = id = readl_relaxed(ethosudev->regs + NPU_REG_ID); ethosudev->npu_info.config = config = readl_relaxed(ethosudev->regs + NPU_REG_CONFIG); - ethosu_sram_init(ethosudev); + ret = ethosu_sram_init(ethosudev); + if (ret) + goto err_runtime_suspend; dev_info(ethosudev->base.dev, "Ethos-U NPU, arch v%ld.%ld.%ld, rev r%ldp%ld, cmd stream ver%ld, %d MACs, %dKB SRAM\n", @@ -346,6 +348,9 @@ static int ethosu_init(struct ethosu_device *ethosudev) return 0; +err_runtime_suspend: + ethosu_runtime_suspend(ethosudev); + return ret; err_suspend: pm_runtime_dont_use_autosuspend(ethosudev->base.dev); ethosu_device_suspend(ethosudev->base.dev); -- 2.43.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 4/5] accel/ethosu: propagate SRAM initialization errors 2026-07-17 6:11 ` [PATCH v2 4/5] accel/ethosu: propagate SRAM initialization errors GuoHan Zhao @ 2026-07-17 6:24 ` sashiko-bot 0 siblings, 0 replies; 11+ messages in thread From: sashiko-bot @ 2026-07-17 6:24 UTC (permalink / raw) To: GuoHan Zhao; +Cc: dri-devel Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: Pre-existing issues: - [High] Unsafe hardware access in shared IRQ handler without Runtime PM check. - [High] Missing synchronize_irq() in runtime suspend callback. - [High] SRAM is allocated but left uninitialized during probe, leading to potential use of uninitialized memory. -- --- Patch [4]: [PATCH v2 4/5] accel/ethosu: propagate SRAM initialization errors --- commit 4382c986c5c63a85ef8db5d2db6b39f2605d7154 Author: GuoHan Zhao <zhaoguohan@kylinos.cn> accel/ethosu: propagate SRAM initialization errors ethosu_sram_init() returns -ENOMEM if allocation from a declared SRAM pool fails. ethosu_init() ignores the error after recording the pool size. Probe then registers a device with a nonzero SRAM size and a zero sramphys address, allowing jobs to program address zero for SRAM. Propagate the error and synchronously suspend the device before the probe path releases the scheduler. Link: https://sashiko.dev/#/patchset/20260716065219.931088-1-zhaoguohan@kylinos.cn?part=1 > diff --git a/drivers/accel/ethosu/ethosu_drv.c b/drivers/accel/ethosu/ethosu_drv.c > index 6b97d22444a7c..c825b67e9cba0 100644 > --- a/drivers/accel/ethosu/ethosu_drv.c > +++ b/drivers/accel/ethosu/ethosu_drv.c > @@ -331,7 +331,9 @@ static int ethosu_init(struct ethosu_device *ethosudev) > ethosudev->npu_info.id = id = readl_relaxed(ethosudev->regs + NPU_REG_ID); > ethosudev->npu_info.config = config = readl_relaxed(ethosudev->regs + NPU_REG_CONFIG); > > - ethosu_sram_init(ethosudev); > + ret = ethosu_sram_init(ethosudev); > + if (ret) > + goto err_runtime_suspend; [Severity: High] This is a pre-existing issue, but is the SRAM left uninitialized during the first active window after probe? Earlier in ethosu_init(), we call ethosu_device_resume(), which attempts to zero the SRAM via ethosu_reset(). However, since ethosu_sram_init() hasn't run yet, SRAM isn't allocated and zeroing is skipped. If a job is submitted within the 50ms autosuspend delay window after probe finishes, pm_runtime_resume_and_get() will increment the usage counter but skip ethosu_device_resume() since the device is already active. Does this mean the first job could run with uninitialized garbage data in the SRAM, leading to unpredictable hardware behavior? > > dev_info(ethosudev->base.dev, > "Ethos-U NPU, arch v%ld.%ld.%ld, rev r%ldp%ld, cmd stream ver%ld, %d MACs, %dKB SRAM\n", [ ... ] > @@ -346,6 +348,9 @@ static int ethosu_init(struct ethosu_device *ethosudev) > > return 0; > > +err_runtime_suspend: > + ethosu_runtime_suspend(ethosudev); > + return ret; > err_suspend: > pm_runtime_dont_use_autosuspend(ethosudev->base.dev); > ethosu_device_suspend(ethosudev->base.dev); [Severity: High] This is a pre-existing issue, but does ethosu_device_suspend() need to call synchronize_irq() before disabling the clocks? Looking at ethosu_device_suspend(), it calls clk_bulk_disable_unprepare() directly without synchronizing with the interrupt handler: drivers/accel/ethosu/ethosu_drv.c:ethosu_device_suspend() { struct ethosu_device *ethosudev = dev_get_drvdata(dev); clk_bulk_disable_unprepare(ethosudev->num_clks, ethosudev->clks); return 0; } If the autosuspend timer expires and ethosu_device_suspend() executes while an interrupt is mid-flight on another CPU, could the clocks be disabled while the IRQ handler is actively accessing hardware registers, resulting in a bus fault? [Severity: High] This is a pre-existing issue, but is it safe for ethosu_job_irq_handler() to access hardware registers without checking if the device is active? When the device enters runtime suspend and its clocks are disabled, a different device sharing the same IRQ line could trigger an interrupt. The ethosu_job_irq_handler() unconditionally reads NPU_REG_STATUS: drivers/accel/ethosu/ethosu_job.c:ethosu_job_irq_handler() { ... u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS); ... } Without calling pm_runtime_get_if_active() to check if the device is active first, could this lead to a bus fault and kernel panic if the device is suspended and unclocked? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260717061145.1478139-1-zhaoguohan@kylinos.cn?part=4 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 5/5] accel/ethosu: fix job completion fence cleanup 2026-07-17 6:11 [PATCH v2 0/5] accel/ethosu: fix probe and job cleanup errors GuoHan Zhao ` (3 preceding siblings ...) 2026-07-17 6:11 ` [PATCH v2 4/5] accel/ethosu: propagate SRAM initialization errors GuoHan Zhao @ 2026-07-17 6:11 ` GuoHan Zhao 2026-07-17 6:22 ` sashiko-bot 4 siblings, 1 reply; 11+ messages in thread From: GuoHan Zhao @ 2026-07-17 6:11 UTC (permalink / raw) To: Rob Herring (Arm), Tomeu Vizoso, dri-devel Cc: Oded Gabbay, Thomas Zimmermann, Frank Li ethosu_ioctl_submit_job() allocates done_fence before validating buffer handles. Errors after allocation call ethosu_job_err_cleanup(), which frees the job but leaks the uninitialized fence. A scheduler dependency error also lets ethosu_job_run() return before dma_fence_init(). Normal cleanup then passes a zeroed refcount to dma_fence_put(). Release done_fence in the common cleanup path and use dma_fence_was_initialized() to distinguish initialized fences from raw allocations. Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver") Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260716065219.931088-1-zhaoguohan@kylinos.cn?part=1 Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> --- Changes in v2: - Renumber from patch 3/3 to 5/5; no code changes. Sashiko reports: > drivers/accel/ethosu/ethosu_job.c:ethosu_job_err_cleanup() { > unsigned int i; > > for (i = 0; i < job->region_cnt; i++) > drm_gem_object_put(job->region_bo[i]); > > drm_gem_object_put(job->cmd_bo); > > kfree(job); > } > > This is a pre-existing issue, but was not introduced by this patch. > > ethosu_ioctl_submit_job() allocates done_fence. If a subsequent > validation fails, the error path calls ethosu_job_err_cleanup(). > > This function frees the job structure but misses freeing job->done_fence. > > Can an unprivileged user repeatedly call the submit ioctl with invalid > handles to trigger a done_fence leak? > drivers/accel/ethosu/ethosu_job.c:ethosu_job_run() { > ... > if (unlikely(job->base.s_fence->finished.error)) > return NULL; > > dma_fence_init(fence, ðosu_fence_ops, &dev->fence_lock, > dev->fence_context, ++dev->emit_seqno); > ... > } > > This is a pre-existing issue, but was not introduced by this patch. > > If job->base.s_fence->finished.error is true, the function returns early > without calling dma_fence_init() on job->done_fence. > > When the job is later destroyed, ethosu_job_cleanup() unconditionally > calls dma_fence_put() on the fence: > > drivers/accel/ethosu/ethosu_job.c:ethosu_job_cleanup() { > ... > dma_fence_put(job->done_fence); > ... > } > > Since the fence is zero-initialized, will calling kref_put() on it > violate the API and cause a refcount underflow? drivers/accel/ethosu/ethosu_job.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c index 5847433e87e7..b68a905d22f8 100644 --- a/drivers/accel/ethosu/ethosu_job.c +++ b/drivers/accel/ethosu/ethosu_job.c @@ -152,6 +152,13 @@ static void ethosu_job_err_cleanup(struct ethosu_job *job) drm_gem_object_put(job->cmd_bo); + if (job->done_fence) { + if (dma_fence_was_initialized(job->done_fence)) + dma_fence_put(job->done_fence); + else + dma_fence_free(job->done_fence); + } + kfree(job); } @@ -162,7 +169,6 @@ static void ethosu_job_cleanup(struct kref *ref) pm_runtime_put_autosuspend(job->dev->base.dev); - dma_fence_put(job->done_fence); dma_fence_put(job->inference_done_fence); ethosu_job_err_cleanup(job); -- 2.43.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 5/5] accel/ethosu: fix job completion fence cleanup 2026-07-17 6:11 ` [PATCH v2 5/5] accel/ethosu: fix job completion fence cleanup GuoHan Zhao @ 2026-07-17 6:22 ` sashiko-bot 0 siblings, 0 replies; 11+ messages in thread From: sashiko-bot @ 2026-07-17 6:22 UTC (permalink / raw) To: GuoHan Zhao; +Cc: dri-devel Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: Pre-existing issues: - [High] Calling drm_sched_job_cleanup() on an uninitialized struct drm_sched_job causes a NULL pointer dereference in the ethosu_ioctl_submit_job() error path. - [High] The shared IRQ handler accesses hardware registers without ensuring the device is active via Runtime PM, and the suspend callback fails to synchronize IRQs, risking fatal bus faults. -- --- Patch [5]: [PATCH v2 5/5] accel/ethosu: fix job completion fence cleanup --- commit b390c1806154d7460d3ff212d56c250283785f11 Author: GuoHan Zhao <zhaoguohan@kylinos.cn> Subject: accel/ethosu: fix job completion fence cleanup This commit addresses memory leaks and refcount underflows in the Ethos-U NPU driver's job cleanup path. It ensures that the done_fence is properly released during error cleanup and uses dma_fence_was_initialized() to handle raw allocations gracefully. Link: https://sashiko.dev/#/patchset/20260716065219.931088-1-zhaoguohan@kylinos.cn?part=1 > diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c > index 5847433e87e7e..b68a905d22f83 100644 > --- a/drivers/accel/ethosu/ethosu_job.c > +++ b/drivers/accel/ethosu/ethosu_job.c > @@ -152,6 +152,13 @@ static void ethosu_job_err_cleanup(struct ethosu_job *job) > > drm_gem_object_put(job->cmd_bo); > > + if (job->done_fence) { > + if (dma_fence_was_initialized(job->done_fence)) > + dma_fence_put(job->done_fence); > + else > + dma_fence_free(job->done_fence); > + } > + > kfree(job); > } > [Severity: High] This is a pre-existing issue, but was not introduced by this patch. When the done_fence allocation fails in ethosu_ioctl_submit_job(), it jumps to out_cleanup_job: drivers/accel/ethosu/ethosu_job.c:ethosu_ioctl_submit_job() { ... if (!ejob->done_fence) { ret = -ENOMEM; goto out_cleanup_job; } ... out_cleanup_job: if (ret) drm_sched_job_cleanup(&ejob->base); } Because drm_sched_job_init() was not called yet, ejob->base is completely zero-initialized, meaning ejob->base.s_fence is NULL. When drm_sched_job_cleanup() attempts to read the refcount: drivers/gpu/drm/scheduler/sched_main.c:drm_sched_job_cleanup() { ... if (kref_read(&job->s_fence->finished.refcount)) { ... } Will this result in a NULL pointer dereference because the function assumes job->s_fence is a valid pointer? [Severity: High] This isn't a bug introduced by this patch, but there appears to be an issue with how shared interrupts interact with runtime PM. The NPU interrupt is registered with the IRQF_SHARED flag: drivers/accel/ethosu/ethosu_job.c:ethosu_job_init() { ... ret = devm_request_threaded_irq(dev, edev->irq, ethosu_job_irq_handler, ethosu_job_irq_handler_thread, IRQF_SHARED, KBUILD_MODNAME, edev); ... } If another device sharing the IRQ line triggers an interrupt while the NPU is runtime-suspended, the handler executes and reads MMIO registers: drivers/accel/ethosu/ethosu_job.c:ethosu_job_irq_handler() { ... u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS); if (!(status & STATUS_IRQ_RAISED)) return IRQ_NONE; ... } Could this unconditionally read registers without verifying the device's PM state via pm_runtime_get_if_active()? Furthermore, the runtime suspend callback disables clocks: drivers/accel/ethosu/ethosu_drv.c:ethosu_device_suspend() { ... clk_bulk_disable_unprepare(ethosudev->num_clks, ethosudev->clks); return 0; } Since this doesn't call synchronize_irq() to wait for executing handlers, could concurrent IRQ execution cause invalid hardware writes or a bus fault when accessing powered-off MMIO registers? > @@ -162,7 +169,6 @@ static void ethosu_job_cleanup(struct kref *ref) > > pm_runtime_put_autosuspend(job->dev->base.dev); > > - dma_fence_put(job->done_fence); > dma_fence_put(job->inference_done_fence); > > ethosu_job_err_cleanup(job); -- Sashiko AI review · https://sashiko.dev/#/patchset/20260717061145.1478139-1-zhaoguohan@kylinos.cn?part=5 ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-07-17 6:27 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-17 6:11 [PATCH v2 0/5] accel/ethosu: fix probe and job cleanup errors GuoHan Zhao 2026-07-17 6:11 ` [PATCH v2 1/5] accel/ethosu: check DMA mask setup GuoHan Zhao 2026-07-17 6:23 ` sashiko-bot 2026-07-17 6:11 ` [PATCH v2 2/5] accel/ethosu: fix scheduler and IRQ lifetime GuoHan Zhao 2026-07-17 6:24 ` sashiko-bot 2026-07-17 6:11 ` [PATCH v2 3/5] accel/ethosu: clean up resources on probe failure GuoHan Zhao 2026-07-17 6:27 ` sashiko-bot 2026-07-17 6:11 ` [PATCH v2 4/5] accel/ethosu: propagate SRAM initialization errors GuoHan Zhao 2026-07-17 6:24 ` sashiko-bot 2026-07-17 6:11 ` [PATCH v2 5/5] accel/ethosu: fix job completion fence cleanup GuoHan Zhao 2026-07-17 6:22 ` sashiko-bot
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.