From: Jeff R. Allen Date: Mon, 1 Jul 2013 04:11:45 +0000 (+1000) Subject: image/gif: do not allow pixels outside the current palette X-Git-Tag: go1.2rc2~1135 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8192017e14a0902293717ef3c847672a9b9a0da4;p=gostls13.git image/gif: do not allow pixels outside the current palette After loading a frame of a GIF, check that each pixel is inside the frame's palette. Fixes #5401. R=nigeltao, r CC=golang-dev https://golang.org/cl/10597043 --- diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go index 8e8531f9b6..3b4417767f 100644 --- a/src/pkg/image/gif/reader.go +++ b/src/pkg/image/gif/reader.go @@ -20,6 +20,7 @@ import ( var ( errNotEnough = errors.New("gif: not enough image data") errTooMuch = errors.New("gif: too much image data") + errBadPixel = errors.New("gif: invalid pixel value") ) // If the io.Reader does not also have ReadByte, then decode will introduce its own buffering. @@ -210,6 +211,15 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { return errTooMuch } + // Check that the color indexes are inside the palette. + if len(m.Palette) < 256 { + for _, pixel := range m.Pix { + if int(pixel) >= len(m.Palette) { + return errBadPixel + } + } + } + // Undo the interlacing if necessary. if d.imageFields&ifInterlace != 0 { uninterlace(m) diff --git a/src/pkg/image/gif/reader_test.go b/src/pkg/image/gif/reader_test.go index dcc6c6dd3e..e81e02331f 100644 --- a/src/pkg/image/gif/reader_test.go +++ b/src/pkg/image/gif/reader_test.go @@ -9,16 +9,16 @@ import ( "testing" ) -func TestDecode(t *testing.T) { - // header and trailer are parts of a valid 2x1 GIF image. - const ( - header = "GIF89a" + - "\x02\x00\x01\x00" + // width=2, height=1 - "\x80\x00\x00" + // headerFields=(a color map of 2 pixels), backgroundIndex, aspect - "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette - trailer = "\x3b" - ) +// header, palette and trailer are parts of a valid 2x1 GIF image. +const ( + header = "GIF89a" + + "\x02\x00\x01\x00" + // width=2, height=1 + "\x80\x00\x00" // headerFields=(a color map of 2 pixels), backgroundIndex, aspect + palette = "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette + trailer = "\x3b" +) +func TestDecode(t *testing.T) { // lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes. lzwEncode := func(n int) []byte { b := &bytes.Buffer{} @@ -42,6 +42,7 @@ func TestDecode(t *testing.T) { for _, tc := range testCases { b := &bytes.Buffer{} b.WriteString(header) + b.WriteString(palette) // Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2 // then this should result in an invalid GIF image. First, write a // magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags @@ -114,7 +115,7 @@ func try(t *testing.T, b []byte, want string) { } func TestBounds(t *testing.T) { - // make a local copy of testGIF + // Make a local copy of testGIF. gif := make([]byte, len(testGIF)) copy(gif, testGIF) // Make the bounds too big, just by one. @@ -136,3 +137,61 @@ func TestBounds(t *testing.T) { } try(t, gif, want) } + +func TestNoPalette(t *testing.T) { + b := &bytes.Buffer{} + + // Manufacture a GIF with no palette, so any pixel at all + // will be invalid. + b.WriteString(header[:len(header)-3]) + b.WriteString("\x00\x00\x00") // No global palette. + + // Image descriptor: 2x1, no local palette. + b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02") + + // Encode the pixels: neither is in range, because there is no palette. + pix := []byte{0, 128} + enc := &bytes.Buffer{} + w := lzw.NewWriter(enc, lzw.LSB, 2) + w.Write(pix) + w.Close() + b.WriteByte(byte(len(enc.Bytes()))) + b.Write(enc.Bytes()) + b.WriteByte(0x00) // An empty block signifies the end of the image data. + + b.WriteString(trailer) + + try(t, b.Bytes(), "gif: invalid pixel value") +} + +func TestPixelOutsidePaletteRange(t *testing.T) { + for _, pval := range []byte{0, 1, 2, 3, 255} { + b := &bytes.Buffer{} + + // Manufacture a GIF with a 2 color palette. + b.WriteString(header) + b.WriteString(palette) + + // Image descriptor: 2x1, no local palette. + b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02") + + // Encode the pixels; some pvals trigger the expected error. + pix := []byte{pval, pval} + enc := &bytes.Buffer{} + w := lzw.NewWriter(enc, lzw.LSB, 2) + w.Write(pix) + w.Close() + b.WriteByte(byte(len(enc.Bytes()))) + b.Write(enc.Bytes()) + b.WriteByte(0x00) // An empty block signifies the end of the image data. + + b.WriteString(trailer) + + // No error expected, unless the pixels are beyond the 2 color palette. + want := "" + if pval >= 2 { + want = "gif: invalid pixel value" + } + try(t, b.Bytes(), want) + } +}