Patch "drm/vmwgfx: Fix up user_dmabuf refcounting" has been added to the 4.1-stable tree
Subsystems (4)
This is a note to let you know that I've just added the patch titled
drm/vmwgfx: Fix up user_dmabuf refcounting
to the 4.1-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
drm-vmwgfx-fix-up-user_dmabuf-refcounting.patch
and it can be found in the queue-4.1 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
54c12bc374408faddbff75dbf1a6167c19af39c4Mon Sep 17 00:00:00 2001
From: Thomas Hellstrom <[email protected]>
Date: Mon, 14 Sep 2015 01:13:11 -0700
Subject: drm/vmwgfx: Fix up user_dmabuf refcounting
From: Thomas Hellstrom <[email protected]>
commit 54c12bc374408faddbff75dbf1a6167c19af39c4 upstream.
If user space calls unreference on a user_dmabuf it will typically kill the struct ttm_base_object member which is responsible for the user-space visibility. However the dmabuf part may still be alive and refcounted. In some situations, like for shared guest-backed surface referencing/opening, the driver may try to reference the struct ttm_base_object member again, causing an immediate kernel warning and a later kernel NULL pointer dereference.
Fix this by always maintaining a reference on the struct ttm_base_object member, in situations where it might subsequently be referenced.
--- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 3 +++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 ++++-- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 6 ++++-- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 29 +++++++++++++++++++++-------- drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 12 +++++++++--- 7 files changed, 43 insertions(+), 17 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +3 -0
@@ -1458,6 +1458,9 @@ static void __exit vmwgfx_exit(void)drm_pci_exit (&driver, &vmw_pci_driver); } +MODULE_INFO (vmw_patch,"ed7d78b2" ); +MODULE_INFO (vmw_patch,"54c12bc3" ); +module_init (vmwgfx_init);module_exit (vmwgfx_exit);
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +4 -2
@@ -636,7 +636,8 @@ extern int vmw_user_dmabuf_alloc(structuint32_t size, bool shareable, uint32_t *handle, - struct vmw_dma_buffer **p_dma_buf); + struct vmw_dma_buffer **p_dma_buf, + struct ttm_base_object **p_base);extern int vmw_user_dmabuf_reference (struct ttm_object_file *tfile,struct vmw_dma_buffer *dma_buf,uint32_t *handle);
@@ -650,7 +651,8 @@ extern uint32_t vmw_dmabuf_validate_node uint32_t cur_validate_node);extern void vmw_dmabuf_validate_clear (struct ttm_buffer_object *bo);extern int vmw_user_dmabuf_lookup (struct ttm_object_file *tfile, -uint32_t id,struct vmw_dma_buffer **out); +uint32_t id,struct vmw_dma_buffer **out, +struct ttm_base_object **base);extern int vmw_stream_claim_ioctl (struct drm_device *dev,void *data,struct drm_file *file_priv); extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +4 -2
@@ -887,7 +887,8 @@ static int vmw_translate_mob_ptr(structstruct vmw_relocation *reloc;int ret; - ret =vmw_user_dmabuf_lookup (sw_context->fp->tfile, handle, &vmw_bo); + ret =vmw_user_dmabuf_lookup (sw_context->fp->tfile, handle, &vmw_bo, +NULL );if (unlikely (ret !=0 )) {DRM_ERROR ("Could not find or use MOB buffer.\n" ); ret = -EINVAL ;
@@ -949,7 +950,8 @@ static int vmw_translate_guest_ptr(strucstruct vmw_relocation *reloc;int ret; - ret =vmw_user_dmabuf_lookup (sw_context->fp->tfile, handle, &vmw_bo); + ret =vmw_user_dmabuf_lookup (sw_context->fp->tfile, handle, &vmw_bo, +NULL );if (unlikely (ret !=0 )) {DRM_ERROR ("Could not find or use GMR region.\n" ); ret = -EINVAL ;
drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +1 -1
@@ -484,7 +484,7 @@ int vmw_overlay_ioctl(struct drm_device goto out_unlock; } - ret =vmw_user_dmabuf_lookup (tfile, arg->handle, &buf); + ret =vmw_user_dmabuf_lookup (tfile, arg->handle, &buf,NULL );if (ret) goto out_unlock;
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +21 -8
@@ -356,7 +356,7 @@ int vmw_user_lookup_handle(struct vmw_pr } *out_surf =NULL ; - ret =vmw_user_dmabuf_lookup (tfile, handle, out_buf); + ret =vmw_user_dmabuf_lookup (tfile, handle, out_buf,NULL );return ret; }
@@ -483,7 +483,8 @@ int vmw_user_dmabuf_alloc(struct vmw_priuint32_t size, bool shareable, uint32_t *handle, - struct vmw_dma_buffer **p_dma_buf) + struct vmw_dma_buffer **p_dma_buf, + struct ttm_base_object **p_base) { struct vmw_user_dma_buffer *user_bo;struct ttm_buffer_object *tmp;
@@ -517,6 +518,10 @@ int vmw_user_dmabuf_alloc(struct vmw_pri } *p_dma_buf = &user_bo->dma; +if (p_base) { + *p_base = &user_bo->prime.base; +kref_get (&(*p_base)->refcount); + } *handle = user_bo->prime.base.hash.key; out_no_base_object:
@@ -633,6 +638,7 @@ int vmw_user_dmabuf_synccpu_ioctl(structstruct vmw_dma_buffer *dma_buf;struct vmw_user_dma_buffer *user_bo;struct ttm_object_file *tfile =vmw_fpriv (file_priv)->tfile; +struct ttm_base_object *buffer_base;int ret; if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0
@@ -645,7 +651,8 @@ int vmw_user_dmabuf_synccpu_ioctl(structswitch (arg->op) {case drm_vmw_synccpu_grab: - ret =vmw_user_dmabuf_lookup (tfile, arg->handle, &dma_buf); + ret =vmw_user_dmabuf_lookup (tfile, arg->handle, &dma_buf, + &buffer_base);if (unlikely (ret !=0 ))return ret;
@@ -653,6 +660,7 @@ int vmw_user_dmabuf_synccpu_ioctl(struct dma); ret =vmw_user_dmabuf_synccpu_grab (user_bo, tfile, arg->flags);vmw_dmabuf_unreference (&dma_buf); +ttm_base_object_unref (&buffer_base);if (unlikely (ret !=0 && ret != -ERESTARTSYS && ret != -EBUSY )) { DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n",
@@ -694,7 +702,8 @@ int vmw_dmabuf_alloc_ioctl(struct drm_dereturn ret; ret =vmw_user_dmabuf_alloc (dev_priv,vmw_fpriv (file_priv)->tfile, - req->size, false, &handle, &dma_buf); + req->size, false, &handle, &dma_buf, +NULL );if (unlikely (ret !=0 )) goto out_no_dmabuf;
@@ -723,7 +732,8 @@ int vmw_dmabuf_unref_ioctl(struct drm_de }int vmw_user_dmabuf_lookup (struct ttm_object_file *tfile, -uint32_t handle,struct vmw_dma_buffer **out) +uint32_t handle,struct vmw_dma_buffer **out, +struct ttm_base_object **p_base) {struct vmw_user_dma_buffer *vmw_user_bo;struct ttm_base_object *base;
@@ -745,7 +755,10 @@ int vmw_user_dmabuf_lookup(struct ttm_ob vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, prime.base); (void )ttm_bo_reference (&vmw_user_bo->dma.base); -ttm_base_object_unref (&base); +if (p_base) + *p_base = base; +else +ttm_base_object_unref (&base); *out = &vmw_user_bo->dma;return 0 ;
@@ -1006,7 +1019,7 @@ int vmw_dumb_create(struct drm_file *fil ret =vmw_user_dmabuf_alloc (dev_priv,vmw_fpriv (file_priv)->tfile, args->size, false, &args->handle, - &dma_buf); + &dma_buf,NULL );if (unlikely (ret !=0 )) goto out_no_dmabuf;
@@ -1034,7 +1047,7 @@ int vmw_dumb_map_offset(struct drm_filestruct vmw_dma_buffer *out_buf;int ret; - ret =vmw_user_dmabuf_lookup (tfile, handle, &out_buf); + ret =vmw_user_dmabuf_lookup (tfile, handle, &out_buf,NULL );if (ret !=0 )return -EINVAL ;
drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +1 -1
@@ -470,7 +470,7 @@ int vmw_shader_define_ioctl(struct drm_dif (arg->buffer_handle !=SVGA3D_INVALID_ID ) { ret =vmw_user_dmabuf_lookup (tfile, arg->buffer_handle, - &buffer); + &buffer,NULL );if (unlikely (ret !=0 )) {DRM_ERROR ("Could not find buffer for shader " "creation.\n" );
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +9 -3
@@ -43,6 +43,7 @@ struct vmw_user_surface {struct vmw_surface srf;uint32_t size;struct drm_master *master; +struct ttm_base_object *backup_base; };/**
@@ -652,6 +653,8 @@ static void vmw_user_surface_base_releasstruct vmw_resource *res = &user_srf->srf.res; *p_base =NULL ; +if (user_srf->backup_base) +ttm_base_object_unref (&user_srf->backup_base);vmw_resource_unreference (&res); }
@@ -846,7 +849,8 @@ int vmw_surface_define_ioctl(struct drm_ res->backup_size, true, &backup_handle, - &res->backup); + &res->backup, + &user_srf->backup_base);if (unlikely (ret !=0 )) {vmw_resource_unreference (&res); goto out_unlock;
@@ -1309,7 +1313,8 @@ int vmw_gb_surface_define_ioctl(struct dif (req->buffer_handle !=SVGA3D_INVALID_ID ) { ret =vmw_user_dmabuf_lookup (tfile, req->buffer_handle, - &res->backup); + &res->backup, + &user_srf->backup_base); }else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer) ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
@@ -1317,7 +1322,8 @@ int vmw_gb_surface_define_ioctl(struct d req->drm_surface_flags & drm_vmw_surface_flag_shareable, &backup_handle, - &res->backup); + &res->backup, + &user_srf->backup_base);if (unlikely (ret !=0 )) {vmw_resource_unreference (&res);
Patches currently in stable-queue which might be from [email protected] are
queue-4.1/drm-vmwgfx-fix-up-user_dmabuf-refcounting.patch