aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-04-03 15:45:27 -0400
committerDave Airlie <airlied@redhat.com>2017-04-03 15:45:27 -0400
commit84c4ba54f4a52f4d045c956dbc9801f27eb300b7 (patch)
treee80de38a542fcdf70a876f882454bdd24b7e74fa
parenta71c9a1c779f2499fb2afc0553e543f18aff6edf (diff)
parente7e11f99564222d82f0ce84bd521e57d78a6b678 (diff)
Merge branch 'vmwgfx-fixes-4.11' of git://people.freedesktop.org/~thomash/linux into drm-fixes
Set of vmwgfx fixes * 'vmwgfx-fixes-4.11' of git://people.freedesktop.org/~thomash/linux: drm/vmwgfx: fix integer overflow in vmw_surface_define_ioctl() drm/vmwgfx: Remove getparam error message drm/ttm: Avoid calling drm_ht_remove from atomic context drm/ttm, drm/vmwgfx: Relax permission checking when opening surfaces drm/vmwgfx: avoid calling vzalloc with a 0 size in vmw_get_cap_3d_ioctl() drm/vmwgfx: NULL pointer dereference in vmw_surface_define_ioctl() drm/vmwgfx: Type-check lookups of fence objects
-rw-r--r--drivers/gpu/drm/ttm/ttm_object.c14
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.c79
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_surface.c31
-rw-r--r--include/drm/ttm/ttm_object.h5
6 files changed, 80 insertions, 57 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c
index fdb451e3ec01..26a7ad0f4789 100644
--- a/drivers/gpu/drm/ttm/ttm_object.c
+++ b/drivers/gpu/drm/ttm/ttm_object.c
@@ -179,7 +179,7 @@ int ttm_base_object_init(struct ttm_object_file *tfile,
179 if (unlikely(ret != 0)) 179 if (unlikely(ret != 0))
180 goto out_err0; 180 goto out_err0;
181 181
182 ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); 182 ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
183 if (unlikely(ret != 0)) 183 if (unlikely(ret != 0))
184 goto out_err1; 184 goto out_err1;
185 185
@@ -318,7 +318,8 @@ EXPORT_SYMBOL(ttm_ref_object_exists);
318 318
319int ttm_ref_object_add(struct ttm_object_file *tfile, 319int ttm_ref_object_add(struct ttm_object_file *tfile,
320 struct ttm_base_object *base, 320 struct ttm_base_object *base,
321 enum ttm_ref_type ref_type, bool *existed) 321 enum ttm_ref_type ref_type, bool *existed,
322 bool require_existed)
322{ 323{
323 struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; 324 struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
324 struct ttm_ref_object *ref; 325 struct ttm_ref_object *ref;
@@ -345,6 +346,9 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
345 } 346 }
346 347
347 rcu_read_unlock(); 348 rcu_read_unlock();
349 if (require_existed)
350 return -EPERM;
351
348 ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), 352 ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
349 false, false); 353 false, false);
350 if (unlikely(ret != 0)) 354 if (unlikely(ret != 0))
@@ -449,10 +453,10 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
449 ttm_ref_object_release(&ref->kref); 453 ttm_ref_object_release(&ref->kref);
450 } 454 }
451 455
456 spin_unlock(&tfile->lock);
452 for (i = 0; i < TTM_REF_NUM; ++i) 457 for (i = 0; i < TTM_REF_NUM; ++i)
453 drm_ht_remove(&tfile->ref_hash[i]); 458 drm_ht_remove(&tfile->ref_hash[i]);
454 459
455 spin_unlock(&tfile->lock);
456 ttm_object_file_unref(&tfile); 460 ttm_object_file_unref(&tfile);
457} 461}
458EXPORT_SYMBOL(ttm_object_file_release); 462EXPORT_SYMBOL(ttm_object_file_release);
@@ -529,9 +533,7 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev)
529 533
530 *p_tdev = NULL; 534 *p_tdev = NULL;
531 535
532 spin_lock(&tdev->object_lock);
533 drm_ht_remove(&tdev->object_hash); 536 drm_ht_remove(&tdev->object_hash);
534 spin_unlock(&tdev->object_lock);
535 537
536 kfree(tdev); 538 kfree(tdev);
537} 539}
@@ -635,7 +637,7 @@ int ttm_prime_fd_to_handle(struct ttm_object_file *tfile,
635 prime = (struct ttm_prime_object *) dma_buf->priv; 637 prime = (struct ttm_prime_object *) dma_buf->priv;
636 base = &prime->base; 638 base = &prime->base;
637 *handle = base->hash.key; 639 *handle = base->hash.key;
638 ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); 640 ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
639 641
640 dma_buf_put(dma_buf); 642 dma_buf_put(dma_buf);
641 643
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 6541dd8b82dc..6b2708b4eafe 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 */
717static struct ttm_base_object *
718vmw_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
704int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data, 739int 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,24 +1065,18 @@ 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);
1052 1076
1053 if (user_fence_rep != NULL) { 1077 if (user_fence_rep != NULL) {
1054 bool existed;
1055
1056 ret = ttm_ref_object_add(vmw_fp->tfile, base, 1078 ret = ttm_ref_object_add(vmw_fp->tfile, base,
1057 TTM_REF_USAGE, &existed); 1079 TTM_REF_USAGE, NULL, false);
1058 if (unlikely(ret != 0)) { 1080 if (unlikely(ret != 0)) {
1059 DRM_ERROR("Failed to reference a fence " 1081 DRM_ERROR("Failed to reference a fence "
1060 "object.\n"); 1082 "object.\n");
@@ -1097,8 +1119,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
1097 return 0; 1119 return 0;
1098out_no_create: 1120out_no_create:
1099 if (user_fence_rep != NULL) 1121 if (user_fence_rep != NULL)
1100 ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, 1122 ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE);
1101 handle, TTM_REF_USAGE);
1102out_no_ref_obj: 1123out_no_ref_obj:
1103 vmw_fence_obj_unreference(&fence); 1124 vmw_fence_obj_unreference(&fence);
1104 return ret; 1125 return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index b8c6a03c8c54..5ec24fd801cd 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -114,8 +114,6 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
114 param->value = dev_priv->has_dx; 114 param->value = dev_priv->has_dx;
115 break; 115 break;
116 default: 116 default:
117 DRM_ERROR("Illegal vmwgfx get param request: %d\n",
118 param->param);
119 return -EINVAL; 117 return -EINVAL;
120 } 118 }
121 119
@@ -186,7 +184,7 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
186 bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS); 184 bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS);
187 struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); 185 struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
188 186
189 if (unlikely(arg->pad64 != 0)) { 187 if (unlikely(arg->pad64 != 0 || arg->max_size == 0)) {
190 DRM_ERROR("Illegal GET_3D_CAP argument.\n"); 188 DRM_ERROR("Illegal GET_3D_CAP argument.\n");
191 return -EINVAL; 189 return -EINVAL;
192 } 190 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 65b3f0369636..bf23153d4f55 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -589,7 +589,7 @@ static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo,
589 return ret; 589 return ret;
590 590
591 ret = ttm_ref_object_add(tfile, &user_bo->prime.base, 591 ret = ttm_ref_object_add(tfile, &user_bo->prime.base,
592 TTM_REF_SYNCCPU_WRITE, &existed); 592 TTM_REF_SYNCCPU_WRITE, &existed, false);
593 if (ret != 0 || existed) 593 if (ret != 0 || existed)
594 ttm_bo_synccpu_write_release(&user_bo->dma.base); 594 ttm_bo_synccpu_write_release(&user_bo->dma.base);
595 595
@@ -773,7 +773,7 @@ int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
773 773
774 *handle = user_bo->prime.base.hash.key; 774 *handle = user_bo->prime.base.hash.key;
775 return ttm_ref_object_add(tfile, &user_bo->prime.base, 775 return ttm_ref_object_add(tfile, &user_bo->prime.base,
776 TTM_REF_USAGE, NULL); 776 TTM_REF_USAGE, NULL, false);
777} 777}
778 778
779/* 779/*
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index b445ce9b9757..05fa092c942b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -713,11 +713,14 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
713 128; 713 128;
714 714
715 num_sizes = 0; 715 num_sizes = 0;
716 for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) 716 for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
717 if (req->mip_levels[i] > DRM_VMW_MAX_MIP_LEVELS)
718 return -EINVAL;
717 num_sizes += req->mip_levels[i]; 719 num_sizes += req->mip_levels[i];
720 }
718 721
719 if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * 722 if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS ||
720 DRM_VMW_MAX_MIP_LEVELS) 723 num_sizes == 0)
721 return -EINVAL; 724 return -EINVAL;
722 725
723 size = vmw_user_surface_size + 128 + 726 size = vmw_user_surface_size + 128 +
@@ -891,17 +894,16 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
891 uint32_t handle; 894 uint32_t handle;
892 struct ttm_base_object *base; 895 struct ttm_base_object *base;
893 int ret; 896 int ret;
897 bool require_exist = false;
894 898
895 if (handle_type == DRM_VMW_HANDLE_PRIME) { 899 if (handle_type == DRM_VMW_HANDLE_PRIME) {
896 ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle); 900 ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle);
897 if (unlikely(ret != 0)) 901 if (unlikely(ret != 0))
898 return ret; 902 return ret;
899 } else { 903 } else {
900 if (unlikely(drm_is_render_client(file_priv))) { 904 if (unlikely(drm_is_render_client(file_priv)))
901 DRM_ERROR("Render client refused legacy " 905 require_exist = true;
902 "surface reference.\n"); 906
903 return -EACCES;
904 }
905 if (ACCESS_ONCE(vmw_fpriv(file_priv)->locked_master)) { 907 if (ACCESS_ONCE(vmw_fpriv(file_priv)->locked_master)) {
906 DRM_ERROR("Locked master refused legacy " 908 DRM_ERROR("Locked master refused legacy "
907 "surface reference.\n"); 909 "surface reference.\n");
@@ -929,17 +931,14 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
929 931
930 /* 932 /*
931 * Make sure the surface creator has the same 933 * Make sure the surface creator has the same
932 * authenticating master. 934 * authenticating master, or is already registered with us.
933 */ 935 */
934 if (drm_is_primary_client(file_priv) && 936 if (drm_is_primary_client(file_priv) &&
935 user_srf->master != file_priv->master) { 937 user_srf->master != file_priv->master)
936 DRM_ERROR("Trying to reference surface outside of" 938 require_exist = true;
937 " master domain.\n");
938 ret = -EACCES;
939 goto out_bad_resource;
940 }
941 939
942 ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); 940 ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL,
941 require_exist);
943 if (unlikely(ret != 0)) { 942 if (unlikely(ret != 0)) {
944 DRM_ERROR("Could not add a reference to a surface.\n"); 943 DRM_ERROR("Could not add a reference to a surface.\n");
945 goto out_bad_resource; 944 goto out_bad_resource;
diff --git a/include/drm/ttm/ttm_object.h b/include/drm/ttm/ttm_object.h
index ed953f98f0e1..1487011fe057 100644
--- a/include/drm/ttm/ttm_object.h
+++ b/include/drm/ttm/ttm_object.h
@@ -229,6 +229,8 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base);
229 * @ref_type: The type of reference. 229 * @ref_type: The type of reference.
230 * @existed: Upon completion, indicates that an identical reference object 230 * @existed: Upon completion, indicates that an identical reference object
231 * already existed, and the refcount was upped on that object instead. 231 * already existed, and the refcount was upped on that object instead.
232 * @require_existed: Fail with -EPERM if an identical ref object didn't
233 * already exist.
232 * 234 *
233 * Checks that the base object is shareable and adds a ref object to it. 235 * Checks that the base object is shareable and adds a ref object to it.
234 * 236 *
@@ -243,7 +245,8 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base);
243 */ 245 */
244extern int ttm_ref_object_add(struct ttm_object_file *tfile, 246extern int ttm_ref_object_add(struct ttm_object_file *tfile,
245 struct ttm_base_object *base, 247 struct ttm_base_object *base,
246 enum ttm_ref_type ref_type, bool *existed); 248 enum ttm_ref_type ref_type, bool *existed,
249 bool require_existed);
247 250
248extern bool ttm_ref_object_exists(struct ttm_object_file *tfile, 251extern bool ttm_ref_object_exists(struct ttm_object_file *tfile,
249 struct ttm_base_object *base); 252 struct ttm_base_object *base);