dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ryan Brue" <ryanbrue.dev@gmail.com>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v3 2/4] drm/imagination: unplug the device before tearing it down in pvr_remove()
Date: Mon, 14 Sep 2026 02:27:05 +0000	[thread overview]
Message-ID: <20260914022706.68C811F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260913-rbrue-suez-upstreaming-pvr-suspend-gpu-system-sleep-v3-2-674b907d0652@gmail.com>

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

New issues:
- [High] TOCTOU race on `pvr_dev->lost` in `pvr_remove()` allows a double `drm_dev_unplug()` execution, causing a kernel oops.

Pre-existing issues:
- [Critical] Deadlock caused by calling `drm_dev_unplug()` from within a `drm_dev_enter()` SRCU read critical section via `pvr_device_lost()`.
- [Critical] Incorrect teardown ordering in `pvr_remove()` destroys firmware memory before stopping asynchronous workers (DRM schedulers), leading to Use-After-Free.
- [High] Missing `drm_dev_enter()` guards in teardown ioctls invalidate the commit's core synchronization assumption.
--

commit 3adf692930871afc287c13c7680a8b09a7c0ad9e
Author: Ryan Brue <ryanbrue.dev@gmail.com>

drm/imagination: unplug the device before tearing it down in pvr_remove()

This commit reorders the teardown sequence in pvr_remove() to call
drm_dev_unplug() before destroying the job and free list xarrays, powering
down the GPU, and running pvr_device_fini(). It skips the unplug if
pvr_device_lost() has already performed it.

Fixes: 1f88f017e649 ("drm/imagination: Get GPU resources")
Fixes: 727538a4bbff ("drm/imagination: Implement power management")
Cc: stable@vger.kernel.org

> diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c
> index 5c965ef0274ff..fc92a82a72084 100644
> --- a/drivers/gpu/drm/imagination/pvr_drv.c
> +++ b/drivers/gpu/drm/imagination/pvr_drv.c
> @@ -1469,15 +1469,23 @@ static void pvr_remove(struct platform_device *plat_dev)
>  	struct drm_device *drm_dev = platform_get_drvdata(plat_dev);
>  	struct pvr_device *pvr_dev = to_pvr_device(drm_dev);
>  
> +	/*
> +	 * Unplug before freeing anything, so no ioctl is still inside
> +	 * drm_dev_enter(). pvr_device_lost() may already have done it, and

[Severity: Critical]
This is a pre-existing issue, but does calling drm_dev_unplug() from
pvr_device_lost() introduce a potential self-deadlock when triggered from
an MMU flush?

Looking at pvr_mmu_flush_exec(), it acquires the SRCU read lock via
drm_dev_enter(). If the flush times out, it attempts recovery and calls
pvr_device_lost(), which subsequently triggers drm_dev_unplug() and its
internal synchronize_srcu():

drivers/gpu/drm/imagination/pvr_mmu.c:pvr_mmu_flush_exec() {
        if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx))
                return -EIO;
        ...
        /* On timeout calls pvr_power_reset() or pvr_device_lost() */
}

Since synchronize_srcu() waits indefinitely for all SRCU readers to exit, and
the calling thread itself holds the read lock, won't it hang forever waiting
for its own completion?

> +	 * drm_dev_unplug() is not idempotent.
> +	 */
> +	if (!pvr_dev->lost)
> +		drm_dev_unplug(drm_dev);

[Severity: High]
Is this vulnerable to a time-of-check to time-of-use race with
pvr_power_reset() and pvr_device_lost()?

If pvr_remove() runs on the unbind path and evaluates !pvr_dev->lost as true,
could it be preempted before calling drm_dev_unplug()?

Concurrently, if an asynchronous context like a DRM scheduler timeout triggers
pvr_power_reset(), it would call pvr_device_lost(). Because the flag isn't set
yet, pvr_device_lost() would also evaluate !pvr_dev->lost as true, set the
flag, and execute drm_dev_unplug():

drivers/gpu/drm/imagination/pvr_power.c:pvr_device_lost() {
        if (!pvr_dev->lost) {
                pvr_dev->lost = true;
                drm_dev_unplug(from_pvr_device(pvr_dev));
        }
}

When pvr_remove() resumes, wouldn't it execute drm_dev_unplug() a second time,
causing a kernel oops inside drm_client_sysrq_unregister() since
drm_dev_unplug() is not idempotent?

[Severity: High]
This is a pre-existing issue, but does this unplug actually synchronize with
all ioctls as intended?

While this patch relies on drm_dev_unplug() to wait for in-flight ioctls via
drm_dev_enter() and drm_dev_exit(), some teardown ioctls appear to lack these
guards entirely.

For example, in pvr_ioctl_destroy_context():

drivers/gpu/drm/imagination/pvr_drv.c:pvr_ioctl_destroy_context() {
        ...
        return pvr_context_destroy(pvr_file, args->handle);
}

And in pvr_ioctl_vm_unmap():

drivers/gpu/drm/imagination/pvr_drv.c:pvr_ioctl_vm_unmap() {
        ...
        err = pvr_vm_unmap(vm_ctx, args->device_addr, args->size);
        ...
}

Since these ioctls bypass the drm_dev_enter() check, couldn't userspace
execute them concurrently during or after the unplug, interacting with
hardware queues via pvr_queue_cleanup_fw_context() after pvr_remove() has
already freed them?

[ ... ]

>  	xa_destroy(&pvr_dev->job_ids);
>  	xa_destroy(&pvr_dev->free_list_ids);
>  
> -	pm_runtime_suspend(drm_dev->dev);
>  	pvr_device_fini(pvr_dev);
> -	drm_dev_unplug(drm_dev);
>  	pvr_watchdog_fini(pvr_dev);
>  	pvr_queue_device_fini(pvr_dev);

[Severity: Critical]
This is a pre-existing issue, but does the ordering here tear down firmware
memory before stopping asynchronous workers?

When pvr_device_fini() is called, it tears down hardware components and frees
firmware memory such as pvr_dev->fw_dev. However, the DRM scheduler threads
executing on pvr_dev->sched_wq are not stopped until pvr_queue_device_fini()
is called later.

Couldn't drm_sched concurrently execute pvr_queue_run_job() while or after the
firmware memory is freed, leading to a use-after-free when it accesses that
memory to submit KCCB commands?

Note that while a subsequent patch in the series moves pvr_watchdog_fini(),
the DRM scheduler teardown issue appears to remain unresolved here.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260913-rbrue-suez-upstreaming-pvr-suspend-gpu-system-sleep-v3-0-674b907d0652@gmail.com?part=2

  reply	other threads:[~2026-09-14  2:27 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-14  2:09 [PATCH v3 0/4] drm/imagination: fix system suspend, and the callback design underneath it Ryan Brue
2026-09-14  2:09 ` [PATCH v3 1/4] drm/imagination: don't gate the runtime PM callbacks on drm_dev_enter() Ryan Brue
2026-09-14  2:29   ` sashiko-bot
2026-09-14  2:09 ` [PATCH v3 2/4] drm/imagination: unplug the device before tearing it down in pvr_remove() Ryan Brue
2026-09-14  2:27   ` sashiko-bot [this message]
2026-09-14  2:09 ` [PATCH v3 3/4] drm/imagination: stop the watchdog before tearing the device down Ryan Brue
2026-09-14  2:34   ` sashiko-bot
2026-09-14  2:09 ` [PATCH v3 4/4] drm/imagination: suspend the GPU for system sleep, not just runtime PM Ryan Brue
2026-09-14  2:25   ` sashiko-bot

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=20260914022706.68C811F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=ryanbrue.dev@gmail.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /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