tiff: don't panic on reading short block data.

Fixes golang/go#10394

Change-Id: I12621650f0c21579047497407ca2745febe4521b
Reviewed-on: https://go-review.googlesource.com/9278
Reviewed-by: Benny Siegert <bsiegert@gmail.com>
Reviewed-by: Nigel Tao <nigeltao@golang.org>
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 @@
 }
 
 // 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 @@
 	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 @@
 	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 @@
 			}
 		} 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 @@
 			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 @@
 			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 @@
 		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 @@
 			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 @@
 				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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 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()