drm/amd/display: perform a bounds check before filling dirty rectangles

commit af22d6a869 upstream.

Currently, it is possible for us to access memory that we shouldn't.
Since, we acquire (possibly dangling) pointers to dirty rectangles
before doing a bounds check to make sure we can actually accommodate the
number of dirty rectangles userspace has requested to fill. This issue
is especially evident if a compositor requests both MPO and damage clips
at the same time, in which case I have observed a soft-hang. So, to
avoid this issue, perform the bounds check before filling a single dirty
rectangle and WARN() about it, if it is ever attempted in
fill_dc_dirty_rect().

Cc: stable@vger.kernel.org # 6.1+
Fixes: 30ebe41582 ("drm/amd/display: add FB_DAMAGE_CLIPS support")
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Hamza Mahfooz 2023-06-21 15:19:05 -04:00 committed by Greg Kroah-Hartman
parent 0441c44154
commit d58fb94f24
1 changed files with 4 additions and 9 deletions

View File

@ -4953,11 +4953,7 @@ static inline void fill_dc_dirty_rect(struct drm_plane *plane,
int32_t y, int32_t width, int32_t height,
int *i, bool ffu)
{
if (*i > DC_MAX_DIRTY_RECTS)
return;
if (*i == DC_MAX_DIRTY_RECTS)
goto out;
WARN_ON(*i >= DC_MAX_DIRTY_RECTS);
dirty_rect->x = x;
dirty_rect->y = y;
@ -4973,7 +4969,6 @@ static inline void fill_dc_dirty_rect(struct drm_plane *plane,
"[PLANE:%d] PSR SU dirty rect at (%d, %d) size (%d, %d)",
plane->base.id, x, y, width, height);
out:
(*i)++;
}
@ -5055,6 +5050,9 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
new_plane_state->plane->base.id,
bb_changed, fb_changed, num_clips);
if ((num_clips + (bb_changed ? 2 : 0)) > DC_MAX_DIRTY_RECTS)
goto ffu;
if (bb_changed) {
fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i],
new_plane_state->crtc_x,
@ -5084,9 +5082,6 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
new_plane_state->crtc_h, &i, false);
}
if (i > DC_MAX_DIRTY_RECTS)
goto ffu;
flip_addrs->dirty_rect_count = i;
return;