From 690fbd1a64c1e1fd07f7f8a5e39e05a33e4d0721 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Jul 2010 21:55:04 +0100 Subject: [PATCH] drmmode: Use a copy of the converted mode on resize Avoid a potential use-after-free of the copied mode string by reusing the converted kernel mode on resize. ==19897== Invalid read of size 8 ==19897== at 0x661C330: ??? (strcpy.S:1308) ==19897== by 0x8618AE7: drmmode_set_mode_major (drmmode_display.c:293) ==19897== by 0x8618E6F: drmmode_xf86crtc_resize (drmmode_display.c:1299) ==19897== by 0x529A77: xf86RandR12ScreenSetSize (xf86RandR12.c:708) ==19897== by 0x4BD528: ProcRRSetScreenSize (rrscreen.c:301) ==19897== by 0x42B820: Dispatch (dispatch.c:432) ==19897== by 0x4254C9: main (main.c:289) ==19897== Address 0x72e91e0 is 0 bytes inside a block of size 9 free'd ==19897== at 0x4C23DBC: free (vg_replace_malloc.c:325) ==19897== by 0x48424F: xf86DeleteMode (xf86Mode.c:1921) ==19897== by 0x4942B7: xf86ProbeOutputModes (xf86Crtc.c:1572) ==19897== by 0x5290BB: xf86RandR12GetInfo12 (xf86RandR12.c:1551) ==19897== by 0x5313AE: RRGetInfo (rrinfo.c:202) ==19897== by 0x4BCCAA: rrGetScreenResources (rrscreen.c:337) ==19897== by 0x42B820: Dispatch (dispatch.c:432) ==19897== by 0x4254C9: main (main.c:289) Signed-off-by: Chris Wilson --- src/drmmode_display.c | 106 ++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 45 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 17f65415..67007b5e 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -57,6 +57,7 @@ typedef struct { typedef struct { drmmode_ptr drmmode; + drmModeModeInfo kmode; drmModeCrtcPtr mode_crtc; dri_bo *cursor; dri_bo *rotate_bo; @@ -302,52 +303,20 @@ drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode) } static Bool -drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, - Rotation rotation, int x, int y) +drmmode_apply(xf86CrtcPtr crtc) { ScrnInfoPtr scrn = crtc->scrn; - intel_screen_private *intel = intel_get_screen_private(scrn); - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; - int saved_x, saved_y; - Rotation saved_rotation; - DisplayModeRec saved_mode; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); uint32_t *output_ids; int output_count = 0; - int ret = TRUE; - int i; - int fb_id; - drmModeModeInfo kmode; - unsigned int pitch = scrn->displayWidth * intel->cpp; - - if (drmmode->fb_id == 0) { - ret = drmModeAddFB(drmmode->fd, - scrn->virtualX, scrn->virtualY, - scrn->depth, scrn->bitsPerPixel, - pitch, intel->front_buffer->handle, - &drmmode->fb_id); - if (ret < 0) { - ErrorF("failed to add fb\n"); - return FALSE; - } - } - - saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; - saved_rotation = crtc->rotation; - - crtc->mode = *mode; - crtc->x = x; - crtc->y = y; - crtc->rotation = rotation; + int fb_id, x, y; + int i, ret; output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); - if (!output_ids) { - ret = FALSE; - goto done; - } + if (!output_ids) + return FALSE; for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; @@ -375,9 +344,9 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, crtc->gamma_blue, crtc->gamma_size); #endif - drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); - + x = crtc->x; + y = crtc->y; fb_id = drmmode->fb_id; if (drmmode_crtc->rotate_fb_id) { fb_id = drmmode_crtc->rotate_fb_id; @@ -385,11 +354,13 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, y = 0; } ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, - fb_id, x, y, output_ids, output_count, &kmode); - if (ret) + fb_id, x, y, output_ids, output_count, + &drmmode_crtc->kmode); + if (ret) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "failed to set mode: %s", strerror(-ret)); - else + ret = FALSE; + } else ret = TRUE; /* Turn on any outputs on this crtc that may have been disabled */ @@ -406,7 +377,52 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, if (scrn->pScreen) xf86_reload_cursors(scrn->pScreen); + + return ret; + done: + free(output_ids); + return FALSE; +} + +static Bool +drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + Rotation rotation, int x, int y) +{ + ScrnInfoPtr scrn = crtc->scrn; + intel_screen_private *intel = intel_get_screen_private(scrn); + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + int saved_x, saved_y; + Rotation saved_rotation; + DisplayModeRec saved_mode; + int ret = TRUE; + unsigned int pitch = scrn->displayWidth * intel->cpp; + + if (drmmode->fb_id == 0) { + ret = drmModeAddFB(drmmode->fd, + scrn->virtualX, scrn->virtualY, + scrn->depth, scrn->bitsPerPixel, + pitch, intel->front_buffer->handle, + &drmmode->fb_id); + if (ret < 0) { + ErrorF("failed to add fb\n"); + return FALSE; + } + } + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + saved_rotation = crtc->rotation; + + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + crtc->rotation = rotation; + + drmmode_ConvertToKMode(crtc->scrn, &drmmode_crtc->kmode, mode); + ret = drmmode_apply(crtc); if (!ret) { crtc->x = saved_x; crtc->y = saved_y; @@ -1296,8 +1312,8 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) if (!crtc->enabled) continue; - drmmode_set_mode_major(crtc, &crtc->mode, - crtc->rotation, crtc->x, crtc->y); + if (!drmmode_apply(crtc)) + goto fail; } if (old_fb_id)