From 341a4787157c68597951727d5d11a2813a31ec7e Mon Sep 17 00:00:00 2001 From: Alex Goins Date: Wed, 28 Aug 2019 18:24:16 -0500 Subject: [PATCH] modesetting: Fix ms_covering_crtc() segfault with non-modesetting slave primary ms_covering_crtc() uses RRFirstOutput() to determine a primary output to fall back to if a drawable is overlapping a slave output. If the primary output is a slave output, RRFirstOutput() will return a slave output even if passed a master ScreenPtr. ms_covering_crtc() dereferences the output's devPrivate, which is invalid for non-modesetting outputs, and can crash. Changing RRFirstOutput() could have unintended side effects for other callers, so this change replaces the call to RRFirstOutput() with ms_first_output(). ms_first_output() ignores the primary output if it doesn't match the given ScreenPtr, choosing the first connected output instead. Signed-off-by: Alex Goins (cherry picked from commit 3ef9029ace4245d9f8929aa71e22bc6a6f40b7b3) --- hw/xfree86/drivers/modesetting/vblank.c | 35 ++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c index 561229f30..df1d6aad8 100644 --- a/hw/xfree86/drivers/modesetting/vblank.c +++ b/hw/xfree86/drivers/modesetting/vblank.c @@ -90,6 +90,39 @@ ms_crtc_on(xf86CrtcPtr crtc) return crtc->enabled && drmmode_crtc->dpms_mode == DPMSModeOn; } +/* + * Return the first output which is connected to an active CRTC on this screen. + * + * RRFirstOutput() will return an output from a slave screen if it is primary, + * which is not the behavior that ms_covering_crtc() wants. + */ + +static RROutputPtr ms_first_output(ScreenPtr pScreen) +{ + rrScrPriv(pScreen); + RROutputPtr output; + int i, j; + + if (!pScrPriv) + return NULL; + + if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc && + (pScrPriv->primaryOutput->pScreen == pScreen)) { + return pScrPriv->primaryOutput; + } + + for (i = 0; i < pScrPriv->numCrtcs; i++) { + RRCrtcPtr crtc = pScrPriv->crtcs[i]; + + for (j = 0; j < pScrPriv->numOutputs; j++) { + output = pScrPriv->outputs[j]; + if (output->crtc == crtc) + return output; + } + } + return NULL; +} + /* * Return the crtc covering 'box'. If two crtcs cover a portion of * 'box', then prefer the crtc with greater coverage. @@ -135,7 +168,7 @@ ms_covering_crtc(ScreenPtr pScreen, BoxPtr box, Bool screen_is_ms) ScreenPtr slave; if (dixPrivateKeyRegistered(rrPrivKey)) - primary_output = RRFirstOutput(scrn->pScreen); + primary_output = ms_first_output(scrn->pScreen); if (!primary_output || !primary_output->crtc) return NULL;