aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/archive/tar/format.go6
-rw-r--r--src/archive/tar/reader.go28
-rw-r--r--src/archive/tar/reader_test.go11
3 files changed, 41 insertions, 4 deletions
diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go
index 9954b4d9f5..32e58a9d9b 100644
--- a/src/archive/tar/format.go
+++ b/src/archive/tar/format.go
@@ -147,6 +147,12 @@ const (
// Max length of a special file (PAX header, GNU long name or link).
// This matches the limit used by libarchive.
maxSpecialFileSize = 1 << 20
+
+ // Maximum number of sparse file entries.
+ // We should never actually hit this limit
+ // (every sparse encoding will first be limited by maxSpecialFileSize),
+ // but this adds an additional layer of defense.
+ maxSparseFileEntries = 1 << 20
)
// blockPadding computes the number of bytes needed to pad offset up to the
diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go
index 16ac2f5b17..f85b998625 100644
--- a/src/archive/tar/reader.go
+++ b/src/archive/tar/reader.go
@@ -490,7 +490,8 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, err
}
s := blk.toGNU().sparse()
spd := make(sparseDatas, 0, s.maxEntries())
- for {
+ totalSize := len(s)
+ for totalSize < maxSpecialFileSize {
for i := 0; i < s.maxEntries(); i++ {
// This termination condition is identical to GNU and BSD tar.
if s.entry(i).offset()[0] == 0x00 {
@@ -501,7 +502,11 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, err
if p.err != nil {
return nil, p.err
}
- spd = append(spd, sparseEntry{Offset: offset, Length: length})
+ var err error
+ spd, err = appendSparseEntry(spd, sparseEntry{Offset: offset, Length: length})
+ if err != nil {
+ return nil, err
+ }
}
if s.isExtended()[0] > 0 {
@@ -510,10 +515,12 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, err
return nil, err
}
s = blk.toSparse()
+ totalSize += len(s)
continue
}
return spd, nil // Done
}
+ return nil, errSparseTooLong
}
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
@@ -586,7 +593,10 @@ func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
if err1 != nil || err2 != nil {
return nil, ErrHeader
}
- spd = append(spd, sparseEntry{Offset: offset, Length: length})
+ spd, err = appendSparseEntry(spd, sparseEntry{Offset: offset, Length: length})
+ if err != nil {
+ return nil, err
+ }
}
return spd, nil
}
@@ -620,12 +630,22 @@ func readGNUSparseMap0x1(paxHdrs map[string]string) (sparseDatas, error) {
if err1 != nil || err2 != nil {
return nil, ErrHeader
}
- spd = append(spd, sparseEntry{Offset: offset, Length: length})
+ spd, err = appendSparseEntry(spd, sparseEntry{Offset: offset, Length: length})
+ if err != nil {
+ return nil, err
+ }
sparseMap = sparseMap[2:]
}
return spd, nil
}
+func appendSparseEntry(spd sparseDatas, ent sparseEntry) (sparseDatas, error) {
+ if len(spd) >= maxSparseFileEntries {
+ return nil, errSparseTooLong
+ }
+ return append(spd, ent), nil
+}
+
// Read reads from the current file in the tar archive.
// It returns (0, io.EOF) when it reaches the end of that file,
// until [Next] is called to advance to the next file.
diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go
index c7611ca044..a324674cb7 100644
--- a/src/archive/tar/reader_test.go
+++ b/src/archive/tar/reader_test.go
@@ -1145,6 +1145,17 @@ func TestReadOldGNUSparseMap(t *testing.T) {
input: makeInput(FormatGNU, "",
makeSparseStrings(sparseDatas{{10 << 30, 512}, {20 << 30, 512}})...),
wantMap: sparseDatas{{10 << 30, 512}, {20 << 30, 512}},
+ }, {
+ input: makeInput(FormatGNU, "",
+ makeSparseStrings(func() sparseDatas {
+ var datas sparseDatas
+ // This is more than enough entries to exceed our limit.
+ for i := range int64(1 << 20) {
+ datas = append(datas, sparseEntry{i * 2, (i * 2) + 1})
+ }
+ return datas
+ }())...),
+ wantErr: errSparseTooLong,
}}
for i, v := range vectors {