[gdk-pixbuf] pixdata: Check for RLE pixdata length



commit 10c811117efaa03e1e4d487fc6322c27299f5632
Author: Bastien Nocera <hadess hadess net>
Date:   Fri Dec 16 15:17:12 2016 +0100

    pixdata: Check for RLE pixdata length
    
    Avoid copying data from past the end of the pixdata when processing
    RLE-encoded pixdata.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=775693

 gdk-pixbuf/gdk-pixdata.c |   34 ++++++++++++++++++++++++++++++++--
 1 files changed, 32 insertions(+), 2 deletions(-)
---
diff --git a/gdk-pixbuf/gdk-pixdata.c b/gdk-pixbuf/gdk-pixdata.c
index b73e5a4..af04244 100644
--- a/gdk-pixbuf/gdk-pixdata.c
+++ b/gdk-pixbuf/gdk-pixdata.c
@@ -412,6 +412,8 @@ gdk_pixdata_from_pixbuf (GdkPixdata      *pixdata,
 /* From glib's gmem.c */
 #define SIZE_OVERFLOWS(a,b) (G_UNLIKELY ((b) > 0 && (a) > G_MAXSIZE / (b)))
 
+#define RLE_OVERRUN(offset) (rle_buffer_limit == NULL ? FALSE : rle_buffer + (offset) > rle_buffer_limit)
+
 /**
  * gdk_pixbuf_from_pixdata:
  * @pixdata: a #GdkPixdata to convert into a #GdkPixbuf.
@@ -494,13 +496,26 @@ gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
   if (encoding == GDK_PIXDATA_ENCODING_RLE)
     {
       const guint8 *rle_buffer = pixdata->pixel_data;
+      guint8 *rle_buffer_limit = NULL;
       guint8 *image_buffer = data;
       guint8 *image_limit = data + pixdata->rowstride * pixdata->height;
       gboolean check_overrun = FALSE;
 
-      while (image_buffer < image_limit)
+      if (pixdata->length >= 1)
+        rle_buffer_limit = pixdata->pixel_data + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
+
+      while (image_buffer < image_limit &&
+             (rle_buffer_limit != NULL || rle_buffer > rle_buffer_limit))
        {
-         guint length = *(rle_buffer++);
+         guint length;
+
+         if (RLE_OVERRUN(1))
+           {
+             check_overrun = TRUE;
+             break;
+           }
+
+         length = *(rle_buffer++);
 
          if (length & 128)
            {
@@ -508,6 +523,11 @@ gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
              check_overrun = image_buffer + length * bpp > image_limit;
              if (check_overrun)
                length = (image_limit - image_buffer) / bpp;
+             if (RLE_OVERRUN(bpp < 4 ? 3 : 4))
+               {
+                 check_overrun = TRUE;
+                 break;
+               }
              if (bpp < 4)      /* RGB */
                do
                  {
@@ -522,6 +542,11 @@ gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
                    image_buffer += 4;
                  }
                while (--length);
+             if (RLE_OVERRUN(bpp))
+               {
+                 check_overrun = TRUE;
+                 break;
+               }
              rle_buffer += bpp;
            }
          else
@@ -530,6 +555,11 @@ gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
              check_overrun = image_buffer + length > image_limit;
              if (check_overrun)
                length = image_limit - image_buffer;
+             if (RLE_OVERRUN(length))
+               {
+                 check_overrun = TRUE;
+                 break;
+               }
              memcpy (image_buffer, rle_buffer, length);
              image_buffer += length;
              rle_buffer += length;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]