[PATCH v3] drm/amd/display: Fix dangling pointers in state reset functions on allocation failure
From: Evgenii Burenchev
Date: Fri Jun 26 2026 - 15:14:05 EST
Multiple reset functions in amdgpu_dm free the old state before allocating
a new one. If kzalloc_obj() fails, the function returns without updating
the state pointer, leaving a dangling pointer to already freed memory.
Fix this by allocating the new state first. In case of allocation failure,
the old state remains untouched and the function safely returns, preserving
the existing state.
For amdgpu_dm_connector_funcs_reset(), additionally restore the explicit
kfree(old_state) which was lost when the function was refactored, as
__drm_atomic_helper_connector_destroy_state() only frees resources but not
the state structure itself.
This affects three functions:
- amdgpu_dm_plane_drm_plane_reset()
- amdgpu_dm_crtc_reset_state()
- amdgpu_dm_connector_funcs_reset()
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: 5d945cbcd4b1 ("drm/amd/display: Create a file dedicated to planes")
Fixes: 473683a03495 ("drm/amd/display: Create a file dedicated for CRTC")
Fixes: e7b07ceef2a6 ("drm/amd/display: Merge amdgpu_dm_types and amdgpu_dm")
Signed-off-by: Evgenii Burenchev <evg28bur@xxxxxxxxx>
---
Changes in v3:
- Restore explicit kfree(old_state) in amdgpu_dm_connector_funcs_reset()
to prevent memory leak (reviewer Mario Limonciello <mario.limonciello@xxxxxxx>)
Changes in v2:
- Also fix amdgpu_dm_crtc_reset_state() and amdgpu_dm_connector_funcs_reset()
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 46 +++++++++++--------
.../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 8 ++--
.../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 14 +++---
3 files changed, 39 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 97ab1e83b318..8829e884167b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8151,33 +8151,41 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
{
- struct dm_connector_state *state =
+ /* Remember the old state */
+ struct dm_connector_state *old_state =
to_dm_connector_state(connector->state);
+ struct dm_connector_state *state;
+
+ /* Allocate new state */
+ state = kzalloc_obj(*state);
+ if (WARN_ON(!state))
+ return;
+
+ /* Release resources owned by the previous state and free memory */
if (connector->state)
__drm_atomic_helper_connector_destroy_state(connector->state);
- kfree(state);
+ kfree(old_state);
- state = kzalloc_obj(*state);
+ /* Install and initialize the new DRM connector state */
+ __drm_atomic_helper_connector_reset(connector, &state->base);
- if (state) {
- state->scaling = RMX_OFF;
- state->underscan_enable = false;
- state->underscan_hborder = 0;
- state->underscan_vborder = 0;
- state->base.max_requested_bpc = 8;
- state->vcpi_slots = 0;
- state->pbn = 0;
-
- if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
- if (amdgpu_dm_abm_level <= 0)
- state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
- else
- state->abm_level = amdgpu_dm_abm_level;
- }
+ /* Initialize AMD-specific connector state */
+ state->scaling = RMX_OFF;
+ state->underscan_enable = false;
+ state->underscan_hborder = 0;
+ state->underscan_vborder = 0;
+ state->base.max_requested_bpc = 8;
+ state->vcpi_slots = 0;
+ state->pbn = 0;
- __drm_atomic_helper_connector_reset(connector, &state->base);
+ /* Initialize eDP-specific defaults */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ if (amdgpu_dm_abm_level <= 0)
+ state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
+ else
+ state->abm_level = amdgpu_dm_abm_level;
}
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 3dcedaa67ed8..6146fbc528c3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -437,13 +437,15 @@ static void amdgpu_dm_crtc_reset_state(struct drm_crtc *crtc)
{
struct dm_crtc_state *state;
- if (crtc->state)
- amdgpu_dm_crtc_destroy_state(crtc, crtc->state);
-
+ /* Allocate new state first */
state = kzalloc_obj(*state);
if (WARN_ON(!state))
return;
+ /* Destroy old state only after successful allocation */
+ if (crtc->state)
+ amdgpu_dm_crtc_destroy_state(crtc, crtc->state);
+
__drm_atomic_helper_crtc_reset(crtc, &state->base);
}
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..eb1c0a26f20d 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
@@ -1488,17 +1488,17 @@ static const struct drm_plane_helper_funcs dm_primary_plane_helper_funcs = {
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);
+ struct dm_plane_state *amdgpu_state;
+ /* Allocate new state first */
amdgpu_state = kzalloc_obj(*amdgpu_state);
- WARN_ON(amdgpu_state == NULL);
-
- if (!amdgpu_state)
+ if (WARN_ON(!amdgpu_state))
return;
+ /* Destroy old state only after successful allocation */
+ 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;
--
2.43.0