Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7652afa authored by Thomas Hellstrom's avatar Thomas Hellstrom
Browse files

drm/vmwgfx: Type-check lookups of fence objects



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.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: default avatarSinclair Yeh <syeh@vmware.com>
parent d64a0472
Loading
Loading
Loading
Loading
+50 −27
Original line number Diff line number Diff line
@@ -701,6 +701,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,
			     struct drm_file *file_priv)
{
@@ -726,13 +761,9 @@ int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
		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);

@@ -771,13 +802,9 @@ int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
	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);
@@ -1024,6 +1051,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
		(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;
@@ -1037,15 +1065,11 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
	 */
	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);
@@ -1053,7 +1077,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
		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 "
@@ -1097,8 +1121,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
	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;