[v7,03/23] drm: bridge: dw_hdmi: Free IRQ before CEC adapter is unregistered

Message ID 20260518180206.2480119-4-jonas@kwiboo.se (mailing list archive)
State New
Headers
Series drm: bridge: dw_hdmi: Misc enable/disable, CEC and EDID cleanup |

Commit Message

Jonas Karlman May 18, 2026, 6:01 p.m. UTC
The interrupt allocated with devm_request_threaded_irq() can be
use-after-free when the devres release action try to free_irq().

KASAN report a slab-use-after-free in dw_hdmi_cec_hardirq during unbind:

Call trace:
  [...]
  dw_hdmi_cec_hardirq+0x4cc/0x560
  free_irq+0x48c/0x7e4
  devm_irq_release+0x54/0x90
  dr_node_release+0x38/0x5c
  release_nodes+0xac/0x130
  devres_release_all+0xf4/0x1b0
  device_unbind_cleanup+0x28/0x1f8
  device_release_driver_internal+0x358/0x470
  device_release_driver+0x18/0x24
  bus_remove_device+0x33c/0x4f0
  device_del+0x2d8/0x790
  platform_device_del+0x34/0x1e0
  platform_device_unregister+0x14/0x3c
  dw_hdmi_remove+0x74/0x180
  [...]

Freed by:
  [...]
  kfree+0x1dc/0x5dc
  cec_delete_adapter+0xd4/0x118
  cec_devnode_release+0xa4/0xe0
  device_release+0xa0/0x200
  kobject_put+0x14c/0x26c
  put_device+0x14/0x30
  cec_unregister_adapter+0x20c/0x280
  dw_hdmi_cec_remove+0x8c/0xd0
  [...]

Explicitly devm_free_irq() before the CEC adapter is unregistered to
fix this possible use-after-free issue.

Fixes: a616e63c56ef ("drm/bridge: dw-hdmi: add cec driver")
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
v7: New patch

KASAN report a slab-use-after-free in dw_hdmi_cec_hardirq when,
  echo fe0a0000.hdmi > /sys/bus/platform/drivers/dwhdmi-rockchip/unbind
on a Rockchip RK3566 device prior to this fix.
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 1 +
 1 file changed, 1 insertion(+)
  

Comments

sashiko-bot@kernel.org May 18, 2026, 6:33 p.m. UTC | #1
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Freeing the shared IRQ before masking the hardware interrupt source creates a race condition that can lead to an unhandled interrupt storm, permanently disabling the shared IRQ line.
--

commit 860a0518c5583dda606c670b609794b60e6bc07b
Author: Jonas Karlman <jonas@kwiboo.se>

drm: bridge: dw_hdmi: Free IRQ before CEC adapter is unregistered

This commit explicitly frees the IRQ before the CEC adapter is unregistered
to prevent a use-after-free issue. This addresses a KASAN slab-use-after-free
report triggered during device unbind when the devres release action frees
the IRQ.

> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> index 9549dabde941c..67a2a242d3ca9 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> @@ -309,6 +309,7 @@ static void dw_hdmi_cec_remove(struct platform_device *pdev)
>  	struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
>  
>  	cec_notifier_cec_adap_unregister(cec->notify, cec->adap);
> +	devm_free_irq(&pdev->dev, cec->irq, cec->adap);

Does this sequence create a race condition that could result in an unhandled
interrupt storm?

The dw-hdmi-cec driver shares this IRQ line with the main dw-hdmi driver.
By freeing the IRQ handler before calling cec_unregister_adapter(), the
hardware CEC interrupts might still be unmasked and active.

If the CEC hardware asserts an interrupt during this window, the shared IRQ
line will go high. The remaining handlers on that line won't clear the CEC
interrupt, returning IRQ_NONE.

This could lead to an interrupt storm, causing the kernel to permanently
disable the shared IRQ line and break the main dw-hdmi driver's functionality.

Should the CEC hardware interrupts be explicitly masked before
devm_free_irq() is called?

>  	cec_unregister_adapter(cec->adap);
>  }
  
Hans Verkuil May 19, 2026, 6:21 a.m. UTC | #2
On 18/05/2026 20:01, Jonas Karlman wrote:
> The interrupt allocated with devm_request_threaded_irq() can be
> use-after-free when the devres release action try to free_irq().
> 
> KASAN report a slab-use-after-free in dw_hdmi_cec_hardirq during unbind:
> 
> Call trace:
>   [...]
>   dw_hdmi_cec_hardirq+0x4cc/0x560
>   free_irq+0x48c/0x7e4
>   devm_irq_release+0x54/0x90
>   dr_node_release+0x38/0x5c
>   release_nodes+0xac/0x130
>   devres_release_all+0xf4/0x1b0
>   device_unbind_cleanup+0x28/0x1f8
>   device_release_driver_internal+0x358/0x470
>   device_release_driver+0x18/0x24
>   bus_remove_device+0x33c/0x4f0
>   device_del+0x2d8/0x790
>   platform_device_del+0x34/0x1e0
>   platform_device_unregister+0x14/0x3c
>   dw_hdmi_remove+0x74/0x180
>   [...]
> 
> Freed by:
>   [...]
>   kfree+0x1dc/0x5dc
>   cec_delete_adapter+0xd4/0x118
>   cec_devnode_release+0xa4/0xe0
>   device_release+0xa0/0x200
>   kobject_put+0x14c/0x26c
>   put_device+0x14/0x30
>   cec_unregister_adapter+0x20c/0x280
>   dw_hdmi_cec_remove+0x8c/0xd0
>   [...]
> 
> Explicitly devm_free_irq() before the CEC adapter is unregistered to
> fix this possible use-after-free issue.
> 
> Fixes: a616e63c56ef ("drm/bridge: dw-hdmi: add cec driver")
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>

Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>

Regards,

	Hans

> ---
> v7: New patch
> 
> KASAN report a slab-use-after-free in dw_hdmi_cec_hardirq when,
>   echo fe0a0000.hdmi > /sys/bus/platform/drivers/dwhdmi-rockchip/unbind
> on a Rockchip RK3566 device prior to this fix.
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> index 9549dabde941..67a2a242d3ca 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> @@ -309,6 +309,7 @@ static void dw_hdmi_cec_remove(struct platform_device *pdev)
>  	struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
>  
>  	cec_notifier_cec_adap_unregister(cec->notify, cec->adap);
> +	devm_free_irq(&pdev->dev, cec->irq, cec->adap);
>  	cec_unregister_adapter(cec->adap);
>  }
>
  

Patch

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
index 9549dabde941..67a2a242d3ca 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
@@ -309,6 +309,7 @@  static void dw_hdmi_cec_remove(struct platform_device *pdev)
 	struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
 
 	cec_notifier_cec_adap_unregister(cec->notify, cec->adap);
+	devm_free_irq(&pdev->dev, cec->irq, cec->adap);
 	cec_unregister_adapter(cec->adap);
 }