]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: fix NULL ptr deref in ISM delayed work
authorRay Wu <ray.wu@amd.com>
Tue, 7 Apr 2026 08:24:39 +0000 (16:24 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 17 Apr 2026 19:23:12 +0000 (15:23 -0400)
dc_destroy() sets dm->dc to NULL before amdgpu_dm_ism_fini() is called,
leaving a window where in-flight ISM delayed work dereferences the stale
pointer. Call amdgpu_dm_ism_fini() in amdgpu_dm_fini() before dc_destroy().

Fixes: 754003486c3c ("drm/amd/display: Add Idle state manager(ISM)")
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c

index f69a7e88546ad2c28123b77b1ac05fd0813f7607..f4be2724471d299d56625bcccad61e76b6b70e42 100644 (file)
@@ -2239,6 +2239,8 @@ static int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block)
 static void amdgpu_dm_fini(struct amdgpu_device *adev)
 {
        int i;
+       struct drm_crtc *crtc;
+       struct amdgpu_crtc *acrtc;
 
        if (adev->dm.vblank_control_workqueue) {
                destroy_workqueue(adev->dm.vblank_control_workqueue);
@@ -2255,6 +2257,13 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
                adev->dm.idle_workqueue = NULL;
        }
 
+       /* Finalize ISM for each CRTC before dc_destroy() sets dm->dc to NULL */
+       drm_for_each_crtc(crtc, adev_to_drm(adev)) {
+               acrtc = to_amdgpu_crtc(crtc);
+               amdgpu_dm_ism_fini(&acrtc->ism);
+
+       }
+
        amdgpu_dm_destroy_drm_device(&adev->dm);
 
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
index 5d2715f78314efe0968453b3e56beb860bf39f12..d69f5a75b685a81266dc03852ec895ae9039e008 100644 (file)
@@ -457,9 +457,12 @@ static struct drm_crtc_state *amdgpu_dm_crtc_duplicate_state(struct drm_crtc *cr
 
 static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
 {
-       struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+       /*
+        * amdgpu_dm_ism_fini() is intentionally called in amdgpu_dm_fini().
+        * It must be called before dc_destroy() in amdgpu_dm_fini()
+        * to avoid ISM accessing an invalid dc handle once dc is released.
+        */
 
-       amdgpu_dm_ism_fini(&acrtc->ism);
        drm_crtc_cleanup(crtc);
        kfree(crtc);
 }