aboutsummaryrefslogtreecommitdiff
path: root/src/archive/tar/reader_test.go
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2015-10-01 01:35:15 -0700
committerBrad Fitzpatrick <bradfitz@golang.org>2015-12-01 20:22:38 +0000
commit7823197e5d6a024a4fe2f4f9ca414cb5244eb10f (patch)
treeb53f115d7b1ffb70fdf9705fef95f97bb629af09 /src/archive/tar/reader_test.go
parentdd5e14a7511465d20c6e95bf54c9b8f999abbbf6 (diff)
downloadgo-7823197e5d6a024a4fe2f4f9ca414cb5244eb10f.tar.xz
archive/tar: fix issues with readGNUSparseMap1x0
Motivations: * Use of strconv.ParseInt does not properly treat integers as 64bit, preventing this function from working properly on 32bit machines. * Use of io.ReadFull does not properly detect truncated streams when the file suddenly ends on a block boundary. * The function blindly trusts user input for numEntries and allocates memory accordingly. * The function does not validate that numEntries is not negative, allowing a malicious sparse file to cause a panic during make. In general, this function was overly complicated for what it was accomplishing and it was hard to reason that it was free from bounds errors. Instead, it has been rewritten and relies on bytes.Buffer.ReadString to do the main work. So long as invariants about the number of '\n' in the buffer are maintained, it is much easier to see why this approach is correct. Change-Id: Ibb12c4126c26e0ea460ea063cd17af68e3cf609e Reviewed-on: https://go-review.googlesource.com/15174 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/archive/tar/reader_test.go')
-rw-r--r--src/archive/tar/reader_test.go99
1 files changed, 73 insertions, 26 deletions
diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go
index 51d77c1683..387c92fd25 100644
--- a/src/archive/tar/reader_test.go
+++ b/src/archive/tar/reader_test.go
@@ -727,35 +727,82 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
}
func TestReadGNUSparseMap1x0(t *testing.T) {
- // This test uses lots of holes so the sparse header takes up more than two blocks
- numEntries := 100
- expected := make([]sparseEntry, 0, numEntries)
- sparseMap := new(bytes.Buffer)
-
- fmt.Fprintf(sparseMap, "%d\n", numEntries)
- for i := 0; i < numEntries; i++ {
- offset := int64(2048 * i)
- numBytes := int64(1024)
- expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes})
- fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes)
+ var sp = []sparseEntry{{1, 2}, {3, 4}}
+ for i := 0; i < 98; i++ {
+ sp = append(sp, sparseEntry{54321, 12345})
}
- // Make the header the smallest multiple of blockSize that fits the sparseMap
- headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize
- bufLen := blockSize * headerBlocks
- buf := make([]byte, bufLen)
- copy(buf, sparseMap.Bytes())
-
- // Get an reader to read the sparse map
- r := bytes.NewReader(buf)
+ var vectors = []struct {
+ input string // Input data
+ sparseMap []sparseEntry // Expected sparse entries to be outputted
+ cnt int // Expected number of bytes read
+ err error // Expected errors that may be raised
+ }{{
+ input: "",
+ cnt: 0,
+ err: io.ErrUnexpectedEOF,
+ }, {
+ input: "ab",
+ cnt: 2,
+ err: io.ErrUnexpectedEOF,
+ }, {
+ input: strings.Repeat("\x00", 512),
+ cnt: 512,
+ err: io.ErrUnexpectedEOF,
+ }, {
+ input: strings.Repeat("\x00", 511) + "\n",
+ cnt: 512,
+ err: ErrHeader,
+ }, {
+ input: strings.Repeat("\n", 512),
+ cnt: 512,
+ err: ErrHeader,
+ }, {
+ input: "0\n" + strings.Repeat("\x00", 510) + strings.Repeat("a", 512),
+ sparseMap: []sparseEntry{},
+ cnt: 512,
+ }, {
+ input: strings.Repeat("0", 512) + "0\n" + strings.Repeat("\x00", 510),
+ sparseMap: []sparseEntry{},
+ cnt: 1024,
+ }, {
+ input: strings.Repeat("0", 1024) + "1\n2\n3\n" + strings.Repeat("\x00", 506),
+ sparseMap: []sparseEntry{{2, 3}},
+ cnt: 1536,
+ }, {
+ input: strings.Repeat("0", 1024) + "1\n2\n\n" + strings.Repeat("\x00", 509),
+ cnt: 1536,
+ err: ErrHeader,
+ }, {
+ input: strings.Repeat("0", 1024) + "1\n2\n" + strings.Repeat("\x00", 508),
+ cnt: 1536,
+ err: io.ErrUnexpectedEOF,
+ }, {
+ input: "-1\n2\n\n" + strings.Repeat("\x00", 506),
+ cnt: 512,
+ err: ErrHeader,
+ }, {
+ input: "1\nk\n2\n" + strings.Repeat("\x00", 506),
+ cnt: 512,
+ err: ErrHeader,
+ }, {
+ input: "100\n1\n2\n3\n4\n" + strings.Repeat("54321\n0000000000000012345\n", 98) + strings.Repeat("\x00", 512),
+ cnt: 2560,
+ sparseMap: sp,
+ }}
- // Read the sparse map
- sp, err := readGNUSparseMap1x0(r)
- if err != nil {
- t.Errorf("Unexpected error: %v", err)
- }
- if !reflect.DeepEqual(sp, expected) {
- t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
+ for i, v := range vectors {
+ r := strings.NewReader(v.input)
+ sp, err := readGNUSparseMap1x0(r)
+ if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) {
+ t.Errorf("test %d, readGNUSparseMap1x0(...): got %v, want %v", i, sp, v.sparseMap)
+ }
+ if numBytes := len(v.input) - r.Len(); numBytes != v.cnt {
+ t.Errorf("test %d, bytes read: got %v, want %v", i, numBytes, v.cnt)
+ }
+ if err != v.err {
+ t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
+ }
}
}