summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Goins <agoins@nvidia.com>2019-08-28 18:24:16 -0500
committerAaron Plattner <aplattner@nvidia.com>2019-11-11 14:35:57 -0800
commit3ef9029ace4245d9f8929aa71e22bc6a6f40b7b3 (patch)
tree0609f6c1f183861a7f5fd04e4af8e9803964aff8
parentc82f814313a813d7e1a2d7d3b1f7561810446b34 (diff)
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 <agoins@nvidia.com>
-rw-r--r--hw/xfree86/drivers/modesetting/vblank.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c
index d5799d526..b38e5d4ec 100644
--- a/hw/xfree86/drivers/modesetting/vblank.c
+++ b/hw/xfree86/drivers/modesetting/vblank.c
@@ -91,6 +91,39 @@ ms_crtc_on(xf86CrtcPtr crtc)
}
/*
+ * 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;