hi, i previously emailed jonas tonight with a patch that can be used to incorporate fixes for the above bugs in etch. for posterity, here it is. i hear there are going to be a few more security issues surfacing in the near future, so i won't be sending this to the security team yet, but if i haven't heard a request not to do so i will probably do so after the other issues are dealt with.
sean
diff -u libgd2-2.0.33/debian/changelog libgd2-2.0.33/debian/changelog --- libgd2-2.0.33/debian/changelog +++ libgd2-2.0.33/debian/changelog @@ -1,3 +1,17 @@ +libgd2 (2.0.33-5.2etch1) unstable; urgency=high + + * Security NMU. + * Includes multiple fixes for GIF loader, as found in CVE-2006-4484 + Thanks to Pierre Joye (closes: #425978). + * Fix for potential DoS in imagearc and imagefilledarc functions. + Thanks again to Pierre Joye (closes: #425754). + * Fix for CVE-2007-0455: libgd2: "gdImageStringFTEx()" Denial of Service + Thanks to Alex de Oliveira Silva for reporting this (closes: #408982). + * Fix for CVE-2007-2756: infinite loop in PNG loader. Thanks again + to Pierre Joye (closes: #425584). + + -- sean finney <[EMAIL PROTECTED]> Tue, 29 May 2007 20:00:07 +0200 + libgd2 (2.0.33-5.2) unstable; urgency=high * Non-maintainer upload. diff -u libgd2-2.0.33/debian/patches/series libgd2-2.0.33/debian/patches/series --- libgd2-2.0.33/debian/patches/series +++ libgd2-2.0.33/debian/patches/series @@ -7,0 +8,4 @@ +0001-gifloader_issues +0002-arc-angle-dos +0003-CVE-2007-0455.patch +0004-CVE-2007-2756.patch only in patch2: unchanged: --- libgd2-2.0.33.orig/debian/patches/0004-CVE-2007-2756.patch +++ libgd2-2.0.33/debian/patches/0004-CVE-2007-2756.patch @@ -0,0 +1,15 @@ +--- libgd2-2.0.33-5.2-patched/gd_png.c 2007-05-15 19:44:43.000000000 +0200 ++++ libgd2-2.0.33-5.2-patched-fx/gd_png.c 2007-05-22 17:20:03.000000000 +0200 +@@ -84,7 +84,11 @@ gdPngErrorHandler (png_structp png_ptr, + static void + gdPngReadData (png_structp png_ptr, png_bytep data, png_size_t length) + { +- gdGetBuf (data, length, (gdIOCtx *) png_get_io_ptr (png_ptr)); ++ int check; ++ check = gdGetBuf (data, length, (gdIOCtx *) png_get_io_ptr (png_ptr)); ++ if (check != length) { ++ png_error(png_ptr, "Read Error: truncated data"); ++ } + } + + static void only in patch2: unchanged: --- libgd2-2.0.33.orig/debian/patches/0003-CVE-2007-0455.patch +++ libgd2-2.0.33/debian/patches/0003-CVE-2007-0455.patch @@ -0,0 +1,13 @@ +Index: libgd2-2.0.33/gdft.c +=================================================================== +--- libgd2-2.0.33.orig/gdft.c 2007-05-29 19:25:39.000000000 +0200 ++++ libgd2-2.0.33/gdft.c 2007-05-29 19:33:50.000000000 +0200 +@@ -1169,7 +1169,7 @@ + { + ch = c & 0xFF; /* don't extend sign */ + } +- next++; ++ if (*next) next++; + } + break; + case gdFTEX_Big5: only in patch2: unchanged: --- libgd2-2.0.33.orig/debian/patches/0001-gifloader_issues +++ libgd2-2.0.33/debian/patches/0001-gifloader_issues @@ -0,0 +1,510 @@ +Index: libgd2-2.0.33/gd_gif_in.c +=================================================================== +--- libgd2-2.0.33.orig/gd_gif_in.c 2007-05-29 17:59:50.000000000 +0200 ++++ libgd2-2.0.33/gd_gif_in.c 2007-05-29 18:48:04.000000000 +0200 +@@ -1,13 +1,13 @@ +-#ifdef HAVE_CONFIG_H +-#include "config.h" +-#endif +- + #include <stdio.h> + #include <math.h> + #include <string.h> + #include <stdlib.h> + #include "gd.h" + ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ + /* Used only when debugging GIF compression code */ + /* #define DEBUGGING_ENVARS */ + +@@ -46,7 +46,7 @@ + #define LOCALCOLORMAP 0x80 + #define BitSet(byte, bit) (((byte) & (bit)) == (bit)) + +-#define ReadOK(file,buffer,len) (gdGetBuf(buffer, len, file) >= 0) ++#define ReadOK(file,buffer,len) (gdGetBuf(buffer, len, file) > 0) + + #define LM_to_uint(a,b) (((b)<<8)|(a)) + +@@ -72,11 +72,29 @@ + } Gif89 = { -1, -1, -1, 0 }; + #endif + ++#define STACK_SIZE ((1<<(MAX_LWZ_BITS))*2) ++ ++typedef struct { ++ unsigned char buf[280]; ++ int curbit, lastbit, done, last_byte; ++} CODE_STATIC_DATA; ++ ++typedef struct { ++ int fresh; ++ int code_size, set_code_size; ++ int max_code, max_code_size; ++ int firstcode, oldcode; ++ int clear_code, end_code; ++ int table[2][(1<< MAX_LWZ_BITS)]; ++ int stack[STACK_SIZE], *sp; ++ CODE_STATIC_DATA scd; ++} LZW_STATIC_DATA; ++ + static int ReadColorMap (gdIOCtx *fd, int number, unsigned char (*buffer)[256]); + static int DoExtension (gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP); + static int GetDataBlock (gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP); +-static int GetCode (gdIOCtx *fd, int code_size, int flag, int *ZeroDataBlockP); +-static int LWZReadByte (gdIOCtx *fd, int flag, int input_code_size, int *ZeroDataBlockP); ++static int GetCode (gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP); ++static int LWZReadByte (gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP); + + static void ReadImage (gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP); /*1.4//, int ignore); */ + +@@ -114,15 +132,14 @@ + unsigned char c; + unsigned char ColorMap[3][MAXCOLORMAPSIZE]; + unsigned char localColorMap[3][MAXCOLORMAPSIZE]; +- int imw, imh; +- int useGlobalColormap; ++ int imw, imh, screen_width, screen_height; ++ int gif87a, useGlobalColormap; + int bitPixel; + int i; + /*1.4//int imageCount = 0; */ +- char version[4]; + /* 2.0.28: threadsafe storage */ + int ZeroDataBlock = FALSE; +- int maxcount = 1024; ++ int haveGlobalColormap; + + gdImagePtr im = 0; + if (! ReadOK(fd,buf,6)) { +@@ -131,10 +148,11 @@ + if (strncmp((char *)buf,"GIF",3) != 0) { + return 0; + } +- strncpy(version, (char *)buf + 3, 3); +- version[3] = '\0'; +- +- if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) { ++ if (memcmp((char *)buf+3, "87a", 3) == 0) { ++ gif87a = 1; ++ } else if (memcmp((char *)buf+3, "89a", 3) == 0) { ++ gif87a = 0; ++ } else { + return 0; + } + if (! ReadOK(fd,buf,7)) { +@@ -146,13 +164,19 @@ + Background = buf[5]; + AspectRatio = buf[6]; + #endif ++ screen_width = imw = LM_to_uint(buf[0],buf[1]); ++ screen_height = imh = LM_to_uint(buf[2],buf[3]); + +- if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ ++ haveGlobalColormap = BitSet(buf[4], LOCALCOLORMAP); /* Global Colormap */ ++ if (haveGlobalColormap) { + if (ReadColorMap(fd, BitPixel, ColorMap)) { + return 0; + } + } + for (;;) { ++ int top, left; ++ int width, height; ++ + if (! ReadOK(fd,&c,1)) { + return 0; + } +@@ -169,8 +193,6 @@ + } + + if (c != ',') { /* Not a valid start character */ +- if (--maxcount < 0) +- goto terminated; /* Looping */ + continue; + } + +@@ -183,21 +205,35 @@ + useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP); + + bitPixel = 1<<((buf[8]&0x07)+1); ++ left = LM_to_uint(buf[0], buf[1]); ++ top = LM_to_uint(buf[2], buf[3]); ++ width = LM_to_uint(buf[4], buf[5]); ++ height = LM_to_uint(buf[6], buf[7]); ++ ++ if (left + width > screen_width || top + height > screen_height) { ++ if (VERBOSE) { ++ printf("Frame is not confined to screen dimension.\n"); ++ } ++ return 0; ++ } + +- imw = LM_to_uint(buf[4],buf[5]); +- imh = LM_to_uint(buf[6],buf[7]); +- if (!(im = gdImageCreate(imw, imh))) { ++ if (!(im = gdImageCreate(width, height))) { + return 0; + } + im->interlace = BitSet(buf[8], INTERLACE); + if (! useGlobalColormap) { + if (ReadColorMap(fd, bitPixel, localColorMap)) { ++ gdImageDestroy(im); + return 0; + } +- ReadImage(im, fd, imw, imh, localColorMap, ++ ReadImage(im, fd, width, height, localColorMap, + BitSet(buf[8], INTERLACE), &ZeroDataBlock); + } else { +- ReadImage(im, fd, imw, imh, ++ if (!haveGlobalColormap) { ++ gdImageDestroy(im); ++ return 0; ++ } ++ ReadImage(im, fd, width, height, + ColorMap, + BitSet(buf[8], INTERLACE), &ZeroDataBlock); + } +@@ -254,11 +290,11 @@ + static int + DoExtension(gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP) + { +- static unsigned char buf[256]; +- int maxcount = 1024; ++ unsigned char buf[256]; + + switch (label) { + case 0xf9: /* Graphic Control Extension */ ++ memset(buf, 0, 4); /* initialize a few bytes in the case the next function fails */ + (void) GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP); + #if 0 + Gif89.disposal = (buf[0] >> 2) & 0x7; +@@ -268,13 +304,12 @@ + if ((buf[0] & 0x1) != 0) + *Transparent = buf[3]; + +- while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0 && --maxcount >= 0) +- ; ++ while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0); + return FALSE; + default: + break; + } +- while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0 && --maxcount >= 0) ++ while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0) + ; + + return FALSE; +@@ -317,185 +352,174 @@ + } + + static int +-GetCode_(gdIOCtx *fd, int code_size, int flag, int *ZeroDataBlockP) ++GetCode_(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP) + { +- static unsigned char buf[280]; +- static int curbit, lastbit, done, last_byte; + int i, j, ret; +- unsigned char count; ++ unsigned char count; + + if (flag) { +- curbit = 0; +- lastbit = 0; +- done = FALSE; ++ scd->curbit = 0; ++ scd->lastbit = 0; ++ scd->last_byte = 0; ++ scd->done = FALSE; + return 0; + } + +- if ( (curbit+code_size) >= lastbit) { +- if (done) { +- if (curbit >= lastbit) { ++ if ( (scd->curbit + code_size) >= scd->lastbit) { ++ if (scd->done) { ++ if (scd->curbit >= scd->lastbit) { + /* Oh well */ + } + return -1; + } +- buf[0] = buf[last_byte-2]; +- buf[1] = buf[last_byte-1]; ++ scd->buf[0] = scd->buf[scd->last_byte-2]; ++ scd->buf[1] = scd->buf[scd->last_byte-1]; + +- if ((count = GetDataBlock(fd, &buf[2], ZeroDataBlockP)) == 0) +- done = TRUE; ++ if ((count = GetDataBlock(fd, &scd->buf[2], ZeroDataBlockP)) <= 0) ++ scd->done = TRUE; + +- last_byte = 2 + count; +- curbit = (curbit - lastbit) + 16; +- lastbit = (2+count)*8 ; ++ scd->last_byte = 2 + count; ++ scd->curbit = (scd->curbit - scd->lastbit) + 16; ++ scd->lastbit = (2+count)*8 ; + } + + ret = 0; +- for (i = curbit, j = 0; j < code_size; ++i, ++j) +- ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; ++ for (i = scd->curbit, j = 0; j < code_size; ++i, ++j) ++ ret |= ((scd->buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; + +- curbit += code_size; ++ scd->curbit += code_size; + return ret; + } + + static int +-GetCode(gdIOCtx *fd, int code_size, int flag, int *ZeroDataBlockP) ++GetCode(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP) + { + int rv; + +- rv = GetCode_(fd,code_size,flag, ZeroDataBlockP); ++ rv = GetCode_(fd, scd, code_size,flag, ZeroDataBlockP); + if (VERBOSE) printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv); + return(rv); + } + +-#define STACK_SIZE ((1<<(MAX_LWZ_BITS))*2) + static int +-LWZReadByte_(gdIOCtx *fd, int flag, int input_code_size, int *ZeroDataBlockP) ++LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP) + { +- static int fresh = FALSE; +- int code, incode; +- static int code_size, set_code_size; +- static int max_code, max_code_size; +- static int firstcode, oldcode; +- static int clear_code, end_code; +- static int table[2][(1<< MAX_LWZ_BITS)]; +- static int stack[STACK_SIZE], *sp; +- register int i; ++ int code, incode, i; + + if (flag) { +- set_code_size = input_code_size; +- code_size = set_code_size+1; +- clear_code = 1 << set_code_size ; +- end_code = clear_code + 1; +- max_code_size = 2*clear_code; +- max_code = clear_code+2; ++ sd->set_code_size = input_code_size; ++ sd->code_size = sd->set_code_size+1; ++ sd->clear_code = 1 << sd->set_code_size ; ++ sd->end_code = sd->clear_code + 1; ++ sd->max_code_size = 2*sd->clear_code; ++ sd->max_code = sd->clear_code+2; + +- GetCode(fd, 0, TRUE, ZeroDataBlockP); ++ GetCode(fd, &sd->scd, 0, TRUE, ZeroDataBlockP); + +- fresh = TRUE; ++ sd->fresh = TRUE; + +- for (i = 0; i < clear_code; ++i) { +- table[0][i] = 0; +- table[1][i] = i; ++ for (i = 0; i < sd->clear_code; ++i) { ++ sd->table[0][i] = 0; ++ sd->table[1][i] = i; + } + for (; i < (1<<MAX_LWZ_BITS); ++i) +- table[0][i] = table[1][0] = 0; ++ sd->table[0][i] = sd->table[1][0] = 0; + +- sp = stack; ++ sd->sp = sd->stack; + + return 0; +- } else if (fresh) { +- fresh = FALSE; ++ } else if (sd->fresh) { ++ sd->fresh = FALSE; + do { +- firstcode = oldcode = +- GetCode(fd, code_size, FALSE, ZeroDataBlockP); +- } while (firstcode == clear_code); +- return firstcode; ++ sd->firstcode = sd->oldcode = ++ GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP); ++ } while (sd->firstcode == sd->clear_code); ++ return sd->firstcode; + } + +- if (sp > stack) +- return *--sp; +- +- while ((code = GetCode(fd, code_size, FALSE, ZeroDataBlockP)) >= 0) { +- if (code == clear_code) { +- for (i = 0; i < clear_code; ++i) { +- table[0][i] = 0; +- table[1][i] = i; ++ if (sd->sp > sd->stack) ++ return *--sd->sp; ++ ++ while ((code = GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP)) >= 0) { ++ if (code == sd->clear_code) { ++ for (i = 0; i < sd->clear_code; ++i) { ++ sd->table[0][i] = 0; ++ sd->table[1][i] = i; + } + for (; i < (1<<MAX_LWZ_BITS); ++i) +- table[0][i] = table[1][i] = 0; +- code_size = set_code_size+1; +- max_code_size = 2*clear_code; +- max_code = clear_code+2; +- sp = stack; +- firstcode = oldcode = +- GetCode(fd, code_size, FALSE, ZeroDataBlockP); +- return firstcode; +- } else if (code == end_code) { ++ sd->table[0][i] = sd->table[1][i] = 0; ++ sd->code_size = sd->set_code_size+1; ++ sd->max_code_size = 2*sd->clear_code; ++ sd->max_code = sd->clear_code+2; ++ sd->sp = sd->stack; ++ sd->firstcode = sd->oldcode = ++ GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP); ++ return sd->firstcode; ++ } else if (code == sd->end_code) { + int count; + unsigned char buf[260]; +- int maxcount = 1024; + + if (*ZeroDataBlockP) + return -2; + +- while ((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0 && --maxcount >= 0) ++ while ((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0) + ; + +- if (count != 0 || maxcount < 0) ++ if (count != 0) + return -2; + } + + incode = code; + +- if (sp == (stack + STACK_SIZE)) { ++ if (sd->sp == (sd->stack + STACK_SIZE)) { + /* Bad compressed data stream */ + return -1; + } + +- if (code >= max_code) { +- *sp++ = firstcode; +- code = oldcode; ++ if (code >= sd->max_code) { ++ *sd->sp++ = sd->firstcode; ++ code = sd->oldcode; + } + +- while (code >= clear_code) { +- if (sp == (stack + STACK_SIZE)) { ++ while (code >= sd->clear_code) { ++ if (sd->sp == (sd->stack + STACK_SIZE)) { + /* Bad compressed data stream */ + return -1; + } +- *sp++ = table[1][code]; +- if (code == table[0][code]) { ++ *sd->sp++ = sd->table[1][code]; ++ if (code == sd->table[0][code]) { + /* Oh well */ + } +- code = table[0][code]; ++ code = sd->table[0][code]; + } + +- *sp++ = firstcode = table[1][code]; ++ *sd->sp++ = sd->firstcode = sd->table[1][code]; + +- if ((code = max_code) <(1<<MAX_LWZ_BITS)) { +- table[0][code] = oldcode; +- table[1][code] = firstcode; +- ++max_code; +- if ((max_code >= max_code_size) && +- (max_code_size < (1<<MAX_LWZ_BITS))) { +- max_code_size *= 2; +- ++code_size; ++ if ((code = sd->max_code) <(1<<MAX_LWZ_BITS)) { ++ sd->table[0][code] = sd->oldcode; ++ sd->table[1][code] = sd->firstcode; ++ ++sd->max_code; ++ if ((sd->max_code >= sd->max_code_size) && ++ (sd->max_code_size < (1<<MAX_LWZ_BITS))) { ++ sd->max_code_size *= 2; ++ ++sd->code_size; + } + } + +- oldcode = incode; ++ sd->oldcode = incode; + +- if (sp > stack) +- return *--sp; ++ if (sd->sp > sd->stack) ++ return *--sd->sp; + } + return code; + } + + static int +-LWZReadByte(gdIOCtx *fd, int flag, int input_code_size, int *ZeroDataBlockP) ++LWZReadByte(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP) + { + int rv; + +- rv = LWZReadByte_(fd,flag,input_code_size, ZeroDataBlockP); ++ rv = LWZReadByte_(fd, sd, flag, input_code_size, ZeroDataBlockP); + if (VERBOSE) printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv); + return(rv); + } +@@ -507,6 +531,7 @@ + int v; + int xpos = 0, ypos = 0, pass = 0; + int i; ++ LZW_STATIC_DATA sd; + + /* + ** Initialize the Compression routines +@@ -529,7 +554,7 @@ + } + /* Many (perhaps most) of these colors will remain marked open. */ + im->colorsTotal = gdMaxColors; +- if (LWZReadByte(fd, TRUE, c, ZeroDataBlockP) < 0) { ++ if (LWZReadByte(fd, &sd, TRUE, c, ZeroDataBlockP) < 0) { + return; + } + +@@ -538,12 +563,12 @@ + ** REMOVED For 1.4 + */ + /*if (ignore) { */ +- /* while (LWZReadByte(fd, FALSE, c) >= 0) */ ++ /* while (LWZReadByte(fd, &sd, FALSE, c) >= 0) */ + /* ; */ + /* return; */ + /*} */ + +- while ((v = LWZReadByte(fd,FALSE,c, ZeroDataBlockP)) >= 0 ) { ++ while ((v = LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP)) >= 0 ) { + /* This how we recognize which colors are actually used. */ + if (im->open[v]) { + im->open[v] = 0; +@@ -585,7 +610,7 @@ + } + + fini: +- if (LWZReadByte(fd,FALSE,c, ZeroDataBlockP)>=0) { ++ if (LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP) >=0) { + /* Ignore extra */ + } + } only in patch2: unchanged: --- libgd2-2.0.33.orig/debian/patches/0002-arc-angle-dos +++ libgd2-2.0.33/debian/patches/0002-arc-angle-dos @@ -0,0 +1,18 @@ +--- old/gd.c 2007-05-15 19:44:43.000000000 +0200 ++++ new/gd.c 2007-05-23 20:51:55.000000000 +0200 +@@ -1513,6 +1513,15 @@ BGD_DECLARE(void) gdImageFilledArc (gdIm + int i; + int lx = 0, ly = 0; + int fx = 0, fy = 0; ++ ++ if (s > 360) { ++ s = s % 360; ++ } ++ ++ if (e > 360) { ++ e = e % 360; ++ } ++ + while (e < s) + { + e += 360;
signature.asc
Description: This is a digitally signed message part.