Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eea23ca2 authored by Thomas Zimmermann's avatar Thomas Zimmermann Committed by Greg Kroah-Hartman
Browse files

drm/vmwgfx: Don't double-free the mode stored in par->set_mode



commit c2d311553855395764e2e5bf401d987ba65c2056 upstream.

When calling vmw_fb_set_par(), the mode stored in par->set_mode gets free'd
twice. The first free is in vmw_fb_kms_detach(), the second is near the
end of vmw_fb_set_par() under the name of 'old_mode'. The mode-setting code
only works correctly if the mode doesn't actually change. Removing
'old_mode' in favor of using par->set_mode directly fixes the problem.

Cc: <stable@vger.kernel.org>
Fixes: a278724a ("drm/vmwgfx: Implement fbdev on kms v2")
Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarDeepak Rawat <drawat@vmware.com>
Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c179e6de
Loading
Loading
Loading
Loading
+3 −9
Original line number Diff line number Diff line
@@ -531,11 +531,9 @@ static int vmw_fb_set_par(struct fb_info *info)
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
	};
	struct drm_display_mode *old_mode;
	struct drm_display_mode *mode;
	int ret;

	old_mode = par->set_mode;
	mode = drm_mode_duplicate(vmw_priv->dev, &new_mode);
	if (!mode) {
		DRM_ERROR("Could not create new fb mode.\n");
@@ -546,11 +544,7 @@ static int vmw_fb_set_par(struct fb_info *info)
	mode->vdisplay = var->yres;
	vmw_guess_mode_timing(mode);

	if (old_mode && drm_mode_equal(old_mode, mode)) {
		drm_mode_destroy(vmw_priv->dev, mode);
		mode = old_mode;
		old_mode = NULL;
	} else if (!vmw_kms_validate_mode_vram(vmw_priv,
	if (!vmw_kms_validate_mode_vram(vmw_priv,
					mode->hdisplay *
					DIV_ROUND_UP(var->bits_per_pixel, 8),
					mode->vdisplay)) {
@@ -613,8 +607,8 @@ static int vmw_fb_set_par(struct fb_info *info)
	schedule_delayed_work(&par->local_work, 0);

out_unlock:
	if (old_mode)
		drm_mode_destroy(vmw_priv->dev, old_mode);
	if (par->set_mode)
		drm_mode_destroy(vmw_priv->dev, par->set_mode);
	par->set_mode = mode;

	drm_modeset_unlock_all(vmw_priv->dev);