Skip to content

Commit 3157439

Browse files
jeffallennigeltao
authored andcommitted
image/tiff: do not allow zero bits per sample
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]>
1 parent d8e202c commit 3157439

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

Diff for: tiff/reader.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error {
231231
off += 2
232232
}
233233
}
234-
} else if d.bpp == 8 {
234+
} else {
235235
var off int
236236
n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
237237
for y := ymin; y < ymax; y++ {
@@ -436,6 +436,14 @@ func newDecoder(r io.Reader) (*decoder, error) {
436436
return nil, FormatError("BitsPerSample tag missing")
437437
}
438438
d.bpp = d.firstVal(tBitsPerSample)
439+
switch d.bpp {
440+
case 0:
441+
return nil, FormatError("BitsPerSample must not be 0")
442+
case 1, 8, 16:
443+
// Nothing to do, these are accepted by this implementation.
444+
default:
445+
return nil, UnsupportedError(fmt.Sprintf("BitsPerSample of %v", d.bpp))
446+
}
439447

440448
// Determine the image mode.
441449
switch d.firstVal(tPhotometricInterpretation) {

Diff for: tiff/reader_test.go

+24-1
Original file line numberDiff line numberDiff line change
@@ -255,12 +255,35 @@ func TestLargeIFDEntry(t *testing.T) {
255255
}
256256
}
257257

258+
// TestZeroBitsPerSample verifies that an IFD with a bitsPerSample of 0 does not cause a crash.
259+
// Issue 10711.
260+
func TestZeroBitsPerSample(t *testing.T) {
261+
contents, err := ioutil.ReadFile(testdataDir + "bw-deflate.tiff")
262+
if err != nil {
263+
t.Fatal(err)
264+
}
265+
266+
// Mutate the loaded image to have the problem.
267+
// 02 01: tag number (tBitsPerSample)
268+
// 03 00: data type (short, or uint16)
269+
// 01 00 00 00: count
270+
// ?? 00 00 00: value (1 -> 0)
271+
find := []byte{2, 1, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0}
272+
repl := []byte{2, 1, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0}
273+
contents = bytes.Replace(contents, find, repl, 1)
274+
275+
_, err = Decode(bytes.NewReader(contents))
276+
if err == nil {
277+
t.Fatal("Decode with 0 bits per sample: got nil error, want non-nil")
278+
}
279+
}
280+
258281
// benchmarkDecode benchmarks the decoding of an image.
259282
func benchmarkDecode(b *testing.B, filename string) {
260283
b.StopTimer()
261284
contents, err := ioutil.ReadFile(testdataDir + filename)
262285
if err != nil {
263-
panic(err)
286+
b.Fatal(err)
264287
}
265288
r := &buffer{buf: contents}
266289
b.StartTimer()

0 commit comments

Comments
 (0)