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

Pre-existing issues:
- [High] The IRQ is requested and enabled before the DRM scheduler is fully 
initialized and before device clocks are enabled, causing potential crashes or 
bus stalls on spurious/pending interrupts.
- [High] The DRM scheduler is torn down while the device IRQ is still active, 
allowing the IRQ handler to access destroyed scheduler structures.
- [High] `ethosu_job_fini()` clears the `in_flight_job` without signaling its 
`done_fence`, causing tasks waiting on the fence to hang indefinitely.
- [High] Use-After-Free during device removal due to missing 
`drm_dev_enter()`/`drm_dev_exit()` in ioctls.
--

commit cee294332b061aafaf416ab459f70a84d756797f
Author: Rob Herring (Arm) <[email protected]>

accel: ethosu: Fix probe error cleanup
    
This commit fixes a probe error path bug in the Ethos-U NPU driver.
If ethosu_init() or drm_dev_register() fails, the probe function returns
without tearing down the job scheduler or freeing the SRAM pool.
The commit adds proper resource unwinding for these failure paths.

Cc: [email protected]

> diff --git a/drivers/accel/ethosu/ethosu_drv.c 
> b/drivers/accel/ethosu/ethosu_drv.c
> index 1f6fb5d18cf22..2c8d735767b2a 100644
> --- a/drivers/accel/ethosu/ethosu_drv.c
> +++ b/drivers/accel/ethosu/ethosu_drv.c
> @@ -375,9 +375,20 @@ static int ethosu_probe(struct platform_device *pdev)
>  
>       ret = ethosu_init(ethosudev);
>       if (ret)
> -             return ret;
> +             goto err_job_fini;

[Severity: High]
This is a pre-existing issue, but does calling ethosu_job_init() before
ethosu_init() leave us vulnerable to spurious interrupts?

In ethosu_probe(), the IRQ is requested and enabled via
devm_request_threaded_irq() (without IRQF_NO_AUTOEN) during
ethosu_job_init(). However, device clocks are not enabled until
ethosu_init() runs.

If a pending or spurious interrupt fires immediately before clocks are enabled:

ethosu_job_irq_handler() {
    u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS);
    ...
}

Can reading from memory-mapped registers with disabled clocks stall the bus
or cause a synchronous external abort? Furthermore, if the thread handler
executes, it calls drm_sched_fault() on a scheduler that may not be fully
initialized yet.

>       ret = drm_dev_register(&ethosudev->base, 0);
> +     if (ret)
> +             goto err_sram_free;
> +
> +     return 0;
> +
> +err_sram_free:
> +     if (ethosudev->sram)
> +             gen_pool_free(ethosudev->srampool, (unsigned 
> long)ethosudev->sram,
> +                           ethosudev->npu_info.sram_size);
> +err_job_fini:
> +     ethosu_job_fini(ethosudev);

[Severity: High]
This is a pre-existing issue, but does calling ethosu_job_fini() here tear
down the scheduler while the device IRQ is still active?

ethosu_job_fini() calls synchronize_irq() to wait for executing handlers,
but does not disable the IRQ line before calling drm_sched_fini().

Because the IRQ is managed by devres, it remains enabled until devres
teardown, which happens after the probe error path completes. If the device
generates an interrupt in this window, the thread handler can execute:

ethosu_job_handle_irq() {
    ...
    drm_sched_fault(&dev->sched);
}

Could this result in a use-after-free by accessing the already-destroyed
DRM scheduler?

[Severity: High]
This is also a pre-existing issue, but does ethosu_job_fini() clear the
in-flight job without signaling its completion fence?

When ethosu_job_fini() checks READ_ONCE(dev->in_flight_job), if it is
populated, it clears the pointer and resets the hardware:

ethosu_job_fini() {
    ...
    if (READ_ONCE(dev->in_flight_job)) {
        WRITE_ONCE(dev->in_flight_job, NULL);
        ethosu_device_reset(dev);
    }
    ...
}

Because the hardware is reset, the completion interrupt will never arrive.
Without extracting the job and signaling its done_fence (e.g., with
-ECANCELED), could this cause userspace or kernel tasks waiting on the
fence to hang indefinitely during probe failure or driver unbind?

>       return ret;
>  }
>  
> diff --git a/drivers/accel/ethosu/ethosu_job.c 
> b/drivers/accel/ethosu/ethosu_job.c
> index 8dce74db0cb48..ec65305e0cd7d 100644
> --- a/drivers/accel/ethosu/ethosu_job.c
> +++ b/drivers/accel/ethosu/ethosu_job.c

[ ... ]

> @@ -355,14 +355,10 @@ int ethosu_job_init(struct ethosu_device *edev)
>       ret = drm_sched_init(&edev->sched, &args);
>       if (ret) {
>               dev_err(dev, "Failed to create scheduler: %d\n", ret);
> -             goto err_sched;
> +             return ret;
>       }
>  
>       return 0;
> -
> -err_sched:
> -     drm_sched_fini(&edev->sched);
> -     return ret;
>  }

[Severity: High]
This isn't a bug introduced by this patch, but are the driver's ioctls
missing drm_dev_enter() and drm_dev_exit() protections?

During a hot-unplug event, ethosu_remove() calls drm_dev_unregister(),
which stops new opens but allows existing file descriptors to persist. It
then tears down the DRM scheduler via ethosu_job_fini().

However, ethosu_ioctl_submit() and the ETHOSU_PERFMON_* ioctls do not verify
the device plug state. A concurrent userspace process holding the file
descriptor can still issue the ETHOSU_SUBMIT ioctl:

ethosu_ioctl_submit_job() {
    ...
    ret = drm_sched_job_init(&ejob->base, &file_priv->sched_entity, ...);
    ...
}

Can this lead to a use-after-free if userspace calls into the DRM scheduler
after dev->sched has been destroyed during device removal?

-- 
Sashiko AI review ยท 
https://sashiko.dev/#/patchset/[email protected]?part=3

Reply via email to