xref: /OK3568_Linux_fs/yocto/poky/meta/recipes-devtools/go/go-1.18/CVE-2022-2879.patch (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1From d064ed520a7cc6b480f9565e30751e695d394f4e Mon Sep 17 00:00:00 2001
2From: Damien Neil <dneil@google.com>
3Date: Fri, 2 Sep 2022 20:45:18 -0700
4Subject: [PATCH] archive/tar: limit size of headers
5
6Set a 1MiB limit on special file blocks (PAX headers, GNU long names,
7GNU link names), to avoid reading arbitrarily large amounts of data
8into memory.
9
10Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting
11this issue.
12
13Fixes CVE-2022-2879
14Updates #54853
15Fixes #55925
16
17Change-Id: I85136d6ff1e0af101a112190e027987ab4335680
18Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1565555
19Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
20Run-TryBot: Roland Shoemaker <bracewell@google.com>
21Reviewed-by: Roland Shoemaker <bracewell@google.com>
22(cherry picked from commit 6ee768cef6b82adf7a90dcf367a1699ef694f3b2)
23Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1590622
24Reviewed-by: Damien Neil <dneil@google.com>
25Reviewed-by: Julie Qiu <julieqiu@google.com>
26Reviewed-on: https://go-review.googlesource.com/c/go/+/438500
27Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
28Reviewed-by: Carlos Amedee <carlos@golang.org>
29Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
30Run-TryBot: Carlos Amedee <carlos@golang.org>
31TryBot-Result: Gopher Robot <gobot@golang.org>
32
33CVE: CVE-2022-2879
34Upstream-Status: Backport [0a723816cd205576945fa57fbdde7e6532d59d08]
35Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
36---
37 src/archive/tar/format.go      |  4 ++++
38 src/archive/tar/reader.go      | 14 ++++++++++++--
39 src/archive/tar/reader_test.go |  8 +++++++-
40 src/archive/tar/writer.go      |  3 +++
41 src/archive/tar/writer_test.go | 27 +++++++++++++++++++++++++++
42 5 files changed, 53 insertions(+), 3 deletions(-)
43
44diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go
45index cfe24a5..6642364 100644
46--- a/src/archive/tar/format.go
47+++ b/src/archive/tar/format.go
48@@ -143,6 +143,10 @@ const (
49 	blockSize  = 512 // Size of each block in a tar stream
50 	nameSize   = 100 // Max length of the name field in USTAR format
51 	prefixSize = 155 // Max length of the prefix field in USTAR format
52+
53+	// Max length of a special file (PAX header, GNU long name or link).
54+	// This matches the limit used by libarchive.
55+	maxSpecialFileSize = 1 << 20
56 )
57
58 // blockPadding computes the number of bytes needed to pad offset up to the
59diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go
60index 1b1d5b4..f645af8 100644
61--- a/src/archive/tar/reader.go
62+++ b/src/archive/tar/reader.go
63@@ -103,7 +103,7 @@ func (tr *Reader) next() (*Header, error) {
64 			continue // This is a meta header affecting the next header
65 		case TypeGNULongName, TypeGNULongLink:
66 			format.mayOnlyBe(FormatGNU)
67-			realname, err := io.ReadAll(tr)
68+			realname, err := readSpecialFile(tr)
69 			if err != nil {
70 				return nil, err
71 			}
72@@ -293,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
73 // parsePAX parses PAX headers.
74 // If an extended header (type 'x') is invalid, ErrHeader is returned
75 func parsePAX(r io.Reader) (map[string]string, error) {
76-	buf, err := io.ReadAll(r)
77+	buf, err := readSpecialFile(r)
78 	if err != nil {
79 		return nil, err
80 	}
81@@ -826,6 +826,16 @@ func tryReadFull(r io.Reader, b []byte) (n int, err error) {
82 	return n, err
83 }
84
85+// readSpecialFile is like io.ReadAll except it returns
86+// ErrFieldTooLong if more than maxSpecialFileSize is read.
87+func readSpecialFile(r io.Reader) ([]byte, error) {
88+	buf, err := io.ReadAll(io.LimitReader(r, maxSpecialFileSize+1))
89+	if len(buf) > maxSpecialFileSize {
90+		return nil, ErrFieldTooLong
91+	}
92+	return buf, err
93+}
94+
95 // discard skips n bytes in r, reporting an error if unable to do so.
96 func discard(r io.Reader, n int64) error {
97 	// If possible, Seek to the last byte before the end of the data section.
98diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go
99index 789ddc1..926dc3d 100644
100--- a/src/archive/tar/reader_test.go
101+++ b/src/archive/tar/reader_test.go
102@@ -6,6 +6,7 @@ package tar
103
104 import (
105 	"bytes"
106+	"compress/bzip2"
107 	"crypto/md5"
108 	"errors"
109 	"fmt"
110@@ -625,9 +626,14 @@ func TestReader(t *testing.T) {
111 			}
112 			defer f.Close()
113
114+			var fr io.Reader = f
115+			if strings.HasSuffix(v.file, ".bz2") {
116+				fr = bzip2.NewReader(fr)
117+			}
118+
119 			// Capture all headers and checksums.
120 			var (
121-				tr      = NewReader(f)
122+				tr      = NewReader(fr)
123 				hdrs    []*Header
124 				chksums []string
125 				rdbuf   = make([]byte, 8)
126diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go
127index e80498d..893eac0 100644
128--- a/src/archive/tar/writer.go
129+++ b/src/archive/tar/writer.go
130@@ -199,6 +199,9 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
131 			flag = TypeXHeader
132 		}
133 		data := buf.String()
134+		if len(data) > maxSpecialFileSize {
135+			return ErrFieldTooLong
136+		}
137 		if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal {
138 			return err // Global headers return here
139 		}
140diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go
141index a00f02d..4e709e5 100644
142--- a/src/archive/tar/writer_test.go
143+++ b/src/archive/tar/writer_test.go
144@@ -1006,6 +1006,33 @@ func TestIssue12594(t *testing.T) {
145 	}
146 }
147
148+func TestWriteLongHeader(t *testing.T) {
149+	for _, test := range []struct {
150+		name string
151+		h    *Header
152+	}{{
153+		name: "name too long",
154+		h:    &Header{Name: strings.Repeat("a", maxSpecialFileSize)},
155+	}, {
156+		name: "linkname too long",
157+		h:    &Header{Linkname: strings.Repeat("a", maxSpecialFileSize)},
158+	}, {
159+		name: "uname too long",
160+		h:    &Header{Uname: strings.Repeat("a", maxSpecialFileSize)},
161+	}, {
162+		name: "gname too long",
163+		h:    &Header{Gname: strings.Repeat("a", maxSpecialFileSize)},
164+	}, {
165+		name: "PAX header too long",
166+		h:    &Header{PAXRecords: map[string]string{"GOLANG.x": strings.Repeat("a", maxSpecialFileSize)}},
167+	}} {
168+		w := NewWriter(io.Discard)
169+		if err := w.WriteHeader(test.h); err != ErrFieldTooLong {
170+			t.Errorf("%v: w.WriteHeader() = %v, want ErrFieldTooLong", test.name, err)
171+		}
172+	}
173+}
174+
175 // testNonEmptyWriter wraps an io.Writer and ensures that
176 // Write is never called with an empty buffer.
177 type testNonEmptyWriter struct{ io.Writer }
178