[PATCH 2/2] drm/nouveau/uvmm: reject a second VM_INIT
Junrui Luo via B4 Relay <[email protected]>
| Newsgroups | org.freedesktop.lists.nouveau,org.freedesktop.lists.dri-devel,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
From: Junrui Luo <[email protected]> nouveau_uvmm_ioctl_vm_init() sets up the GPU VA space for a drm_file and is reachable from an unprivileged render node client (DRM_RENDER_ALLOW). After the cli->uvmm.disabled check it unconditionally allocates a nouveau_uvmm, initialises its drm_gpuvm and region maple tree, creates the backing nvif vmm and overwrites cli->uvmm.ptr, without testing whether one already exists. Calling DRM_IOCTL_NOUVEAU_VM_INIT twice therefore drops the previous nouveau_uvmm with no remaining reference to it: drm_gpuvm_put() is reached only from nouveau_uvmm_fini(), which nouveau_cli_fini() calls once on whatever cli->uvmm.ptr holds at close time. The orphaned nouveau_uvmm, its drm_gpuvm, that gpuvm's reservation GEM object and its region maple tree are never freed, buffer objects mapped in it stay pinned by the orphaned uvmas, and its nvif vmm keeps the GPU page directories allocated until the file is closed, so repeating the ioctl leaks kernel memory without bound. Test cli->uvmm.ptr under cli->mutex before anything is allocated and return -EBUSY, mirroring nouveau_svmm_init(). Fixes: b88baab82871 ("drm/nouveau: implement new VM_BIND uAPI") Reported-by: Yuhao Jiang <[email protected]> Assisted-by: Claude:claude-opus-5 Cc: [email protected] Signed-off-by: Junrui Luo <[email protected]> --- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index bced1481674e..26d2a57b5aac 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1929,6 +1929,12 @@ nouveau_uvmm_ioctl_vm_init(struct drm_device *dev, goto out_unlock; } + /* Check that a GPU VA space isn't already set up for the client. */ + if (cli->uvmm.ptr) { + ret = -EBUSY; + goto out_unlock; + } + uvmm = kzalloc_obj(*uvmm); if (!uvmm) { ret = -ENOMEM; -- 2.51.2