diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2017-03-27 05:09:08 -0400 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2017-03-30 05:42:54 -0400 |
commit | f7652afa8eadb416b23eb57dec6f158529942041 (patch) | |
tree | b96ae6140a414f7eb0577da2c6b20270ff3483f8 | |
parent | d64a04720b0e64c1cd0726a3a27b360822fbee22 (diff) |
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: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 6541dd8b82dc..4076063e0fdd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | |||
@@ -538,7 +538,7 @@ int vmw_fence_create(struct vmw_fence_manager *fman, | |||
538 | struct vmw_fence_obj **p_fence) | 538 | struct vmw_fence_obj **p_fence) |
539 | { | 539 | { |
540 | struct vmw_fence_obj *fence; | 540 | struct vmw_fence_obj *fence; |
541 | int ret; | 541 | int ret; |
542 | 542 | ||
543 | fence = kzalloc(sizeof(*fence), GFP_KERNEL); | 543 | fence = kzalloc(sizeof(*fence), GFP_KERNEL); |
544 | if (unlikely(fence == NULL)) | 544 | if (unlikely(fence == NULL)) |
@@ -701,6 +701,41 @@ void vmw_fence_fifo_up(struct vmw_fence_manager *fman) | |||
701 | } | 701 | } |
702 | 702 | ||
703 | 703 | ||
704 | /** | ||
705 | * vmw_fence_obj_lookup - Look up a user-space fence object | ||
706 | * | ||
707 | * @tfile: A struct ttm_object_file identifying the caller. | ||
708 | * @handle: A handle identifying the fence object. | ||
709 | * @return: A struct vmw_user_fence base ttm object on success or | ||
710 | * an error pointer on failure. | ||
711 | * | ||
712 | * The fence object is looked up and type-checked. The caller needs | ||
713 | * to have opened the fence object first, but since that happens on | ||
714 | * creation and fence objects aren't shareable, that's not an | ||
715 | * issue currently. | ||
716 | */ | ||
717 | static struct ttm_base_object * | ||
718 | vmw_fence_obj_lookup(struct ttm_object_file *tfile, u32 handle) | ||
719 | { | ||
720 | struct ttm_base_object *base = ttm_base_object_lookup(tfile, handle); | ||
721 | |||
722 | if (!base) { | ||
723 | pr_err("Invalid fence object handle 0x%08lx.\n", | ||
724 | (unsigned long)handle); | ||
725 | return ERR_PTR(-EINVAL); | ||
726 | } | ||
727 | |||
728 | if (base->refcount_release != vmw_user_fence_base_release) { | ||
729 | pr_err("Invalid fence object handle 0x%08lx.\n", | ||
730 | (unsigned long)handle); | ||
731 | ttm_base_object_unref(&base); | ||
732 | return ERR_PTR(-EINVAL); | ||
733 | } | ||
734 | |||
735 | return base; | ||
736 | } | ||
737 | |||
738 | |||
704 | int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data, | 739 | int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data, |
705 | struct drm_file *file_priv) | 740 | struct drm_file *file_priv) |
706 | { | 741 | { |
@@ -726,13 +761,9 @@ int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data, | |||
726 | arg->kernel_cookie = jiffies + wait_timeout; | 761 | arg->kernel_cookie = jiffies + wait_timeout; |
727 | } | 762 | } |
728 | 763 | ||
729 | base = ttm_base_object_lookup(tfile, arg->handle); | 764 | base = vmw_fence_obj_lookup(tfile, arg->handle); |
730 | if (unlikely(base == NULL)) { | 765 | if (IS_ERR(base)) |
731 | printk(KERN_ERR "Wait invalid fence object handle " | 766 | return PTR_ERR(base); |
732 | "0x%08lx.\n", | ||
733 | (unsigned long)arg->handle); | ||
734 | return -EINVAL; | ||
735 | } | ||
736 | 767 | ||
737 | fence = &(container_of(base, struct vmw_user_fence, base)->fence); | 768 | fence = &(container_of(base, struct vmw_user_fence, base)->fence); |
738 | 769 | ||
@@ -771,13 +802,9 @@ int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data, | |||
771 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | 802 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
772 | struct vmw_private *dev_priv = vmw_priv(dev); | 803 | struct vmw_private *dev_priv = vmw_priv(dev); |
773 | 804 | ||
774 | base = ttm_base_object_lookup(tfile, arg->handle); | 805 | base = vmw_fence_obj_lookup(tfile, arg->handle); |
775 | if (unlikely(base == NULL)) { | 806 | if (IS_ERR(base)) |
776 | printk(KERN_ERR "Fence signaled invalid fence object handle " | 807 | return PTR_ERR(base); |
777 | "0x%08lx.\n", | ||
778 | (unsigned long)arg->handle); | ||
779 | return -EINVAL; | ||
780 | } | ||
781 | 808 | ||
782 | fence = &(container_of(base, struct vmw_user_fence, base)->fence); | 809 | fence = &(container_of(base, struct vmw_user_fence, base)->fence); |
783 | fman = fman_from_fence(fence); | 810 | fman = fman_from_fence(fence); |
@@ -1024,6 +1051,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, | |||
1024 | (struct drm_vmw_fence_event_arg *) data; | 1051 | (struct drm_vmw_fence_event_arg *) data; |
1025 | struct vmw_fence_obj *fence = NULL; | 1052 | struct vmw_fence_obj *fence = NULL; |
1026 | struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); | 1053 | struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); |
1054 | struct ttm_object_file *tfile = vmw_fp->tfile; | ||
1027 | struct drm_vmw_fence_rep __user *user_fence_rep = | 1055 | struct drm_vmw_fence_rep __user *user_fence_rep = |
1028 | (struct drm_vmw_fence_rep __user *)(unsigned long) | 1056 | (struct drm_vmw_fence_rep __user *)(unsigned long) |
1029 | arg->fence_rep; | 1057 | arg->fence_rep; |
@@ -1037,15 +1065,11 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, | |||
1037 | */ | 1065 | */ |
1038 | if (arg->handle) { | 1066 | if (arg->handle) { |
1039 | struct ttm_base_object *base = | 1067 | struct ttm_base_object *base = |
1040 | ttm_base_object_lookup_for_ref(dev_priv->tdev, | 1068 | vmw_fence_obj_lookup(tfile, arg->handle); |
1041 | arg->handle); | 1069 | |
1042 | 1070 | if (IS_ERR(base)) | |
1043 | if (unlikely(base == NULL)) { | 1071 | return PTR_ERR(base); |
1044 | DRM_ERROR("Fence event invalid fence object handle " | 1072 | |
1045 | "0x%08lx.\n", | ||
1046 | (unsigned long)arg->handle); | ||
1047 | return -EINVAL; | ||
1048 | } | ||
1049 | fence = &(container_of(base, struct vmw_user_fence, | 1073 | fence = &(container_of(base, struct vmw_user_fence, |
1050 | base)->fence); | 1074 | base)->fence); |
1051 | (void) vmw_fence_obj_reference(fence); | 1075 | (void) vmw_fence_obj_reference(fence); |
@@ -1053,7 +1077,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, | |||
1053 | if (user_fence_rep != NULL) { | 1077 | if (user_fence_rep != NULL) { |
1054 | bool existed; | 1078 | bool existed; |
1055 | 1079 | ||
1056 | ret = ttm_ref_object_add(vmw_fp->tfile, base, | 1080 | ret = ttm_ref_object_add(tfile, base, |
1057 | TTM_REF_USAGE, &existed); | 1081 | TTM_REF_USAGE, &existed); |
1058 | if (unlikely(ret != 0)) { | 1082 | if (unlikely(ret != 0)) { |
1059 | DRM_ERROR("Failed to reference a fence " | 1083 | DRM_ERROR("Failed to reference a fence " |
@@ -1097,8 +1121,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, | |||
1097 | return 0; | 1121 | return 0; |
1098 | out_no_create: | 1122 | out_no_create: |
1099 | if (user_fence_rep != NULL) | 1123 | if (user_fence_rep != NULL) |
1100 | ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, | 1124 | ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); |
1101 | handle, TTM_REF_USAGE); | ||
1102 | out_no_ref_obj: | 1125 | out_no_ref_obj: |
1103 | vmw_fence_obj_unreference(&fence); | 1126 | vmw_fence_obj_unreference(&fence); |
1104 | return ret; | 1127 | return ret; |