Skip to content

Commit

Permalink
image/tiff: do not allow zero bits per sample
Browse files Browse the repository at this point in the history
Fuzzing detected a divide by zero in images with 0 bits
per sample. Instead of panicing, return an error. Do more
validation of bits per sample so that the package only
supports what we've actually tested.

Fixes golang/go#10711.

Change-Id: Ib41b5cd798c32b06429164c9bc471f5f321d88c5
Reviewed-on: https://go-review.googlesource.com/10943
Reviewed-by: Benny Siegert <[email protected]>
Reviewed-by: Nigel Tao <[email protected]>
  • Loading branch information
yi-ge3 committed Mar 10, 2022
1 parent 01afa82 commit 7cde6eb
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
10 changes: 9 additions & 1 deletion tiff/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error {
off += 2
}
}
} else if d.bpp == 8 {
} else {
var off int
n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
for y := ymin; y < ymax; y++ {
Expand Down Expand Up @@ -436,6 +436,14 @@ func newDecoder(r io.Reader) (*decoder, error) {
return nil, FormatError("BitsPerSample tag missing")
}
d.bpp = d.firstVal(tBitsPerSample)
switch d.bpp {
case 0:
return nil, FormatError("BitsPerSample must not be 0")
case 1, 8, 16:
// Nothing to do, these are accepted by this implementation.
default:
return nil, UnsupportedError(fmt.Sprintf("BitsPerSample of %v", d.bpp))
}

// Determine the image mode.
switch d.firstVal(tPhotometricInterpretation) {
Expand Down
25 changes: 24 additions & 1 deletion tiff/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,35 @@ func TestLargeIFDEntry(t *testing.T) {
}
}

// TestZeroBitsPerSample verifies that an IFD with a bitsPerSample of 0 does not cause a crash.
// Issue 10711.
func TestZeroBitsPerSample(t *testing.T) {
contents, err := ioutil.ReadFile(testdataDir + "bw-deflate.tiff")
if err != nil {
t.Fatal(err)
}

// Mutate the loaded image to have the problem.
// 02 01: tag number (tBitsPerSample)
// 03 00: data type (short, or uint16)
// 01 00 00 00: count
// ?? 00 00 00: value (1 -> 0)
find := []byte{2, 1, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0}
repl := []byte{2, 1, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0}
contents = bytes.Replace(contents, find, repl, 1)

_, err = Decode(bytes.NewReader(contents))
if err == nil {
t.Fatal("Decode with 0 bits per sample: got nil error, want non-nil")
}
}

// benchmarkDecode benchmarks the decoding of an image.
func benchmarkDecode(b *testing.B, filename string) {
b.StopTimer()
contents, err := ioutil.ReadFile(testdataDir + filename)
if err != nil {
panic(err)
b.Fatal(err)
}
r := &buffer{buf: contents}
b.StartTimer()
Expand Down

0 comments on commit 7cde6eb

Please sign in to comment.