diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-09-26 15:50:05 -0400 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-10-03 09:16:17 -0400 |
commit | ce9d419dbecc292cc3e06e8b1d6d123d3fa813a4 (patch) | |
tree | a65b65d58e52bb05b3f08c6610f5d6345e5f4879 /drivers/gpu | |
parent | ab7ad7f6451580aa7eccc0ba62807c872088a8f9 (diff) |
drm/i915: Sanity check pread/pwrite
Move the access control up from the fast paths, which are no longer
universally taken first, up into the caller. This then duplicates some
sanity checking along the slow paths, but is much simpler.
Tracked as CVE-2010-2962.
Reported-by: Kees Cook <kees@ubuntu.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: stable@kernel.org
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index cfe597865f5d..7749e78a7300 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -477,8 +477,15 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, | |||
477 | */ | 477 | */ |
478 | if (args->offset > obj->size || args->size > obj->size || | 478 | if (args->offset > obj->size || args->size > obj->size || |
479 | args->offset + args->size > obj->size) { | 479 | args->offset + args->size > obj->size) { |
480 | drm_gem_object_unreference_unlocked(obj); | 480 | ret = -EINVAL; |
481 | return -EINVAL; | 481 | goto err; |
482 | } | ||
483 | |||
484 | if (!access_ok(VERIFY_WRITE, | ||
485 | (char __user *)(uintptr_t)args->data_ptr, | ||
486 | args->size)) { | ||
487 | ret = -EFAULT; | ||
488 | goto err; | ||
482 | } | 489 | } |
483 | 490 | ||
484 | if (i915_gem_object_needs_bit17_swizzle(obj)) { | 491 | if (i915_gem_object_needs_bit17_swizzle(obj)) { |
@@ -490,8 +497,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, | |||
490 | file_priv); | 497 | file_priv); |
491 | } | 498 | } |
492 | 499 | ||
500 | err: | ||
493 | drm_gem_object_unreference_unlocked(obj); | 501 | drm_gem_object_unreference_unlocked(obj); |
494 | |||
495 | return ret; | 502 | return ret; |
496 | } | 503 | } |
497 | 504 | ||
@@ -580,8 +587,6 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, | |||
580 | 587 | ||
581 | user_data = (char __user *) (uintptr_t) args->data_ptr; | 588 | user_data = (char __user *) (uintptr_t) args->data_ptr; |
582 | remain = args->size; | 589 | remain = args->size; |
583 | if (!access_ok(VERIFY_READ, user_data, remain)) | ||
584 | return -EFAULT; | ||
585 | 590 | ||
586 | 591 | ||
587 | mutex_lock(&dev->struct_mutex); | 592 | mutex_lock(&dev->struct_mutex); |
@@ -940,8 +945,15 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
940 | */ | 945 | */ |
941 | if (args->offset > obj->size || args->size > obj->size || | 946 | if (args->offset > obj->size || args->size > obj->size || |
942 | args->offset + args->size > obj->size) { | 947 | args->offset + args->size > obj->size) { |
943 | drm_gem_object_unreference_unlocked(obj); | 948 | ret = -EINVAL; |
944 | return -EINVAL; | 949 | goto err; |
950 | } | ||
951 | |||
952 | if (!access_ok(VERIFY_READ, | ||
953 | (char __user *)(uintptr_t)args->data_ptr, | ||
954 | args->size)) { | ||
955 | ret = -EFAULT; | ||
956 | goto err; | ||
945 | } | 957 | } |
946 | 958 | ||
947 | /* We can only do the GTT pwrite on untiled buffers, as otherwise | 959 | /* We can only do the GTT pwrite on untiled buffers, as otherwise |
@@ -975,8 +987,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
975 | DRM_INFO("pwrite failed %d\n", ret); | 987 | DRM_INFO("pwrite failed %d\n", ret); |
976 | #endif | 988 | #endif |
977 | 989 | ||
990 | err: | ||
978 | drm_gem_object_unreference_unlocked(obj); | 991 | drm_gem_object_unreference_unlocked(obj); |
979 | |||
980 | return ret; | 992 | return ret; |
981 | } | 993 | } |
982 | 994 | ||