Commit ed528923 authored by Thomas Hellstrom's avatar Thomas Hellstrom Committed by Greg Kroah-Hartman

drm/vmwgfx: Type-check lookups of fence objects

commit f7652afa 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: default avatarThomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: default avatarSinclair Yeh <syeh@vmware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8f8ee970
...@@ -539,7 +539,7 @@ int vmw_fence_create(struct vmw_fence_manager *fman, ...@@ -539,7 +539,7 @@ int vmw_fence_create(struct vmw_fence_manager *fman,
struct vmw_fence_obj **p_fence) struct vmw_fence_obj **p_fence)
{ {
struct vmw_fence_obj *fence; struct vmw_fence_obj *fence;
int ret; int ret;
fence = kzalloc(sizeof(*fence), GFP_KERNEL); fence = kzalloc(sizeof(*fence), GFP_KERNEL);
if (unlikely(fence == NULL)) if (unlikely(fence == NULL))
...@@ -702,6 +702,41 @@ void vmw_fence_fifo_up(struct vmw_fence_manager *fman) ...@@ -702,6 +702,41 @@ void vmw_fence_fifo_up(struct vmw_fence_manager *fman)
} }
/**
* 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, int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
...@@ -727,13 +762,9 @@ int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data, ...@@ -727,13 +762,9 @@ int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
arg->kernel_cookie = jiffies + wait_timeout; arg->kernel_cookie = jiffies + wait_timeout;
} }
base = ttm_base_object_lookup(tfile, arg->handle); base = vmw_fence_obj_lookup(tfile, arg->handle);
if (unlikely(base == NULL)) { if (IS_ERR(base))
printk(KERN_ERR "Wait invalid fence object handle " return PTR_ERR(base);
"0x%08lx.\n",
(unsigned long)arg->handle);
return -EINVAL;
}
fence = &(container_of(base, struct vmw_user_fence, base)->fence); fence = &(container_of(base, struct vmw_user_fence, base)->fence);
...@@ -772,13 +803,9 @@ int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data, ...@@ -772,13 +803,9 @@ int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
struct vmw_private *dev_priv = vmw_priv(dev); struct vmw_private *dev_priv = vmw_priv(dev);
base = ttm_base_object_lookup(tfile, arg->handle); base = vmw_fence_obj_lookup(tfile, arg->handle);
if (unlikely(base == NULL)) { if (IS_ERR(base))
printk(KERN_ERR "Fence signaled invalid fence object handle " return PTR_ERR(base);
"0x%08lx.\n",
(unsigned long)arg->handle);
return -EINVAL;
}
fence = &(container_of(base, struct vmw_user_fence, base)->fence); fence = &(container_of(base, struct vmw_user_fence, base)->fence);
fman = fman_from_fence(fence); fman = fman_from_fence(fence);
...@@ -1093,6 +1120,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, ...@@ -1093,6 +1120,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
(struct drm_vmw_fence_event_arg *) data; (struct drm_vmw_fence_event_arg *) data;
struct vmw_fence_obj *fence = NULL; struct vmw_fence_obj *fence = NULL;
struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); 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 *user_fence_rep =
(struct drm_vmw_fence_rep __user *)(unsigned long) (struct drm_vmw_fence_rep __user *)(unsigned long)
arg->fence_rep; arg->fence_rep;
...@@ -1106,15 +1134,11 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, ...@@ -1106,15 +1134,11 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
*/ */
if (arg->handle) { if (arg->handle) {
struct ttm_base_object *base = struct ttm_base_object *base =
ttm_base_object_lookup_for_ref(dev_priv->tdev, vmw_fence_obj_lookup(tfile, arg->handle);
arg->handle);
if (IS_ERR(base))
if (unlikely(base == NULL)) { return PTR_ERR(base);
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, fence = &(container_of(base, struct vmw_user_fence,
base)->fence); base)->fence);
(void) vmw_fence_obj_reference(fence); (void) vmw_fence_obj_reference(fence);
...@@ -1122,7 +1146,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, ...@@ -1122,7 +1146,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
if (user_fence_rep != NULL) { if (user_fence_rep != NULL) {
bool existed; bool existed;
ret = ttm_ref_object_add(vmw_fp->tfile, base, ret = ttm_ref_object_add(tfile, base,
TTM_REF_USAGE, &existed); TTM_REF_USAGE, &existed);
if (unlikely(ret != 0)) { if (unlikely(ret != 0)) {
DRM_ERROR("Failed to reference a fence " DRM_ERROR("Failed to reference a fence "
...@@ -1166,8 +1190,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, ...@@ -1166,8 +1190,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
return 0; return 0;
out_no_create: out_no_create:
if (user_fence_rep != NULL) if (user_fence_rep != NULL)
ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE);
handle, TTM_REF_USAGE);
out_no_ref_obj: out_no_ref_obj:
vmw_fence_obj_unreference(&fence); vmw_fence_obj_unreference(&fence);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment