dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Jonghyuk Kim(MalHyuk)" <malhyuk97@gmail.com>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v4 1/3] drm/sched: cache the timeline name to fix a use-after-free
Date: Fri, 04 Sep 2026 08:18:28 +0000	[thread overview]
Message-ID: <20260904081829.67C321F00A3D@smtp.kernel.org> (raw)
In-Reply-To: <20260904080618.2098450-2-malhyuk97@gmail.com>

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

New issues:
- [High] The patch attempts to fix a Use-After-Free by caching the timeline name in `fence->sched_name`, but it introduces a direct Use-After-Free of the string memory itself. The commit message incorrectly assumes all drivers pass a string literal or keep the string alive via RCU. However, `panthor` dynamically allocates the timeline name (`kasprintf`) and synchronously frees it (`kfree(queue->name)`) when the queue is destroyed. Furthermore, for `xe`, `kfree_rcu` does not protect against a `sync_file` fd held open by userspace for an arbitrary duration (userspace holding an fd does not equate to holding an RCU read lock). When userspace queries the fence info via the `SYNC_IOC_FILE_INFO` ioctl after the string is freed, `drm_sched_fence_get_timeline_name()` returns the cached pointer to the freed memory, leading to an info leak to userspace.

Pre-existing issues:
- [High] The AMDGPU driver's `amdgpu_sync_same_dev()` function incorrectly assumes that any `drm_sched_fence` belongs to an AMDGPU ring. `to_drm_sched_fence()` returns non-NULL for *any* DRM scheduler fence globally (e.g., from `panthor`, `xe`, `nouveau`). If a foreign fence is passed via a `dma-buf` or `syncobj`, `amdgpu_sync_same_dev()` unconditionally calculates `ring = container_of(s_fence->sched, struct amdgpu_ring, sched)` and dereferences `ring->adev`. This results in an out-of-bounds read (Type Confusion). Additionally, if the foreign fence originated from a per-context scheduler that has been freed (like a destroyed `panthor` queue), this results in a Use-After-Free read.
- [High] The PowerVR driver's `pvr_queue_fence_is_native()` accesses `sched_fence->sched->ops` to determine if a fence is native to the driver. However, if the `drm_sched_fence` originated from a per-context scheduler (whether from `pvr` or another driver like `panthor`) and that scheduler has been destroyed, `sched_fence->sched` is a dangling pointer. Dereferencing it to check `->ops` causes a Use-After-Free read.
--

commit 99163b915ba8e6d549d23c04536ae0f2ac030b70
Author: Jonghyuk Kim(MalHyuk) <malhyuk97@gmail.com>

drm/sched: cache the timeline name to fix a use-after-free

This commit caches the scheduler's timeline name inside drm_sched_fence to
prevent a use-after-free when a userspace-held finished fence outlives a
per-context scheduler. It documents that the name must outlive the fence,
assuming all in-tree drivers pass string literals or keep the name alive.

>     Every in-tree driver passes a string literal, which satisfies this;

[Severity: High]
Is this assumption correct for all in-tree drivers?

For example, panthor dynamically allocates the timeline name and synchronously
frees it when the queue is destroyed:

drivers/gpu/drm/panthor/panthor_sched.c:group_free_queue() {
    ...
    kfree(queue->name);
    ...
}

If a user creates a panthor queue, submits a job to get a fence, exports it
to a sync_file, and destroys the queue, the string memory is freed. When
userspace then queries the fence info via the SYNC_IOC_FILE_INFO ioctl,
wouldn't the cached pointer point to freed memory, leading to an info leak?

> diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c
> index 096fe28aa9c9e..b2a842a1c9ba9 100644
> --- a/drivers/gpu/drm/scheduler/sched_fence.c
> +++ b/drivers/gpu/drm/scheduler/sched_fence.c
> @@ -92,7 +92,13 @@ static const char *drm_sched_fence_get_driver_name(struct dma_fence *fence)
>  static const char *drm_sched_fence_get_timeline_name(struct dma_fence *f)
>  {
>  	struct drm_sched_fence *fence = to_drm_sched_fence(f);
> -	return (const char *)fence->sched->name;
> +
> +	/*
> +	 * Do not dereference fence->sched here: a userspace-held finished
> +	 * fence can outlive a per-context scheduler. Return the name cached
> +	 * in drm_sched_fence_init() instead.
> +	 */
> +	return fence->sched_name;

[Severity: High]
Does returning this cached pointer just replace the scheduler use-after-free
with a string memory use-after-free?

Because drivers like panthor can free the string memory synchronously during
queue destruction, this cached pointer will point to freed memory when read
by the caller.

[ ... ]

> @@ -228,6 +242,14 @@ void drm_sched_fence_init(struct drm_sched_fence *fence,
>  	unsigned seq;
>  
>  	fence->sched = entity->rq->sched;
> +	/*
> +	 * Cache the scheduler's timeline name. The finished fence may be
> +	 * exported to userspace and outlive @sched (per-context schedulers are
> +	 * freed on context teardown), so get_timeline_name() must not
> +	 * dereference @sched. The name is required to outlive any exported
> +	 * fence (see @name in struct drm_sched_init_args).
> +	 */
> +	fence->sched_name = fence->sched->name;

[Severity: High]
Does caching the string pointer here without taking ownership or extending
its lifetime erroneously assume the string will inherently outlive the fence?

This is a pre-existing issue, but the dangling fence->sched pointer causes
problems in other drivers as well when foreign fences are imported.

[Severity: High]
Does the AMDGPU driver's amdgpu_sync_same_dev() incorrectly assume any
drm_sched_fence globally belongs to an AMDGPU ring?

drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c:amdgpu_sync_same_dev() {
    ...
    ring = container_of(s_fence->sched, struct amdgpu_ring, sched);
    return ring->adev == adev;
}

If a foreign fence from another driver (e.g., panthor) is passed via a dma-buf
or syncobj and used as an input dependency to the AMDGPU command submission
ioctl, this unconditional container_of() calculation will dereference an
invalid or freed pointer. Can this lead to an out-of-bounds type confusion
read, or a use-after-free read if the original per-context scheduler was
already destroyed?

This is also a pre-existing issue, but similar to the AMDGPU issue above,
does the PowerVR driver also dereference a freed scheduler pointer?

[Severity: High]
drivers/gpu/drm/imagination/pvr_queue.c:pvr_queue_fence_is_native() {
    ...
    if (sched_fence &&
        sched_fence->sched->ops == &pvr_queue_sched_ops)
    ...
}

If a user exports a drm_sched_fence from a queue, destroys that queue (freeing
the scheduler), and then passes the fence as an input dependency to the PVR
job submission ioctl, sched_fence->sched will be a dangling pointer. Will
dereferencing it to check the ops field cause a use-after-free read?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260904080618.2098450-1-malhyuk97@gmail.com?part=1

  reply	other threads:[~2026-09-04  8:18 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-04  8:06 [PATCH v4 0/3] drm/sched: fix use-after-free of the fence timeline name Jonghyuk Kim(MalHyuk)
2026-09-04  8:06 ` [PATCH v4 1/3] drm/sched: cache the timeline name to fix a use-after-free Jonghyuk Kim(MalHyuk)
2026-09-04  8:18   ` sashiko-bot [this message]
2026-09-04  8:20   ` Christian König
2026-09-04  8:31     ` Philipp Stanner
2026-09-04 12:49       ` Christian König
2026-09-04 19:06         ` Philipp Stanner
2026-09-04  8:31     ` Jonghyuk Kim(MalHyuk)
2026-09-04  8:39       ` Philipp Stanner
2026-09-04  9:11         ` Jonghyuk Kim(MalHyuk)
2026-09-04  9:07       ` Tvrtko Ursulin
2026-09-04  9:57   ` Danilo Krummrich
2026-09-04 10:51     ` Philipp Stanner
2026-09-04  8:06 ` [PATCH v4 2/3] drm/sched: add the fence ops-detach cleanup to the TODO list Jonghyuk Kim(MalHyuk)
2026-09-04  8:06 ` [PATCH v4 3/3] drm/sched/tests: add a UAF regression test for the timeline name Jonghyuk Kim(MalHyuk)
2026-09-04  8:15   ` 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=20260904081829.67C321F00A3D@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=malhyuk97@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