]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/imagination: Fix user array stride in pvr_set_uobj_array()
authorShuvam Pandey <shuvampandey1@gmail.com>
Wed, 1 Jul 2026 18:44:34 +0000 (11:44 -0700)
committerAlessio Belle <alessio.belle@imgtec.com>
Thu, 2 Jul 2026 10:16:18 +0000 (11:16 +0100)
pvr_set_uobj_array() copies an array of kernel objects to a userspace
array whose element size is described by out->stride. When out->stride
is different from the kernel object size, the slow path advances the
userspace pointer by the kernel object size and the kernel pointer by the
userspace stride.

This reverses the intended layout. For larger userspace strides, later
copies read from the wrong kernel addresses. For smaller userspace
strides, later copies are written at the wrong userspace offsets. The
padding clear is also done only for the first element instead of the
padding area for each element.

Advance the userspace pointer by out->stride and the kernel pointer by
obj_size, and clear per-element padding while the current userspace
pointer is still available.

Fixes: f99f5f3ea7ef ("drm/imagination: Add GPU ID parsing and firmware loading")
Cc: stable@vger.kernel.org # v6.8+
Reviewed-by: Alessio Belle <alessio.belle@imgtec.com>
Signed-off-by: Shuvam Pandey <shuvampandey1@gmail.com>
Link: https://patch.msgid.link/6a456012.eb165e5c.113c2a.b71d@mx.google.com
Signed-off-by: Alessio Belle <alessio.belle@imgtec.com>
drivers/gpu/drm/imagination/pvr_drv.c

index 091e9b4873e101841868d3be700a4ba2e95fadda..e8487fd22e1549e46eb9dbe71029a595c87478dd 100644 (file)
@@ -1257,14 +1257,13 @@ pvr_set_uobj_array(const struct drm_pvr_obj_array *out, u32 min_stride, u32 obj_
                        if (copy_to_user(out_ptr, in_ptr, cpy_elem_size))
                                return -EFAULT;
 
-                       out_ptr += obj_size;
-                       in_ptr += out->stride;
-               }
+                       if (out->stride > obj_size &&
+                           clear_user(out_ptr + cpy_elem_size, out->stride - obj_size)) {
+                               return -EFAULT;
+                       }
 
-               if (out->stride > obj_size &&
-                   clear_user(u64_to_user_ptr(out->array + obj_size),
-                              out->stride - obj_size)) {
-                       return -EFAULT;
+                       out_ptr += out->stride;
+                       in_ptr += obj_size;
                }
        }