[Intel-gfx] [resend] drm/i915: Prevent overflow of execbuf.buffer_count and num_cliprects
Chris Wilson
chris at chris-wilson.co.uk
Wed Nov 15 15:38:24 UTC 2017
Quoting Tvrtko Ursulin (2017-11-15 15:33:28)
>
> On 14/11/2017 23:00, Chris Wilson wrote:
> > @@ -2462,11 +2462,13 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
> > struct drm_i915_gem_execbuffer2 exec2;
> > struct drm_i915_gem_exec_object *exec_list = NULL;
> > struct drm_i915_gem_exec_object2 *exec2_list = NULL;
> > + const size_t count = args->buffer_count;
> > unsigned int i;
> > int err;
> >
> > - if (args->buffer_count < 1 || args->buffer_count > SIZE_MAX / sz - 1) {
> > - DRM_DEBUG("execbuf2 with %d buffers\n", args->buffer_count);
> > + /* Lookups via HANDLE_LUT are limited to INT_MAX (see eb_create()) */
> > + if (count < 1 || count > INT_MAX || count > SIZE_MAX / sz - 1) {
>
> Does it need to be "count >= INT_MAX" since below we do "count + 1" ?
> > v2: buffer_count is currently limited to INT_MAX because we treat it as
> > signaled variable for LUT_HANDLE in eb_lookup_vma
The +1 is not used for the lookup, so we only need to check against
INT_MAX and not INT_MAX-1.
>
> I am not sure though why this check. kvmalloc_array takes size_t for
> both parameters, so where does an INT_MAX come into picture to start
> with? Should it be count >= SIZE_MAX in this check since count is size_t?
>
> > + DRM_DEBUG("execbuf2 with %zd buffers\n", count); > return -EINVAL;
> > }
> >
> > @@ -2485,9 +2487,9 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
> > return -EINVAL;
> >
> > /* Copy in the exec list from userland */
> > - exec_list = kvmalloc_array(args->buffer_count, sizeof(*exec_list),
> > + exec_list = kvmalloc_array(count, sizeof(*exec_list),
> > __GFP_NOWARN | GFP_KERNEL);
> > - exec2_list = kvmalloc_array(args->buffer_count + 1, sz,
> > + exec2_list = kvmalloc_array(count + 1, sz,
> > __GFP_NOWARN | GFP_KERNEL);
> > if (exec_list == NULL || exec2_list == NULL) {
> > DRM_DEBUG("Failed to allocate exec list for %d buffers\n",
> > @@ -2498,7 +2500,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
> > }
> > err = copy_from_user(exec_list,
> > u64_to_user_ptr(args->buffers_ptr),
> > - sizeof(*exec_list) * args->buffer_count);
> > + sizeof(*exec_list) * count);
> > if (err) {
> > DRM_DEBUG("copy %d exec entries failed %d\n",
> > args->buffer_count, err);
> > @@ -2554,10 +2556,11 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
> > struct drm_i915_gem_execbuffer2 *args = data;
> > struct drm_i915_gem_exec_object2 *exec2_list;
> > struct drm_syncobj **fences = NULL;
> > + const size_t count = args->buffer_count;
> > int err;
> >
> > - if (args->buffer_count < 1 || args->buffer_count > SIZE_MAX / sz - 1) {
> > - DRM_DEBUG("execbuf2 with %d buffers\n", args->buffer_count);
> > + if (count < 1 || count > SIZE_MAX / sz - 1) {
> > + DRM_DEBUG("execbuf2 with %zd buffers\n", count);
>
> Why is the check different between eb and eb2? Move to helper if the
> same check is actually correct?
We need before the allocation so that we report -EINVAL not -ENOMEM.
(Because I forgot about the duplication after finding the INT_MAX limit.)
-Chris
More information about the Intel-gfx
mailing list