[PATCH v9 24/61] drm/rockchip: dw_hdmi_qp: Fix NULL deref in PM ops on incomplete bind

Cristian Ciocaltea <[email protected]>
Newsgroups org.infradead.lists.linux-rockchip,dev.linux.lists.linux-sunxi,org.freedesktop.lists.dri-devel,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The system-sleep PM callbacks fetch the driver state via
dev_get_drvdata() and dereference it unconditionally.  However, they can
run while the device is not fully bound.  If the system suspends before
the component framework invokes the bind callback (e.g. during a
deferred probe waiting for the VOP), dev_get_drvdata() returns NULL.
Moreover, if dw_hdmi_qp_bind() fails, drvdata is already set but
hdmi->hdmi is left holding an error pointer.

In either case dw_hdmi_qp_rockchip_resume() dereferences an invalid
pointer, causing a kernel panic; the suspend path is equally affected.

Guard both callbacks against NULL checks, and reset hdmi->hdmi to NULL
when dw_hdmi_qp_bind() fails so the guards are effective.
hdmi->ctrl_ops is assigned before platform_set_drvdata(), so it is safe
to use whenever drvdata is non-NULL.

Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Reported-by: Sashiko <[email protected]>
Closes: https://lore.kernel.org/all/[email protected]/
Signed-off-by: Cristian Ciocaltea <[email protected]>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 9c4cf68d79d5..7c9d26d79664 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -686,9 +686,12 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	platform_set_drvdata(pdev, hdmi);
 
 	hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
-	if (IS_ERR(hdmi->hdmi))
-		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
+	if (IS_ERR(hdmi->hdmi)) {
+		ret = PTR_ERR(hdmi->hdmi);
+		hdmi->hdmi = NULL;
+		return dev_err_probe(hdmi->dev, ret,
 				     "Failed to bind dw-hdmi-qp");
+	}
 
 	connector = drm_bridge_connector_init(drm, encoder);
 	if (IS_ERR(connector))
@@ -726,7 +729,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
 {
 	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
 
-	dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+	if (hdmi && hdmi->hdmi)
+		dw_hdmi_qp_suspend(dev, hdmi->hdmi);
 
 	return 0;
 }
@@ -735,12 +739,15 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
 {
 	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
 
-	hdmi->ctrl_ops->io_init(hdmi);
+	if (hdmi) {
+		hdmi->ctrl_ops->io_init(hdmi);
 
-	dw_hdmi_qp_resume(dev, hdmi->hdmi);
+		if (hdmi->hdmi)
+			dw_hdmi_qp_resume(dev, hdmi->hdmi);
 
-	if (hdmi->encoder.encoder.dev)
-		drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
+		if (hdmi->encoder.encoder.dev)
+			drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
+	}
 
 	return 0;
 }

-- 
2.55.0


_______________________________________________
Linux-rockchip mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-rockchip
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.