vmw_dumb_create(), called from DRM_IOCTL_MODE_CREATE_DUMB, drops its
extra GEM reference on the vbo before it reads vbo->dumb_surface and
clears the user surface's refcount_release. After that put, the only
reference left is held by the GEM handle, which is already visible to
userspace. A concurrent DRM_IOCTL_GEM_CLOSE on that handle can drop it
and free the vbo (and the dumb surface) while vmw_dumb_create() is
still using them:
CPU0 (DRM_IOCTL_MODE_CREATE_DUMB) CPU1 (DRM_IOCTL_GEM_CLOSE)
vmw_dumb_create()
vmw_gb_surface_define_ext_ioctl()
/* vbo refcount == 2 */
drm_gem_object_put(&vbo->tbo.base)
/* vbo refcount == 1 */
drm_gem_close_ioctl()
drm_gem_handle_delete()
drm_gem_object_release_handle()
drm_gem_object_handle_put_unlocked()
drm_gem_object_put()
/* vbo refcount == 0 */
vmw_gem_object_free()
ttm_bo_fini()
vmw_bo_free()
vmw_surface_unreference()
kfree(vbo)
usurf = container_of(vbo->dumb_surface, ...) /* UAF read */
usurf->prime.base.refcount_release = NULL /* UAF write */
Move drm_gem_object_put() after the last access to the vbo.
Fixes: f42c09e614f1 ("drm/vmwgfx: Fix dumb buffer leak")
Signed-off-by: Jayapal Ashwin Nair <[email protected]>
---
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index bd0563741e89..2dfbd914bdef 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -2332,7 +2332,6 @@ int vmw_dumb_create(struct drm_file *file_priv,
vbo = res->guest_memory_bo;
vbo->is_dumb = true;
vbo->dumb_surface = vmw_res_to_srf(res);
- drm_gem_object_put(&vbo->tbo.base);
/*
* Unset the user surface dtor since this in not actually exposed
* to userspace. The suface is owned via the dumb_buffer's GEM handle
@@ -2340,6 +2339,7 @@ int vmw_dumb_create(struct drm_file *file_priv,
struct vmw_user_surface *usurf = container_of(vbo->dumb_surface,
struct vmw_user_surface, srf);
usurf->prime.base.refcount_release = NULL;
+ drm_gem_object_put(&vbo->tbo.base);
err:
if (res)
vmw_resource_unreference(&res);
--
2.53.0