* [PATCH] drm/nouveau: disable VM_BIND once a legacy BO VMA is created
@ 2026-08-13 10:24 Zhenhao Wan
2026-08-13 10:40 ` sashiko-bot
0 siblings, 1 reply; 2+ messages in thread
From: Zhenhao Wan @ 2026-08-13 10:24 UTC (permalink / raw)
To: Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dave Airlie
Cc: dri-devel, nouveau, linux-kernel, Yuhao Jiang, stable,
Zhenhao Wan
nouveau_gem_object_open() creates a legacy per-client VMA when the client
has not initialised VM_BIND (!nouveau_cli_uvmm()), but
nouveau_gem_object_close() only tears it down while the client is still not
a VM_BIND client ("if (nouveau_cli_uvmm(cli)) return;").
nouveau_gem_ioctl_new() calls nouveau_cli_disable_uvmm_noinit() to stop a
client mixing the legacy and VM_BIND uAPIs, but the prime-import and flink
GEM_OPEN paths that also run nouveau_gem_object_open() do not. A client can
thus open an object (creating a legacy VMA), call NOUVEAU_VM_INIT, then
close the handle: close() now returns early and leaks the VMA. If the BO is
flink-shared it outlives the client's freed vmm, and the next migration
walks nvbo->vma_list in nouveau_bo_move_ntfy() and dereferences the stale
vma->vmm -- a use-after-free.
Disable VM_BIND in nouveau_gem_object_open() as nouveau_gem_ioctl_new()
does; the helper is a no-op once VM_BIND is initialised, so VM_BIND-first
clients are unaffected.
Fixes: b88baab82871 ("drm/nouveau: implement new VM_BIND uAPI")
Reported-by: Yuhao Jiang <danisjiang@gmail.com>
Assisted-by: Claude:claude-opus-5
Cc: stable@vger.kernel.org
Signed-off-by: Zhenhao Wan <whi4ed0g@gmail.com>
---
drivers/gpu/drm/nouveau/nouveau_gem.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 20dba02d6175..e33f76b5a239 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -108,6 +108,14 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50)
return 0;
+ /*
+ * Opening the object binds it through the legacy per-VMA path below.
+ * Disable VM_BIND for this client, as nouveau_gem_ioctl_new() does, so
+ * a later NOUVEAU_VM_INIT cannot switch the client to uvmm and leave
+ * nouveau_gem_object_close() unable to tear this VMA down.
+ */
+ nouveau_cli_disable_uvmm_noinit(cli);
+
if (nvbo->no_share && uvmm &&
drm_gpuvm_resv(&uvmm->base) != nvbo->bo.base.resv)
return -EPERM;
---
base-commit: db2ddb87143519e20a95aa36c60b36107b736a58
change-id: 20260813-nouveau-gem-uvmm-vma-fix-8d0fbac454b9
Best regards,
--
Zhenhao Wan <whi4ed0g@gmail.com>
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] drm/nouveau: disable VM_BIND once a legacy BO VMA is created
2026-08-13 10:24 [PATCH] drm/nouveau: disable VM_BIND once a legacy BO VMA is created Zhenhao Wan
@ 2026-08-13 10:40 ` sashiko-bot
0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-08-13 10:40 UTC (permalink / raw)
To: Zhenhao Wan; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] A time-of-check to time-of-use (TOCTOU) race condition in `nouveau_gem_object_open()` allows a VM_BIND client to bypass the `NOUVEAU_GEM_DOMAIN_NO_SHARE` restriction and open exclusive buffers.
- [High] Unprivileged userspace can trigger a massive memory and GPU resource leak by repeatedly calling the `NOUVEAU_VM_INIT` ioctl.
--
--- Patch [1]: [PATCH] drm/nouveau: disable VM_BIND once a legacy BO VMA is created ---
commit f241cc2db54abcee53ca3ff7b4e2aadd6db117dd
Author: Zhenhao Wan <whi4ed0g@gmail.com>
drm/nouveau: disable VM_BIND once a legacy BO VMA is created
This commit fixes a use-after-free issue where a legacy per-client VMA could
be leaked if a client initializes VM_BIND after opening an object. It calls
nouveau_cli_disable_uvmm_noinit() in nouveau_gem_object_open() to disable
VM_BIND for clients creating legacy VMAs.
> diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
> index 20dba02d6175b..e33f76b5a2398 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_gem.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
> @@ -108,6 +108,14 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
> if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50)
> return 0;
>
> + /*
> + * Opening the object binds it through the legacy per-VMA path below.
> + * Disable VM_BIND for this client, as nouveau_gem_ioctl_new() does, so
> + * a later NOUVEAU_VM_INIT cannot switch the client to uvmm and leave
> + * nouveau_gem_object_close() unable to tear this VMA down.
> + */
> + nouveau_cli_disable_uvmm_noinit(cli);
> +
> if (nvbo->no_share && uvmm &&
> drm_gpuvm_resv(&uvmm->base) != nvbo->bo.base.resv)
> return -EPERM;
[Severity: High]
This is a pre-existing issue, but does this function have a time-of-check to
time-of-use race condition involving the cached uvmm pointer?
The uvmm pointer is cached without locks at the start of
nouveau_gem_object_open():
struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(cli);
If a client guesses the flink name of a no_share buffer, calls GEM_OPEN, and
concurrently calls NOUVEAU_VM_INIT:
CPU1 calls NOUVEAU_VM_INIT and sets cli->uvmm.ptr
CPU2 in nouveau_gem_object_open():
struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(cli); /* caches NULL */
...
nouveau_cli_disable_uvmm_noinit(cli); /* locks and disables */
if (nvbo->no_share && uvmm &&
drm_gpuvm_resv(&uvmm->base) != nvbo->bo.base.resv)
return -EPERM;
Can NOUVEAU_VM_INIT complete after uvmm is cached as NULL but before
nouveau_cli_disable_uvmm_noinit() acquires the lock?
If so, the no_share condition would be evaluated using the stale NULL pointer,
bypassing the restriction and allowing a client to map an exclusive buffer
belonging to another VM into its own GPU VM. Should uvmm be reloaded after
taking the lock or before the check?
[Severity: High]
This isn't a bug introduced by this patch, but can unprivileged userspace
trigger a massive memory and GPU resource leak through the VM_BIND ioctl?
Looking at nouveau_uvmm_ioctl_vm_init() in
drivers/gpu/drm/nouveau/nouveau_uvmm.c:
uvmm = kzalloc_obj(*uvmm);
if (!uvmm) {
ret = -ENOMEM;
goto out_unlock;
}
...
cli->uvmm.ptr = uvmm;
If an attacker repeatedly calls DRM_IOCTL_NOUVEAU_VM_INIT on a single DRM file
descriptor, does this ioctl handler lack a check to see if cli->uvmm.ptr is
already initialized?
It appears to unconditionally allocate a new struct nouveau_uvmm and overwrite
cli->uvmm.ptr. Does this permanently leak the previously allocated structures
and GPU page tables, potentially leading to a local denial of service?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260813-nouveau-gem-uvmm-vma-fix-v1-1-4f14d427f2c9@gmail.com?part=1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-13 10:40 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-13 10:24 [PATCH] drm/nouveau: disable VM_BIND once a legacy BO VMA is created Zhenhao Wan
2026-08-13 10:40 ` 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.