| From f7652afa8eadb416b23eb57dec6f158529942041 Mon Sep 17 00:00:00 2001 |
| From: Thomas Hellstrom <thellstrom@vmware.com> |
| Date: Mon, 27 Mar 2017 11:09:08 +0200 |
| Subject: drm/vmwgfx: Type-check lookups of fence objects |
| |
| From: Thomas Hellstrom <thellstrom@vmware.com> |
| |
| commit f7652afa8eadb416b23eb57dec6f158529942041 upstream. |
| |
| A malicious caller could otherwise hand over handles to other objects |
| causing all sorts of interesting problems. |
| |
| Testing done: Ran a Fedora 25 desktop using both Xorg and |
| gnome-shell/Wayland. |
| |
| Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> |
| Reviewed-by: Sinclair Yeh <syeh@vmware.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 75 ++++++++++++++++++++++------------ |
| 1 file changed, 49 insertions(+), 26 deletions(-) |
| |
| --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c |
| +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c |
| @@ -539,7 +539,7 @@ int vmw_fence_create(struct vmw_fence_ma |
| struct vmw_fence_obj **p_fence) |
| { |
| struct vmw_fence_obj *fence; |
| - int ret; |
| + int ret; |
| |
| fence = kzalloc(sizeof(*fence), GFP_KERNEL); |
| if (unlikely(fence == NULL)) |
| @@ -702,6 +702,41 @@ void vmw_fence_fifo_up(struct vmw_fence_ |
| } |
| |
| |
| +/** |
| + * vmw_fence_obj_lookup - Look up a user-space fence object |
| + * |
| + * @tfile: A struct ttm_object_file identifying the caller. |
| + * @handle: A handle identifying the fence object. |
| + * @return: A struct vmw_user_fence base ttm object on success or |
| + * an error pointer on failure. |
| + * |
| + * The fence object is looked up and type-checked. The caller needs |
| + * to have opened the fence object first, but since that happens on |
| + * creation and fence objects aren't shareable, that's not an |
| + * issue currently. |
| + */ |
| +static struct ttm_base_object * |
| +vmw_fence_obj_lookup(struct ttm_object_file *tfile, u32 handle) |
| +{ |
| + struct ttm_base_object *base = ttm_base_object_lookup(tfile, handle); |
| + |
| + if (!base) { |
| + pr_err("Invalid fence object handle 0x%08lx.\n", |
| + (unsigned long)handle); |
| + return ERR_PTR(-EINVAL); |
| + } |
| + |
| + if (base->refcount_release != vmw_user_fence_base_release) { |
| + pr_err("Invalid fence object handle 0x%08lx.\n", |
| + (unsigned long)handle); |
| + ttm_base_object_unref(&base); |
| + return ERR_PTR(-EINVAL); |
| + } |
| + |
| + return base; |
| +} |
| + |
| + |
| int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data, |
| struct drm_file *file_priv) |
| { |
| @@ -727,13 +762,9 @@ int vmw_fence_obj_wait_ioctl(struct drm_ |
| arg->kernel_cookie = jiffies + wait_timeout; |
| } |
| |
| - base = ttm_base_object_lookup(tfile, arg->handle); |
| - if (unlikely(base == NULL)) { |
| - printk(KERN_ERR "Wait invalid fence object handle " |
| - "0x%08lx.\n", |
| - (unsigned long)arg->handle); |
| - return -EINVAL; |
| - } |
| + base = vmw_fence_obj_lookup(tfile, arg->handle); |
| + if (IS_ERR(base)) |
| + return PTR_ERR(base); |
| |
| fence = &(container_of(base, struct vmw_user_fence, base)->fence); |
| |
| @@ -772,13 +803,9 @@ int vmw_fence_obj_signaled_ioctl(struct |
| struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
| struct vmw_private *dev_priv = vmw_priv(dev); |
| |
| - base = ttm_base_object_lookup(tfile, arg->handle); |
| - if (unlikely(base == NULL)) { |
| - printk(KERN_ERR "Fence signaled invalid fence object handle " |
| - "0x%08lx.\n", |
| - (unsigned long)arg->handle); |
| - return -EINVAL; |
| - } |
| + base = vmw_fence_obj_lookup(tfile, arg->handle); |
| + if (IS_ERR(base)) |
| + return PTR_ERR(base); |
| |
| fence = &(container_of(base, struct vmw_user_fence, base)->fence); |
| fman = fman_from_fence(fence); |
| @@ -1093,6 +1120,7 @@ int vmw_fence_event_ioctl(struct drm_dev |
| (struct drm_vmw_fence_event_arg *) data; |
| struct vmw_fence_obj *fence = NULL; |
| struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); |
| + struct ttm_object_file *tfile = vmw_fp->tfile; |
| struct drm_vmw_fence_rep __user *user_fence_rep = |
| (struct drm_vmw_fence_rep __user *)(unsigned long) |
| arg->fence_rep; |
| @@ -1106,15 +1134,11 @@ int vmw_fence_event_ioctl(struct drm_dev |
| */ |
| if (arg->handle) { |
| struct ttm_base_object *base = |
| - ttm_base_object_lookup_for_ref(dev_priv->tdev, |
| - arg->handle); |
| + vmw_fence_obj_lookup(tfile, arg->handle); |
| + |
| + if (IS_ERR(base)) |
| + return PTR_ERR(base); |
| |
| - if (unlikely(base == NULL)) { |
| - DRM_ERROR("Fence event invalid fence object handle " |
| - "0x%08lx.\n", |
| - (unsigned long)arg->handle); |
| - return -EINVAL; |
| - } |
| fence = &(container_of(base, struct vmw_user_fence, |
| base)->fence); |
| (void) vmw_fence_obj_reference(fence); |
| @@ -1122,7 +1146,7 @@ int vmw_fence_event_ioctl(struct drm_dev |
| if (user_fence_rep != NULL) { |
| bool existed; |
| |
| - ret = ttm_ref_object_add(vmw_fp->tfile, base, |
| + ret = ttm_ref_object_add(tfile, base, |
| TTM_REF_USAGE, &existed); |
| if (unlikely(ret != 0)) { |
| DRM_ERROR("Failed to reference a fence " |
| @@ -1166,8 +1190,7 @@ int vmw_fence_event_ioctl(struct drm_dev |
| return 0; |
| out_no_create: |
| if (user_fence_rep != NULL) |
| - ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, |
| - handle, TTM_REF_USAGE); |
| + ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); |
| out_no_ref_obj: |
| vmw_fence_obj_unreference(&fence); |
| return ret; |