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

Pre-existing issues:
- [High] Race condition in nouveau_fence_context_del between cancel_work_sync 
and nvif_event_dtor leads to use-after-free of fctx.
- [High] Missing cancel_work_sync for irq_work in nouveau_connector_destroy 
leads to use-after-free of the connector.
--

--- Patch [1]: [PATCH v4 1/3] drm/nouveau: unsubscribe the channel-kill event 
before the fence context ---
commit 4ae9b89defb4e27bc74c023fe090b6ae974e3378
Author: Marek Czernohous <[email protected]>

drm/nouveau: unsubscribe the channel-kill event before the fence context

nouveau_channel_del() tears the fence context down first and only drops
the channel-kill subscription later, which can cause a use-after-free
if a kill event is delivered in that window. This patch drops the
subscription before anything it depends on is torn down.

> diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c 
> b/drivers/gpu/drm/nouveau/nouveau_chan.c
> index 598513f604493..f142f63105966 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_chan.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
> @@ -90,6 +90,14 @@ nouveau_channel_del(struct nouveau_channel **pchan)
>  {
>       struct nouveau_channel *chan = *pchan;
>       if (chan) {
> +             /*
> +              * Drop the kill-event subscription first.  Its handler
> +              * dereferences chan->fence, which the fence context teardown
> +              * below frees, so leaving it armed across the teardown leaves
> +              * a window for a use-after-free.
> +              */
> +             nvif_event_dtor(&chan->kill);
> +
>               if (chan->fence)
>                       nouveau_fence(chan->cli->drm)->context_del(chan);
>  
[ ... ]
> @@ -100,7 +108,6 @@ nouveau_channel_del(struct nouveau_channel **pchan)
>               nvif_object_dtor(&chan->nvsw);
>               nvif_object_dtor(&chan->gart);
>               nvif_object_dtor(&chan->vram);
> -             nvif_event_dtor(&chan->kill);
>               nvif_object_dtor(&chan->user);
>               nvif_mem_dtor(&chan->mem_userd);
>               nouveau_vma_del(&chan->sema.vma);

[Severity: High]
This isn't a bug introduced by this patch, but looking at similar teardown
paths, is there a race condition in nouveau_fence_context_del() between
cancel_work_sync() and nvif_event_dtor()?

drivers/gpu/drm/nouveau/nouveau_fence.c:nouveau_fence_context_del() {
        ...
        cancel_work_sync(&fctx->uevent_work);
        nouveau_fence_context_kill(fctx, 0);
        nvif_event_dtor(&fctx->event);
        ...
}

If a hardware interrupt fires in the narrow window after cancel_work_sync()
but before nvif_event_dtor(), could the event handler schedule the work
again?

The work would remain pending on the workqueue while fctx is subsequently
freed, leading to a use-after-free when the work executes.


[Severity: High]
This is another pre-existing issue in a similar teardown path, but is there a
missing cancel_work_sync() for irq_work in nouveau_connector_destroy()?

drivers/gpu/drm/nouveau/nouveau_connector.c:nouveau_connector_destroy() {
        ...
        nvif_event_dtor(&nv_connector->irq);
        nvif_event_dtor(&nv_connector->hpd);
        kfree(nv_connector->edid);
        drm_connector_unregister(connector);
        ...
}

When a connector is destroyed, it calls nvif_event_dtor() to unregister the
hardware event, but does not appear to call cancel_work_sync() for
nv_connector->irq_work.

If an IRQ fires right before the event is destroyed, the handler schedules
irq_work:

drivers/gpu/drm/nouveau/nouveau_connector.c:nouveau_connector_irq() {
        ...
        schedule_work(&nv_connector->irq_work);
        return NVIF_EVENT_KEEP;
}

Because the work is never canceled, will it eventually execute on freed
memory after the connector has been freed?

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

Reply via email to