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

Reply via email to