Message ID | 20181115230645.15748-5-sebastian.reichel@collabora.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | omapdrm: DSI command mode panel support | expand |
On 16/11/18 01:06, Sebastian Reichel wrote: > The DSI encoder sets dssdev->ops->dsi.set_config, which is stored at the > same offset as dssdev->ops->hdmi.set_hdmi_mode. The code in omap_encoder > only checks if dssdev->ops->hdmi.set_hdmi_mode is NULL. Due to the way > union works, it won't be NULL if dsi.set_config is set. This means > dsi_set_config will be called with config=hdmi_mode=false=NULL parameter > resulting in a NULL dereference. Also the dereference happens while > console is locked, so kernel hangs without any debug output (can be > avoided by fbmem's lockless_register_fb=1 parameter). > > This fixes the issue by exiting early if the output type definitely > has no hdmi_set operations. > > Fixes: 83910ad3f51fb ("drm/omap: Move most omap_dss_driver operations to omap_dss_device_ops") > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> > --- > drivers/gpu/drm/omapdrm/omap_encoder.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c > index 32bbe3a80e7d..ba0099f0644c 100644 > --- a/drivers/gpu/drm/omapdrm/omap_encoder.c > +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c > @@ -122,6 +122,14 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, > > dssdev = omap_encoder->output; > > + /* The following operations access dssdev->ops->hdmi, which is a union > + * also used by DSI. This ensures, that the field does not have data > + * for DSI (or any other future output type). > + */ > + if (dssdev->output_type != OMAP_DISPLAY_TYPE_HDMI && > + dssdev->output_type != OMAP_DISPLAY_TYPE_DVI) Good catch. Why DVI? I think the whole code block starting from /* Set the HDMI mode and HDMI infoframe if applicable. */ to the end of the function should be inside if (dssdev->output_type == OMAP_DISPLAY_TYPE_HDMI) Tomi
Hi Tomi, On Fri, Nov 16, 2018 at 03:41:24PM +0200, Tomi Valkeinen wrote: > On 16/11/18 01:06, Sebastian Reichel wrote: > > The DSI encoder sets dssdev->ops->dsi.set_config, which is stored at the > > same offset as dssdev->ops->hdmi.set_hdmi_mode. The code in omap_encoder > > only checks if dssdev->ops->hdmi.set_hdmi_mode is NULL. Due to the way > > union works, it won't be NULL if dsi.set_config is set. This means > > dsi_set_config will be called with config=hdmi_mode=false=NULL parameter > > resulting in a NULL dereference. Also the dereference happens while > > console is locked, so kernel hangs without any debug output (can be > > avoided by fbmem's lockless_register_fb=1 parameter). > > > > This fixes the issue by exiting early if the output type definitely > > has no hdmi_set operations. > > > > Fixes: 83910ad3f51fb ("drm/omap: Move most omap_dss_driver operations to omap_dss_device_ops") > > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> > > --- > > drivers/gpu/drm/omapdrm/omap_encoder.c | 8 ++++++++ > > 1 file changed, 8 insertions(+) > > > > diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c > > index 32bbe3a80e7d..ba0099f0644c 100644 > > --- a/drivers/gpu/drm/omapdrm/omap_encoder.c > > +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c > > @@ -122,6 +122,14 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, > > > > dssdev = omap_encoder->output; > > > > + /* The following operations access dssdev->ops->hdmi, which is a union > > + * also used by DSI. This ensures, that the field does not have data > > + * for DSI (or any other future output type). > > + */ > > + if (dssdev->output_type != OMAP_DISPLAY_TYPE_HDMI && > > + dssdev->output_type != OMAP_DISPLAY_TYPE_DVI) > > Good catch. > > Why DVI? > > I think the whole code block starting from > > /* Set the HDMI mode and HDMI infoframe if applicable. */ > > to the end of the function should be inside > > if (dssdev->output_type == OMAP_DISPLAY_TYPE_HDMI) When I identified the issue I whitelisted DVI, since I wasn't sure if it also has the HDMI functionality. I planned to check the code later and then forgot about it. You are right, this should only check for HDMI. -- Sebastian
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 32bbe3a80e7d..ba0099f0644c 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -122,6 +122,14 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, dssdev = omap_encoder->output; + /* The following operations access dssdev->ops->hdmi, which is a union + * also used by DSI. This ensures, that the field does not have data + * for DSI (or any other future output type). + */ + if (dssdev->output_type != OMAP_DISPLAY_TYPE_HDMI && + dssdev->output_type != OMAP_DISPLAY_TYPE_DVI) + return; + if (dssdev->ops->hdmi.set_hdmi_mode) dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode);
The DSI encoder sets dssdev->ops->dsi.set_config, which is stored at the same offset as dssdev->ops->hdmi.set_hdmi_mode. The code in omap_encoder only checks if dssdev->ops->hdmi.set_hdmi_mode is NULL. Due to the way union works, it won't be NULL if dsi.set_config is set. This means dsi_set_config will be called with config=hdmi_mode=false=NULL parameter resulting in a NULL dereference. Also the dereference happens while console is locked, so kernel hangs without any debug output (can be avoided by fbmem's lockless_register_fb=1 parameter). This fixes the issue by exiting early if the output type definitely has no hdmi_set operations. Fixes: 83910ad3f51fb ("drm/omap: Move most omap_dss_driver operations to omap_dss_device_ops") Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> --- drivers/gpu/drm/omapdrm/omap_encoder.c | 8 ++++++++ 1 file changed, 8 insertions(+)