From: Xu Qianhui <[email protected]>
_dpu_crtc_get_gc_lut() packs DPU_GAMMA_LUT_SIZE entries of the
user-provided LUT unconditionally:
for (i = 0; i < PGC_TBL_LEN; i++) {
val_even = drm_color_lut_extract(lut[i * 2].green, 10);
...
The DRM core validates the blob against the maximum size and the element
size (drm_property_replace_blob_from_id() with max_size and
expected_elem_size), but not against the exact size, so a blob that is
shorter than DPU_GAMMA_LUT_SIZE * sizeof(struct drm_color_lut) is accepted
and the loop reads past the end of the blob.
Reject such blobs in dpu_crtc_atomic_check(). This is reachable from
userspace on any DPU platform that exposes the GC block (SDM845, SM8650,
SM8750, ...).
Signed-off-by: Xu Qianhui <[email protected]>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 42d0a529b4..7a2ed9ad64 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1534,6 +1534,21 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
+ /*
+ * The DRM core only checks the blob against the maximum LUT size and
+ * the element size, so a shorter blob is accepted. The GC path packs
+ * DPU_GAMMA_LUT_SIZE entries unconditionally, so validate the size
+ * here to avoid reading past the end of the blob.
+ */
+ if (crtc_state->gamma_lut &&
+ crtc_state->gamma_lut->length !=
+ DPU_GAMMA_LUT_SIZE * sizeof(struct drm_color_lut)) {
+ DRM_DEBUG_ATOMIC("%s: invalid gamma LUT size %zu, expected
%zu\n",
+ dpu_crtc->name, crtc_state->gamma_lut->length,
+ DPU_GAMMA_LUT_SIZE * sizeof(struct
drm_color_lut));
+ return -EINVAL;
+ }
+
/* don't reallocate resources if only ACTIVE has beeen changed */
if (crtc_state->mode_changed || crtc_state->connectors_changed ||
crtc_state->color_mgmt_changed) {
--
2.53.0