]> Cypherpunks repositories - gostls13.git/commitdiff
image/gif: do not allow pixels outside the current palette
authorJeff R. Allen <jra@nella.org>
Mon, 1 Jul 2013 04:11:45 +0000 (14:11 +1000)
committerNigel Tao <nigeltao@golang.org>
Mon, 1 Jul 2013 04:11:45 +0000 (14:11 +1000)
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

src/pkg/image/gif/reader.go
src/pkg/image/gif/reader_test.go

index 8e8531f9b6be39cc0e8a3fbd64c462ed3d8dc5b6..3b4417767fedf9d65da64ba207fca34a5968dffb 100644 (file)
@@ -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)
index dcc6c6dd3e45937a072ee4755f85d3edabb64a31..e81e02331fb7b46174627a3a3e75733029f83c2e 100644 (file)
@@ -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)
+       }
+}