diff --git a/tiff/reader.go b/tiff/reader.go index 0b24c53..146ba59 100644 --- a/tiff/reader.go +++ b/tiff/reader.go @@ -164,9 +164,12 @@ func (d *decoder) parseIFD(p []byte) error { } // readBits reads n bits from the internal buffer starting at the current offset. -func (d *decoder) readBits(n uint) uint32 { +func (d *decoder) readBits(n uint) (v uint32, ok bool) { for d.nbits < n { d.v <<= 8 + if d.off >= len(d.buf) { + return 0, false + } d.v |= uint32(d.buf[d.off]) d.off++ d.nbits += 8 @@ -174,7 +177,7 @@ func (d *decoder) readBits(n uint) uint32 { d.nbits -= n rv := d.v >> d.nbits d.v &^= rv << d.nbits - return rv + return rv, true } // flushBits discards the unread bits in the buffer used by readBits. @@ -203,12 +206,14 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { if d.firstVal(tPredictor) == prHorizontal { if d.bpp == 16 { var off int - spp := len(d.features[tBitsPerSample]) // samples per pixel - bpp := spp * 2 // bytes per pixel + n := 2 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel for y := ymin; y < ymax; y++ { - off += spp * 2 - for x := 0; x < (xmax-xmin-1)*bpp; x += 2 { - v0 := d.byteOrder.Uint16(d.buf[off-bpp : off-bpp+2]) + off += n + for x := 0; x < (xmax-xmin-1)*n; x += 2 { + if off+2 > len(d.buf) { + return FormatError("not enough pixel data") + } + v0 := d.byteOrder.Uint16(d.buf[off-n : off-n+2]) v1 := d.byteOrder.Uint16(d.buf[off : off+2]) d.byteOrder.PutUint16(d.buf[off:off+2], v1+v0) off += 2 @@ -216,11 +221,14 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { } } else if d.bpp == 8 { var off int - spp := len(d.features[tBitsPerSample]) // samples per pixel + n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel for y := ymin; y < ymax; y++ { - off += spp - for x := 0; x < (xmax-xmin-1)*spp; x++ { - d.buf[off] += d.buf[off-spp] + off += n + for x := 0; x < (xmax-xmin-1)*n; x++ { + if off >= len(d.buf) { + return FormatError("not enough pixel data") + } + d.buf[off] += d.buf[off-n] off++ } } @@ -235,6 +243,9 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { img := dst.(*image.Gray16) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { + if d.off+2 > len(d.buf) { + return FormatError("not enough pixel data") + } v := d.byteOrder.Uint16(d.buf[d.off : d.off+2]) d.off += 2 if d.mode == mGrayInvert { @@ -248,11 +259,15 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { max := uint32((1 << d.bpp) - 1) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { - v := uint8(d.readBits(d.bpp) * 0xff / max) + v, ok := d.readBits(d.bpp) + if !ok { + return FormatError("not enough pixel data") + } + v = v * 0xff / max if d.mode == mGrayInvert { v = 0xff - v } - img.SetGray(x, y, color.Gray{v}) + img.SetGray(x, y, color.Gray{uint8(v)}) } d.flushBits() } @@ -261,7 +276,11 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { img := dst.(*image.Paletted) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { - img.SetColorIndex(x, y, uint8(d.readBits(d.bpp))) + v, ok := d.readBits(d.bpp) + if !ok { + return FormatError("not enough pixel data") + } + img.SetColorIndex(x, y, uint8(v)) } d.flushBits() } @@ -270,6 +289,9 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { img := dst.(*image.RGBA64) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { + if d.off+6 > len(d.buf) { + return FormatError("not enough pixel data") + } r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) @@ -284,6 +306,9 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { max := img.PixOffset(rMaxX, y) off := (y - ymin) * (xmax - xmin) * 3 for i := min; i < max; i += 4 { + if d.off+3 > len(d.buf) { + return FormatError("not enough pixel data") + } img.Pix[i+0] = d.buf[off+0] img.Pix[i+1] = d.buf[off+1] img.Pix[i+2] = d.buf[off+2] @@ -297,6 +322,9 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { img := dst.(*image.NRGBA64) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { + if d.off+8 > len(d.buf) { + return FormatError("not enough pixel data") + } r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) @@ -310,8 +338,11 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { for y := ymin; y < rMaxY; y++ { min := img.PixOffset(xmin, y) max := img.PixOffset(rMaxX, y) - buf := d.buf[(y-ymin)*(xmax-xmin)*4 : (y-ymin+1)*(xmax-xmin)*4] - copy(img.Pix[min:max], buf) + i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4 + if i1 > len(d.buf) { + return FormatError("not enough pixel data") + } + copy(img.Pix[min:max], d.buf[i0:i1]) } } case mRGBA: @@ -319,6 +350,9 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { img := dst.(*image.RGBA64) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { + if d.off+8 > len(d.buf) { + return FormatError("not enough pixel data") + } r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) @@ -332,8 +366,11 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { for y := ymin; y < rMaxY; y++ { min := img.PixOffset(xmin, y) max := img.PixOffset(rMaxX, y) - buf := d.buf[(y-ymin)*(xmax-xmin)*4 : (y-ymin+1)*(xmax-xmin)*4] - copy(img.Pix[min:max], buf) + i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4 + if i1 > len(d.buf) { + return FormatError("not enough pixel data") + } + copy(img.Pix[min:max], d.buf[i0:i1]) } } } diff --git a/tiff/reader_test.go b/tiff/reader_test.go index 5bd5ee2..5041099 100644 --- a/tiff/reader_test.go +++ b/tiff/reader_test.go @@ -75,6 +75,32 @@ func TestUnpackBits(t *testing.T) { } } +func TestShortBlockData(t *testing.T) { + b, err := ioutil.ReadFile("../testdata/bw-uncompressed.tiff") + if err != nil { + t.Fatal(err) + } + // The bw-uncompressed.tiff image is a 153x55 bi-level image. This is 1 bit + // per pixel, or 20 bytes per row, times 55 rows, or 1100 bytes of pixel + // data. 1100 in hex is 0x44c, or "\x4c\x04" in little-endian. We replace + // that byte count (StripByteCounts-tagged data) by something less than + // that, so that there is not enough pixel data. + old := []byte{0x4c, 0x04} + new := []byte{0x01, 0x01} + i := bytes.Index(b, old) + if i < 0 { + t.Fatal(`could not find "\x4c\x04" byte count`) + } + if bytes.Contains(b[i+len(old):], old) { + t.Fatal(`too many occurrences of "\x4c\x04"`) + } + b[i+0] = new[0] + b[i+1] = new[1] + if _, err = Decode(bytes.NewReader(b)); err == nil { + t.Fatal("got nil error, want non-nil") + } +} + func compare(t *testing.T, img0, img1 image.Image) { b0 := img0.Bounds() b1 := img1.Bounds()