From 1c425c4aaac50c518e9cf1be7605fc3aebbb3706 Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Mon, 20 Jan 2025 10:22:24 -0500 Subject: [PATCH] archive/tar: fix for CVE-2022-2879 Fixes: #76 In a specially crafted tar archive can cause `io.ReadAll()` to overrun the memory. The fix is taken from upstream golang, as this tar-split repo carries an old fork from upstream. Thanks to @tojoos and @bainsy88 for reporting. References: - https://nvd.nist.gov/vuln/detail/cve-2022-2879 - https://github.com/golang/go/commit/0bf7ee9 - https://go-review.googlesource.com/c/go/+/439355/2/src/archive/tar/reader.go#106 Signed-off-by: Vincent Batts --- archive/tar/format.go | 4 ++++ archive/tar/reader.go | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/archive/tar/format.go b/archive/tar/format.go index 1f89d0c..6097798 100644 --- a/archive/tar/format.go +++ b/archive/tar/format.go @@ -143,6 +143,10 @@ const ( blockSize = 512 // Size of each block in a tar stream nameSize = 100 // Max length of the name field in USTAR format prefixSize = 155 // Max length of the prefix field in USTAR format + + // Max length of a special file (PAX header, GNU long name or link). + // This matches the limit used by libarchive. + maxSpecialFileSize = 1 << 20 ) // blockPadding computes the number of bytes needed to pad offset up to the diff --git a/archive/tar/reader.go b/archive/tar/reader.go index 6a6b3e0..248a7cc 100644 --- a/archive/tar/reader.go +++ b/archive/tar/reader.go @@ -144,7 +144,7 @@ func (tr *Reader) next() (*Header, error) { continue // This is a meta header affecting the next header case TypeGNULongName, TypeGNULongLink: format.mayOnlyBe(FormatGNU) - realname, err := io.ReadAll(tr) + realname, err := readSpecialFile(tr) if err != nil { return nil, err } @@ -338,7 +338,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { // parsePAX parses PAX headers. // If an extended header (type 'x') is invalid, ErrHeader is returned func parsePAX(r io.Reader) (map[string]string, error) { - buf, err := io.ReadAll(r) + buf, err := readSpecialFile(r) if err != nil { return nil, err } @@ -889,6 +889,16 @@ func tryReadFull(r io.Reader, b []byte) (n int, err error) { return n, err } +// readSpecialFile is like io.ReadAll except it returns +// ErrFieldTooLong if more than maxSpecialFileSize is read. +func readSpecialFile(r io.Reader) ([]byte, error) { + buf, err := io.ReadAll(io.LimitReader(r, maxSpecialFileSize+1)) + if len(buf) > maxSpecialFileSize { + return nil, ErrFieldTooLong + } + return buf, err +} + // discard skips n bytes in r, reporting an error if unable to do so. func discard(tr *Reader, n int64) error { var seekSkipped, copySkipped int64