drm_atomic_set_mode_prop_for_crtc() has a few issues:

- it doesn't clear the state->mode, so old data may be left there when a
  new mode is set.
- if an error happens, state->mode is left in a partially updated state.

This patch improves the situation by:

- bail out early if blob is of wrong length.
- construct drm_display_mode first in an initialized local variable, and
  copy it to state->mode only when we know the call has succeeded.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ti.com>
---
 drivers/gpu/drm/drm_atomic.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3ff1ed7b33db..5bfecb2bbedf 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -348,16 +348,24 @@ int drm_atomic_set_mode_prop_for_crtc(struct 
drm_crtc_state *state,
        if (blob == state->mode_blob)
                return 0;

+       if (blob && blob->length != sizeof(struct drm_mode_modeinfo))
+               return -EINVAL;
+
        drm_property_unreference_blob(state->mode_blob);
        state->mode_blob = NULL;

        if (blob) {
-               if (blob->length != sizeof(struct drm_mode_modeinfo) ||
-                   drm_mode_convert_umode(&state->mode,
-                                          (const struct drm_mode_modeinfo *)
-                                           blob->data))
+               const struct drm_mode_modeinfo *umode =
+                       (const struct drm_mode_modeinfo *)blob->data;
+               struct drm_display_mode mode;
+
+               memset(&mode, 0, sizeof(mode));
+
+               if (drm_mode_convert_umode(&mode, umode))
                        return -EINVAL;

+               state->mode = mode;
+
                state->mode_blob = drm_property_reference_blob(blob);
                state->enable = true;
                DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n",
-- 
2.5.0

Reply via email to