summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShuvam Pandey <shuvampandey1@gmail.com>2026-07-01 11:44:34 -0700
committerAlessio Belle <alessio.belle@imgtec.com>2026-07-02 11:16:18 +0100
commit8dc8f3f4c2382fb7d1b1986ba8f33a2466cd3d7a (patch)
treeb82bcb724d667b75f8122351e7506a3a9f39828a
parentd431b4012fd22920523dbd2806da663c1048e386 (diff)
downloadlinux-8dc8f3f4c2382fb7d1b1986ba8f33a2466cd3d7a.tar.gz
linux-8dc8f3f4c2382fb7d1b1986ba8f33a2466cd3d7a.zip
drm/imagination: Fix user array stride in pvr_set_uobj_array()
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>
-rw-r--r--drivers/gpu/drm/imagination/pvr_drv.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c
index 091e9b4873e1..e8487fd22e15 100644
--- a/drivers/gpu/drm/imagination/pvr_drv.c
+++ b/drivers/gpu/drm/imagination/pvr_drv.c
@@ -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;
}
}