diff --git a/tiff/reader.go b/tiff/reader.go index 94c4cf7..3f6e397 100644 --- a/tiff/reader.go +++ b/tiff/reader.go @@ -71,7 +71,15 @@ func (d *decoder) firstVal(tag int) uint { // or Long type, and returns the decoded uint values. func (d *decoder) ifdUint(p []byte) (u []uint, err error) { var raw []byte + if len(p) < ifdLen { + return nil, FormatError("bad IFD entry") + } + datatype := d.byteOrder.Uint16(p[2:4]) + if dt := int(datatype); dt <= 0 || dt >= len(lengths) { + return nil, UnsupportedError("IFD entry datatype") + } + count := d.byteOrder.Uint32(p[4:8]) if count > math.MaxInt32/lengths[datatype] { return nil, FormatError("IFD data too large") diff --git a/tiff/reader_test.go b/tiff/reader_test.go index d79c9e9..1a72ac3 100644 --- a/tiff/reader_test.go +++ b/tiff/reader_test.go @@ -6,6 +6,7 @@ package tiff import ( "bytes" + "encoding/binary" "image" "io/ioutil" "os" @@ -101,6 +102,27 @@ func TestShortBlockData(t *testing.T) { } } +func TestDecodeInvalidDataType(t *testing.T) { + b, err := ioutil.ReadFile("../testdata/bw-uncompressed.tiff") + if err != nil { + t.Fatal(err) + } + + // off is the offset of the ImageWidth tag. It is the offset of the overall + // IFD block (0x00000454), plus 2 for the uint16 number of IFD entries, plus 12 + // to skip the first entry. + const off = 0x00000454 + 2 + 12*1 + + if v := binary.LittleEndian.Uint16(b[off : off+2]); v != tImageWidth { + t.Fatal(`could not find ImageWidth tag`) + } + binary.LittleEndian.PutUint16(b[off+2:], uint16(len(lengths))) // invalid datatype + + 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()