[PATCH] dri2: Fix xserver crash if dri2 buffer allocation fails.

Pauli Nieminen ext-pauli.nieminen at nokia.com
Fri May 14 06:25:43 PDT 2010


If driver fails to allocate memory for dri2 buffer server would crash
in send_buffers_reply.

Solution is to handle the allocation failure and return BadAlloc to
client.

Signed-off-by: Pauli Nieminen <ext-pauli.nieminen at nokia.com>
---
 hw/xfree86/dri2/dri2.c    |   69 +++++++++++++++++++++++++++++++++------------
 hw/xfree86/dri2/dri2ext.c |   13 ++++----
 2 files changed, 58 insertions(+), 24 deletions(-)

diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index 03126b0..b1bd16b 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -329,6 +329,31 @@ allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
     }
 }
 
+static void
+update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
+			     DRI2BufferPtr *buffers, int *out_count, int *width, int *height)
+{
+    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
+    int i;
+
+    if (pPriv->buffers != NULL) {
+	for (i = 0; i < pPriv->bufferCount; i++) {
+	    if (pPriv->buffers[i] != NULL) {
+		(*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
+	    }
+	}
+
+	free(pPriv->buffers);
+    }
+
+    pPriv->buffers = buffers;
+    pPriv->bufferCount = *out_count;
+    pPriv->width = pDraw->width;
+    pPriv->height = pDraw->height;
+    *width = pPriv->width;
+    *height = pPriv->height;
+}
+
 static DRI2BufferPtr *
 do_get_buffers(DrawablePtr pDraw, int *width, int *height,
 	       unsigned int *attachments, int count, int *out_count,
@@ -366,6 +391,9 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
 				     &buffers[i]))
 		buffers_changed = 1;
 
+	if (buffers[i] == NULL)
+	    goto err_out;
+
 	/* If the drawable is a window and the front-buffer is requested,
 	 * silently add the fake front-buffer to the list of requested
 	 * attachments.  The counting logic in the loop accounts for the case
@@ -398,6 +426,9 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
 				     front_format, dimensions_match,
 				     &buffers[i++]))
 	    buffers_changed = 1;
+
+	if (buffers[i] == NULL)
+	    goto err_out;
     }
 
     if (need_fake_front > 0) {
@@ -406,29 +437,15 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
 				     &buffers[i++]))
 	    buffers_changed = 1;
 
+	if (buffers[i] == NULL)
+	    goto err_out;
+
 	have_fake_front = 1;
     }
 
     *out_count = i;
 
-
-    if (pPriv->buffers != NULL) {
-	for (i = 0; i < pPriv->bufferCount; i++) {
-	    if (pPriv->buffers[i] != NULL) {
-		(*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
-	    }
-	}
-
-	free(pPriv->buffers);
-    }
-
-    pPriv->buffers = buffers;
-    pPriv->bufferCount = *out_count;
-    pPriv->width = pDraw->width;
-    pPriv->height = pDraw->height;
-    *width = pPriv->width;
-    *height = pPriv->height;
-
+    update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height);
 
     /* If the client is getting a fake front-buffer, pre-fill it with the
      * contents of the real front-buffer.  This ensures correct operation of
@@ -449,6 +466,22 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
     }
 
     return pPriv->buffers;
+
+err_out:
+
+    *out_count = 0;
+
+    for (i = 0; i < count; i++) {
+	    if (buffers[i] != NULL)
+		    (*ds->DestroyBuffer)(pDraw, buffers[i]);
+    }
+
+    free(buffers);
+    buffers = NULL;
+
+    update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height);
+
+    return buffers;
 }
 
 DRI2BufferPtr *
diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
index dd456d7..37d042b 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -206,7 +206,7 @@ ProcDRI2DestroyDrawable(ClientPtr client)
 }
 
 
-static void
+static int
 send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
 		   DRI2BufferPtr *buffers, int count, int width, int height)
 {
@@ -214,6 +214,9 @@ send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
     int skip = 0;
     int i;
 
+    if (buffers == NULL)
+	    return BadAlloc;
+
     if (pDrawable->type == DRAWABLE_WINDOW) {
 	for (i = 0; i < count; i++) {
 	    /* Do not send the real front buffer of a window to the client.
@@ -250,6 +253,7 @@ send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
 	buffer.flags = buffers[i]->flags;
 	WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
     }
+    return Success;
 }
 
 
@@ -275,9 +279,8 @@ ProcDRI2GetBuffers(ClientPtr client)
 			     attachments, stuff->count, &count);
 
 
-    send_buffers_reply(client, pDrawable, buffers, count, width, height);
+    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
 
-    return Success;
 }
 
 static int
@@ -301,9 +304,7 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client)
     buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
 				       attachments, stuff->count, &count);
 
-    send_buffers_reply(client, pDrawable, buffers, count, width, height);
-
-    return Success;
+    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
 }
 
 static int
-- 
1.6.3.3



More information about the xorg-devel mailing list