diff --git a/archive/tar/reader.go b/archive/tar/reader.go index 0b0c3b1..dbc5698 100644 --- a/archive/tar/reader.go +++ b/archive/tar/reader.go @@ -899,6 +899,9 @@ func (sfr *sparseFileReader) Read(b []byte) (n int, err error) { // Otherwise, we're at the end of the file return 0, io.EOF } + if sfr.tot < sfr.sp[0].offset { + return 0, io.ErrUnexpectedEOF + } if sfr.pos < sfr.sp[0].offset { // We're in a hole n = sfr.readHole(b, sfr.sp[0].offset) diff --git a/archive/tar/reader_test.go b/archive/tar/reader_test.go index ab1e844..6ffb383 100644 --- a/archive/tar/reader_test.go +++ b/archive/tar/reader_test.go @@ -757,3 +757,22 @@ func TestNegativeHdrSize(t *testing.T) { } io.Copy(ioutil.Discard, r) } + +// This used to hang in (*sparseFileReader).readHole due to missing +// verification of sparse offsets against file size. +func TestIssue10968(t *testing.T) { + f, err := os.Open("testdata/issue10968.tar") + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := NewReader(f) + _, err = r.Next() + if err != nil { + t.Fatal(err) + } + _, err = io.Copy(ioutil.Discard, r) + if err != io.ErrUnexpectedEOF { + t.Fatalf("expected %q, got %q", io.ErrUnexpectedEOF, err) + } +} diff --git a/archive/tar/testdata/issue10968.tar b/archive/tar/testdata/issue10968.tar new file mode 100644 index 0000000..1cc837b Binary files /dev/null and b/archive/tar/testdata/issue10968.tar differ