It is possible to wrap the counter used to allocate the buffer for relocation copies. This could lead to heap writing overflows.
Signed-off-by: Kees Cook keescook@chromium.org Reported-by: Pinkie Pie Cc: stable@vger.kernel.org --- v2: - move check into validate_exec_list --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 752e399..72d7841 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -732,6 +732,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, int count) { int i; + int total = 0;
for (i = 0; i < count; i++) { char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; @@ -744,6 +745,9 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, if (exec[i].relocation_count > INT_MAX / sizeof(struct drm_i915_gem_relocation_entry)) return -EINVAL; + if (exec[i].relocation_count > INT_MAX - total) + return -ENOMEM; + total += exec[i].relocation_count;
length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry);
On Mon, Mar 11, 2013 at 02:23:29PM -0700, Kees Cook wrote:
It is possible to wrap the counter used to allocate the buffer for relocation copies. This could lead to heap writing overflows.
I'd keep the return value as EINVAL so that we can continue to distinguish between the user passing garbage and hitting an oom. And total_relocs is preferrable to total, which also leads us to think more carefully about the error condition. I think the check should be against INT_MAX / sizeof(struct reloc_entry) for consistency with our other guard against overflows whilst allocating. -Chris
On Mon, Mar 11, 2013 at 3:00 PM, Chris Wilson chris@chris-wilson.co.uk wrote:
On Mon, Mar 11, 2013 at 02:23:29PM -0700, Kees Cook wrote:
It is possible to wrap the counter used to allocate the buffer for relocation copies. This could lead to heap writing overflows.
I'd keep the return value as EINVAL so that we can continue to distinguish between the user passing garbage and hitting an oom. And total_relocs is preferrable to total, which also leads us to think more carefully about the error condition. I think the check should be against INT_MAX / sizeof(struct reloc_entry) for consistency with our other guard against overflows whilst allocating.
I've ended up with this:
int max_alloc = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry); ... /* First check for malicious input causing overflow */ if (exec[i].relocation_count > max_alloc) return -EINVAL; if (exec[i].relocation_count > max_alloc - total_relocs) return -EINVAL; total_relocs += exec[i].relocation_count;
And looking at that, I wonder if we should just eliminate the first if entirely?
-Kees
-- Kees Cook Chrome OS Security
On Mon, Mar 11, 2013 at 03:25:59PM -0700, Kees Cook wrote:
On Mon, Mar 11, 2013 at 3:00 PM, Chris Wilson chris@chris-wilson.co.uk wrote:
On Mon, Mar 11, 2013 at 02:23:29PM -0700, Kees Cook wrote:
It is possible to wrap the counter used to allocate the buffer for relocation copies. This could lead to heap writing overflows.
I'd keep the return value as EINVAL so that we can continue to distinguish between the user passing garbage and hitting an oom. And total_relocs is preferrable to total, which also leads us to think more carefully about the error condition. I think the check should be against INT_MAX / sizeof(struct reloc_entry) for consistency with our other guard against overflows whilst allocating.
I've ended up with this:
int max_alloc = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry);
... /* First check for malicious input causing overflow */ if (exec[i].relocation_count > max_alloc) return -EINVAL; if (exec[i].relocation_count > max_alloc - total_relocs) return -EINVAL; total_relocs += exec[i].relocation_count;
And looking at that, I wonder if we should just eliminate the first if entirely?
Aye, seems reasonable. So perhaps,
/* First check for malicious input causing overflow in the worst case * where we need to allocate the entire relocation tree as a single * array. */ -Chris
dri-devel@lists.freedesktop.org