Skip to content

Commit f7a68d3

Browse files
neildgopherbot
authored andcommitted
archive/tar: set a limit on the size of GNU sparse file 1.0 regions
Sparse files in tar archives contain only the non-zero components of the file. There are several different encodings for sparse files. When reading GNU tar pax 1.0 sparse files, archive/tar did not set a limit on the size of the sparse region data. A malicious archive containing a large number of sparse blocks could cause archive/tar to read an unbounded amount of data from the archive into memory. Since a malicious input can be highly compressable, a small compressed input could cause very large allocations. Cap the size of the sparse block data to the same limit used for PAX headers (1 MiB). Thanks to Harshit Gupta (Mr HAX) (https://www.linkedin.com/in/iam-harshit-gupta/) for reporting this issue. Fixes CVE-2025-58183 Fixes golang#75677 Change-Id: I70b907b584a7b8676df8a149a1db728ae681a770 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2800 Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-by: Nicholas Husin <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/go/+/709861 Auto-Submit: Michael Pratt <[email protected]> TryBot-Bypass: Michael Pratt <[email protected]> Reviewed-by: Carlos Amedee <[email protected]>
1 parent 4631656 commit f7a68d3

File tree

4 files changed

+13
-2
lines changed

4 files changed

+13
-2
lines changed

src/archive/tar/common.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ var (
3939
errMissData = errors.New("archive/tar: sparse file references non-existent data")
4040
errUnrefData = errors.New("archive/tar: sparse file contains unreferenced data")
4141
errWriteHole = errors.New("archive/tar: write non-NUL byte in sparse hole")
42+
errSparseTooLong = errors.New("archive/tar: sparse map too long")
4243
)
4344

4445
type headerError []string

src/archive/tar/reader.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -531,12 +531,17 @@ func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
531531
cntNewline int64
532532
buf bytes.Buffer
533533
blk block
534+
totalSize int
534535
)
535536

536537
// feedTokens copies data in blocks from r into buf until there are
537538
// at least cnt newlines in buf. It will not read more blocks than needed.
538539
feedTokens := func(n int64) error {
539540
for cntNewline < n {
541+
totalSize += len(blk)
542+
if totalSize > maxSpecialFileSize {
543+
return errSparseTooLong
544+
}
540545
if _, err := mustReadFull(r, blk[:]); err != nil {
541546
return err
542547
}
@@ -569,8 +574,8 @@ func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
569574
}
570575

571576
// Parse for all member entries.
572-
// numEntries is trusted after this since a potential attacker must have
573-
// committed resources proportional to what this library used.
577+
// numEntries is trusted after this since feedTokens limits the number of
578+
// tokens based on maxSpecialFileSize.
574579
if err := feedTokens(2 * numEntries); err != nil {
575580
return nil, err
576581
}

src/archive/tar/reader_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,11 @@ func TestReader(t *testing.T) {
621621
},
622622
Format: FormatPAX,
623623
}},
624+
}, {
625+
// Small compressed file that uncompresses to
626+
// a file with a very large GNU 1.0 sparse map.
627+
file: "testdata/gnu-sparse-many-zeros.tar.bz2",
628+
err: errSparseTooLong,
624629
}}
625630

626631
for _, v := range vectors {
1.6 KB
Binary file not shown.

0 commit comments

Comments
 (0)