From 6d9b900a6f25274ca28a33c2cb5550dbb5f01be1 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 5 May 2017 16:44:42 +1000 Subject: [PATCH] image/gif: don't panic on large or nil-containing color.Palettes. Fixes #20249 Change-Id: I5dceaef31de96345f8e6c155e12775dc4cc31bfb Reviewed-on: https://go-review.googlesource.com/42790 Reviewed-by: Brad Fitzpatrick --- src/image/gif/writer.go | 37 ++++++++++++++++++++++++++++-------- src/image/gif/writer_test.go | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/image/gif/writer.go b/src/image/gif/writer.go index 1918196884..e68f7a4ed5 100644 --- a/src/image/gif/writer.go +++ b/src/image/gif/writer.go @@ -132,7 +132,12 @@ func (e *encoder) writeHeader() { e.buf[1] = e.g.BackgroundIndex e.buf[2] = 0x00 // Pixel Aspect Ratio. e.write(e.buf[:3]) - e.globalCT = encodeColorTable(e.globalColorTable[:], p, paddedSize) + var err error + e.globalCT, err = encodeColorTable(e.globalColorTable[:], p, paddedSize) + if err != nil && e.err == nil { + e.err = err + return + } e.write(e.globalColorTable[:e.globalCT]) } else { // All frames have a local color table, so a global color table @@ -149,8 +154,9 @@ func (e *encoder) writeHeader() { e.buf[1] = 0xff // Application Label. e.buf[2] = 0x0b // Block Size. e.write(e.buf[:3]) - _, e.err = io.WriteString(e.w, "NETSCAPE2.0") // Application Identifier. - if e.err != nil { + _, err := io.WriteString(e.w, "NETSCAPE2.0") // Application Identifier. + if err != nil && e.err == nil { + e.err = err return } e.buf[0] = 0x03 // Block Size. @@ -161,11 +167,18 @@ func (e *encoder) writeHeader() { } } -func encodeColorTable(dst []byte, p color.Palette, size int) int { +func encodeColorTable(dst []byte, p color.Palette, size int) (int, error) { + if uint(size) >= uint(len(log2Lookup)) { + return 0, errors.New("gif: cannot encode color table with more than 256 entries") + } n := log2Lookup[size] for i := 0; i < n; i++ { if i < len(p) { - r, g, b, _ := p[i].RGBA() + c := p[i] + if c == nil { + return 0, errors.New("gif: cannot encode color table with nil entries") + } + r, g, b, _ := c.RGBA() dst[3*i+0] = uint8(r >> 8) dst[3*i+1] = uint8(g >> 8) dst[3*i+2] = uint8(b >> 8) @@ -176,7 +189,7 @@ func encodeColorTable(dst []byte, p color.Palette, size int) int { dst[3*i+2] = 0x00 } } - return 3 * n + return 3 * n, nil } func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) { @@ -201,6 +214,10 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) transparentIndex := -1 for i, c := range pm.Palette { + if c == nil { + e.err = errors.New("gif: cannot encode color table with nil entries") + return + } if _, _, _, a := c.RGBA(); a == 0 { transparentIndex = i break @@ -235,8 +252,12 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) e.write(e.buf[:9]) paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n). - ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize) - if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) { + if ct, err := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize); err != nil { + if e.err == nil { + e.err = err + } + return + } else if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) { // Use a local color table. e.writeByte(fColorTable | uint8(paddedSize)) e.write(e.localColorTable[:ct]) diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go index 775ccea31d..bbedbfc36e 100644 --- a/src/image/gif/writer_test.go +++ b/src/image/gif/writer_test.go @@ -438,6 +438,39 @@ func TestEncodePalettes(t *testing.T) { } } +func TestEncodeBadPalettes(t *testing.T) { + const w, h = 5, 5 + for _, n := range []int{256, 257} { + for _, nilColors := range []bool{false, true} { + pal := make(color.Palette, n) + if !nilColors { + for i := range pal { + pal[i] = color.Black + } + } + + err := EncodeAll(ioutil.Discard, &GIF{ + Image: []*image.Paletted{ + image.NewPaletted(image.Rect(0, 0, w, h), pal), + }, + Delay: make([]int, 1), + Disposal: make([]byte, 1), + Config: image.Config{ + ColorModel: pal, + Width: w, + Height: h, + }, + }) + + got := err != nil + want := n > 256 || nilColors + if got != want { + t.Errorf("n=%d, nilColors=%t: err != nil: got %t, want %t", n, nilColors, got, want) + } + } + } +} + func BenchmarkEncode(b *testing.B) { b.StopTimer() -- 2.50.0