lkml.org 
[lkml]   [2015]   [Nov]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.1 80/86] drm/vmwgfx: Fix up user_dmabuf refcounting
    Date
    4.1-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Thomas Hellstrom <thellstrom@vmware.com>

    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.

    Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
    Reviewed-by: Brian Paul <brianp@vmware.com>
    Reviewed-by: Sinclair Yeh <syeh@vmware.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    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(-)

    --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
    +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
    @@ -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);

    --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
    +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
    @@ -636,7 +636,8 @@ extern int vmw_user_dmabuf_alloc(struct
    uint32_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,
    --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
    +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
    @@ -887,7 +887,8 @@ static int vmw_translate_mob_ptr(struct
    struct 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(struc
    struct 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;
    --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
    +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
    @@ -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;

    --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
    +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
    @@ -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_pri
    uint32_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(struct
    struct 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(struct

    switch (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_de
    return 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_file
    struct 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;

    --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
    +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
    @@ -470,7 +470,7 @@ int vmw_shader_define_ioctl(struct drm_d

    if (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");
    --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
    +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
    @@ -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_releas
    struct 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 d

    if (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);



    \
     
     \ /
      Last update: 2015-11-06 21:01    [W:4.212 / U:0.108 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site