summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2013-03-11 17:31:45 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-28 12:12:10 -0700
commite03f8b87d6b11e8c2f9d31b221d8c536091485af (patch)
tree999c254b541d2ed7249c09b8434dfb89ea86116c
parent5cec2bb0c7b4d16bb176b6299d4b6dd098c9db24 (diff)
downloadlinux-3.10-e03f8b87d6b11e8c2f9d31b221d8c536091485af.tar.gz
linux-3.10-e03f8b87d6b11e8c2f9d31b221d8c536091485af.tar.bz2
linux-3.10-e03f8b87d6b11e8c2f9d31b221d8c536091485af.zip
drm/i915: bounds check execbuffer relocation count
commit 3118a4f652c7b12c752f3222af0447008f9b2368 upstream. It is possible to wrap the counter used to allocate the buffer for relocation copies. This could lead to heap writing overflows. CVE-2013-0913 v3: collapse test, improve comment v2: move check into validate_exec_list Signed-off-by: Kees Cook <keescook@chromium.org> Reported-by: Pinkie Pie Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index d4417e3cc3d..e97ed611d8c 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -957,15 +957,20 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
int count)
{
int i;
+ int relocs_total = 0;
+ int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry);
for (i = 0; i < count; i++) {
char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
int length; /* limited by fault_in_pages_readable() */
- /* First check for malicious input causing overflow */
- if (exec[i].relocation_count >
- INT_MAX / sizeof(struct drm_i915_gem_relocation_entry))
+ /* First check for malicious input causing overflow in
+ * the worst case where we need to allocate the entire
+ * relocation tree as a single array.
+ */
+ if (exec[i].relocation_count > relocs_max - relocs_total)
return -EINVAL;
+ relocs_total += exec[i].relocation_count;
length = exec[i].relocation_count *
sizeof(struct drm_i915_gem_relocation_entry);