From 0a078f222dd5727c4e9f74f014b726d65ccb369f Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Thu, 30 Jan 2025 17:46:54 -0500 Subject: [PATCH] archive/tar: fix the archive/tar.Writer CVE The remainder of: https://github.com/golang/go/commit/0bf7ee9 Reference from https://github.com/vbatts/tar-split/issues/76#issuecomment-2618694926 Signed-off-by: Vincent Batts --- archive/tar/reader_test.go | 11 ++++++- .../tar/testdata/pax-bad-hdr-large.tar.bz2 | Bin 0 -> 156 bytes archive/tar/writer.go | 3 ++ archive/tar/writer_test.go | 27 ++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 archive/tar/testdata/pax-bad-hdr-large.tar.bz2 diff --git a/archive/tar/reader_test.go b/archive/tar/reader_test.go index 789ddc1..5a644a4 100644 --- a/archive/tar/reader_test.go +++ b/archive/tar/reader_test.go @@ -6,6 +6,7 @@ package tar import ( "bytes" + "compress/bzip2" "crypto/md5" "errors" "fmt" @@ -243,6 +244,9 @@ func TestReader(t *testing.T) { }, { file: "testdata/pax-bad-hdr-file.tar", err: ErrHeader, + }, { + file: "testdata/pax-bad-hdr-large.tar.bz2", + err: ErrFieldTooLong, }, { file: "testdata/pax-bad-mtime-file.tar", err: ErrHeader, @@ -625,9 +629,14 @@ func TestReader(t *testing.T) { } defer f.Close() + var fr io.Reader = f + if strings.HasSuffix(v.file, ".bz2") { + fr = bzip2.NewReader(fr) + } + // Capture all headers and checksums. var ( - tr = NewReader(f) + tr = NewReader(fr) hdrs []*Header chksums []string rdbuf = make([]byte, 8) diff --git a/archive/tar/testdata/pax-bad-hdr-large.tar.bz2 b/archive/tar/testdata/pax-bad-hdr-large.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..06bf710d3ae4e96a27487124f08e30c9e318699d GIT binary patch literal 156 zcmV;N0Av3`T4*^jL0KkKS;SwlM*sj&-;n5#Kmq^806<7UWm)Y~!#90LDZj0F4RNS<;o$l$z=JG_q>Xyl@Bs{9VZu K;X*?Ze#IONT1LeH literal 0 HcmV?d00001 diff --git a/archive/tar/writer.go b/archive/tar/writer.go index e80498d..893eac0 100644 --- a/archive/tar/writer.go +++ b/archive/tar/writer.go @@ -199,6 +199,9 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error { flag = TypeXHeader } data := buf.String() + if len(data) > maxSpecialFileSize { + return ErrFieldTooLong + } if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal { return err // Global headers return here } diff --git a/archive/tar/writer_test.go b/archive/tar/writer_test.go index a00f02d..4e709e5 100644 --- a/archive/tar/writer_test.go +++ b/archive/tar/writer_test.go @@ -1006,6 +1006,33 @@ func TestIssue12594(t *testing.T) { } } +func TestWriteLongHeader(t *testing.T) { + for _, test := range []struct { + name string + h *Header + }{{ + name: "name too long", + h: &Header{Name: strings.Repeat("a", maxSpecialFileSize)}, + }, { + name: "linkname too long", + h: &Header{Linkname: strings.Repeat("a", maxSpecialFileSize)}, + }, { + name: "uname too long", + h: &Header{Uname: strings.Repeat("a", maxSpecialFileSize)}, + }, { + name: "gname too long", + h: &Header{Gname: strings.Repeat("a", maxSpecialFileSize)}, + }, { + name: "PAX header too long", + h: &Header{PAXRecords: map[string]string{"GOLANG.x": strings.Repeat("a", maxSpecialFileSize)}}, + }} { + w := NewWriter(io.Discard) + if err := w.WriteHeader(test.h); err != ErrFieldTooLong { + t.Errorf("%v: w.WriteHeader() = %v, want ErrFieldTooLong", test.name, err) + } + } +} + // testNonEmptyWriter wraps an io.Writer and ensures that // Write is never called with an empty buffer. type testNonEmptyWriter struct{ io.Writer }