In amdgpu_dm_plane_drm_plane_reset(), the old plane state is freed
before allocating a new one. If kzalloc_obj() fails, the function
returns without updating plane->state, leaving a dangling pointer
to already freed memory.

Fix this by allocating the new state first. If allocation fails,
free the old state (if present) and set plane->state to NULL to
prevent any dangling references.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: 5d945cbcd4b1 ("drm/amd/display: Create a file dedicated to planes")
Signed-off-by: Evgenii Burenchev <[email protected]>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index e957657b06c7..0d81cef5fdaa 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1490,20 +1490,30 @@ static void amdgpu_dm_plane_drm_plane_reset(struct 
drm_plane *plane)
 {
        struct dm_plane_state *amdgpu_state = NULL;
 
-       if (plane->state)
-               plane->funcs->atomic_destroy_state(plane, plane->state);
-
        amdgpu_state = kzalloc_obj(*amdgpu_state);
-       WARN_ON(amdgpu_state == NULL);
 
        if (!amdgpu_state)
-               return;
+               goto err_alloc;
+
+       /* Old state can now be safely destroyed. The new state is already 
allocated and will be assigned */
+       if (plane->state)
+               plane->funcs->atomic_destroy_state(plane, plane->state);
 
        __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
        amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
        amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT;
        amdgpu_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
        amdgpu_state->blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
+
+       return;
+
+err_alloc:
+       /* Allocation failed: free old state (if present) and set plane->state 
to NULL */
+       if (plane->state) {
+               plane->funcs->atomic_destroy_state(plane, plane->state);
+               plane->state = NULL;
+       }
+       WARN_ON(amdgpu_state == NULL);
 }
 
 static struct drm_plane_state 
*amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane)
-- 
2.43.0

Reply via email to