If the number of connectors changes, then it is possible for the fbdev
helper to overrun/underrun some arrays which it allocates.  It allocates
these arrays based on mode_config.num_connector but then walks lists
using fb_helper->connector_count to limit the array index.  This can
lead to writes off the end of the arrays.

Fix this by allocating the arrays using fb_helper->connector_count.

A similar thing exists for some of the CRTC arrays.  For these, use
fb_helper->crtc_count.

Signed-off-by: Russell King <rmk+kernel at arm.linux.org.uk>
---
David,

Would you consider the following patch to clean up the DRM fb helper a
little - we already record the number of CRTCs and connectors in the
fb_helper structure.  While we officially don't support hotplugging,
this is more a consistency cleanup, so that we're dimensioning the
arrays using the same sizing that we will then use to walk over them.

Thanks.

 drivers/gpu/drm/drm_fb_helper.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0a19401aff80..0da727e55fd2 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1360,7 +1360,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
        if (modes[n] == NULL)
                return best_score;

-       crtcs = kzalloc(dev->mode_config.num_connector *
+       crtcs = kcalloc(fb_helper->crtc_count,
                        sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
        if (!crtcs)
                return best_score;
@@ -1406,7 +1406,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
                if (score > best_score) {
                        best_score = score;
                        memcpy(best_crtcs, crtcs,
-                              dev->mode_config.num_connector *
+                              fb_helper->crtc_count *
                               sizeof(struct drm_fb_helper_crtc *));
                }
        }
@@ -1430,11 +1430,11 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper)
        width = dev->mode_config.max_width;
        height = dev->mode_config.max_height;

-       crtcs = kcalloc(dev->mode_config.num_connector,
+       crtcs = kcalloc(fb_helper->connector_count,
                        sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
-       modes = kcalloc(dev->mode_config.num_connector,
+       modes = kcalloc(fb_helper->connector_count,
                        sizeof(struct drm_display_mode *), GFP_KERNEL);
-       enabled = kcalloc(dev->mode_config.num_connector,
+       enabled = kcalloc(fb_helper->connector_count,
                          sizeof(bool), GFP_KERNEL);
        if (!crtcs || !modes || !enabled) {
                DRM_ERROR("Memory allocation failed\n");
@@ -1447,8 +1447,8 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper)
        if (!(fb_helper->funcs->initial_config &&
              fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
                                               enabled, width, height))) {
-               memset(modes, 0, 
dev->mode_config.num_connector*sizeof(modes[0]));
-               memset(crtcs, 0, 
dev->mode_config.num_connector*sizeof(crtcs[0]));
+               memset(modes, 0, fb_helper->connector_count * sizeof(modes[0]));
+               memset(crtcs, 0, fb_helper->connector_count * sizeof(crtcs[0]));

                if (!drm_target_cloned(fb_helper,
                                       modes, enabled, width, height) &&
-- 
1.8.3.1

Reply via email to