diff options
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2023-45290.patch')
-rw-r--r-- | meta/recipes-devtools/go/go-1.14/CVE-2023-45290.patch | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45290.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-45290.patch new file mode 100644 index 0000000000..ddc2f67c96 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45290.patch | |||
@@ -0,0 +1,271 @@ | |||
1 | From bf80213b121074f4ad9b449410a4d13bae5e9be0 Mon Sep 17 00:00:00 2001 | ||
2 | From: Damien Neil <dneil@google.com> | ||
3 | Date: Tue, 16 Jan 2024 15:37:52 -0800 | ||
4 | Subject: [PATCH] [release-branch.go1.21] net/textproto, mime/multipart: avoid | ||
5 | unbounded read in MIME header | ||
6 | |||
7 | mime/multipart.Reader.ReadForm allows specifying the maximum amount | ||
8 | of memory that will be consumed by the form. While this limit is | ||
9 | correctly applied to the parsed form data structure, it was not | ||
10 | being applied to individual header lines in a form. | ||
11 | |||
12 | For example, when presented with a form containing a header line | ||
13 | that never ends, ReadForm will continue to read the line until it | ||
14 | runs out of memory. | ||
15 | |||
16 | Limit the amount of data consumed when reading a header. | ||
17 | |||
18 | Fixes CVE-2023-45290 | ||
19 | Fixes #65389 | ||
20 | For #65383 | ||
21 | |||
22 | Change-Id: I7f9264d25752009e95f6b2c80e3d76aaf321d658 | ||
23 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2134435 | ||
24 | Reviewed-by: Roland Shoemaker <bracewell@google.com> | ||
25 | Reviewed-by: Tatiana Bradley <tatianabradley@google.com> | ||
26 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173776 | ||
27 | Reviewed-by: Carlos Amedee <amedee@google.com> | ||
28 | Reviewed-on: https://go-review.googlesource.com/c/go/+/569240 | ||
29 | Auto-Submit: Michael Knyszek <mknyszek@google.com> | ||
30 | LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> | ||
31 | Reviewed-by: Carlos Amedee <carlos@golang.org> | ||
32 | |||
33 | Upstream-Status: Backport [https://github.com/golang/go/commit/bf80213b121074f4ad9b449410a4d13bae5e9be0] | ||
34 | CVE: CVE-2023-45290 | ||
35 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
36 | --- | ||
37 | src/mime/multipart/formdata_test.go | 42 +++++++++++++++++++++++++ | ||
38 | src/net/textproto/reader.go | 48 ++++++++++++++++++++--------- | ||
39 | src/net/textproto/reader_test.go | 12 ++++++++ | ||
40 | 3 files changed, 87 insertions(+), 15 deletions(-) | ||
41 | |||
42 | diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go | ||
43 | index c78eeb7..f729da6 100644 | ||
44 | --- a/src/mime/multipart/formdata_test.go | ||
45 | +++ b/src/mime/multipart/formdata_test.go | ||
46 | @@ -421,6 +421,48 @@ func TestReadFormLimits(t *testing.T) { | ||
47 | } | ||
48 | } | ||
49 | |||
50 | +func TestReadFormEndlessHeaderLine(t *testing.T) { | ||
51 | + for _, test := range []struct { | ||
52 | + name string | ||
53 | + prefix string | ||
54 | + }{{ | ||
55 | + name: "name", | ||
56 | + prefix: "X-", | ||
57 | + }, { | ||
58 | + name: "value", | ||
59 | + prefix: "X-Header: ", | ||
60 | + }, { | ||
61 | + name: "continuation", | ||
62 | + prefix: "X-Header: foo\r\n ", | ||
63 | + }} { | ||
64 | + t.Run(test.name, func(t *testing.T) { | ||
65 | + const eol = "\r\n" | ||
66 | + s := `--boundary` + eol | ||
67 | + s += `Content-Disposition: form-data; name="a"` + eol | ||
68 | + s += `Content-Type: text/plain` + eol | ||
69 | + s += test.prefix | ||
70 | + fr := io.MultiReader( | ||
71 | + strings.NewReader(s), | ||
72 | + neverendingReader('X'), | ||
73 | + ) | ||
74 | + r := NewReader(fr, "boundary") | ||
75 | + _, err := r.ReadForm(1 << 20) | ||
76 | + if err != ErrMessageTooLarge { | ||
77 | + t.Fatalf("ReadForm(1 << 20): %v, want ErrMessageTooLarge", err) | ||
78 | + } | ||
79 | + }) | ||
80 | + } | ||
81 | +} | ||
82 | + | ||
83 | +type neverendingReader byte | ||
84 | + | ||
85 | +func (r neverendingReader) Read(p []byte) (n int, err error) { | ||
86 | + for i := range p { | ||
87 | + p[i] = byte(r) | ||
88 | + } | ||
89 | + return len(p), nil | ||
90 | +} | ||
91 | + | ||
92 | func BenchmarkReadForm(b *testing.B) { | ||
93 | for _, test := range []struct { | ||
94 | name string | ||
95 | diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go | ||
96 | index ad2d777..cea6613 100644 | ||
97 | --- a/src/net/textproto/reader.go | ||
98 | +++ b/src/net/textproto/reader.go | ||
99 | @@ -17,6 +17,10 @@ import ( | ||
100 | "sync" | ||
101 | ) | ||
102 | |||
103 | +// TODO: This should be a distinguishable error (ErrMessageTooLarge) | ||
104 | +// to allow mime/multipart to detect it. | ||
105 | +var errMessageTooLarge = errors.New("message too large") | ||
106 | + | ||
107 | // A Reader implements convenience methods for reading requests | ||
108 | // or responses from a text protocol network connection. | ||
109 | type Reader struct { | ||
110 | @@ -38,13 +42,13 @@ func NewReader(r *bufio.Reader) *Reader { | ||
111 | // ReadLine reads a single line from r, | ||
112 | // eliding the final \n or \r\n from the returned string. | ||
113 | func (r *Reader) ReadLine() (string, error) { | ||
114 | - line, err := r.readLineSlice() | ||
115 | + line, err := r.readLineSlice(-1) | ||
116 | return string(line), err | ||
117 | } | ||
118 | |||
119 | // ReadLineBytes is like ReadLine but returns a []byte instead of a string. | ||
120 | func (r *Reader) ReadLineBytes() ([]byte, error) { | ||
121 | - line, err := r.readLineSlice() | ||
122 | + line, err := r.readLineSlice(-1) | ||
123 | if line != nil { | ||
124 | buf := make([]byte, len(line)) | ||
125 | copy(buf, line) | ||
126 | @@ -53,7 +57,10 @@ func (r *Reader) ReadLineBytes() ([]byte, error) { | ||
127 | return line, err | ||
128 | } | ||
129 | |||
130 | -func (r *Reader) readLineSlice() ([]byte, error) { | ||
131 | +// readLineSlice reads a single line from r, | ||
132 | +// up to lim bytes long (or unlimited if lim is less than 0), | ||
133 | +// eliding the final \r or \r\n from the returned string. | ||
134 | +func (r *Reader) readLineSlice(lim int64) ([]byte, error) { | ||
135 | r.closeDot() | ||
136 | var line []byte | ||
137 | for { | ||
138 | @@ -61,6 +68,9 @@ func (r *Reader) readLineSlice() ([]byte, error) { | ||
139 | if err != nil { | ||
140 | return nil, err | ||
141 | } | ||
142 | + if lim >= 0 && int64(len(line))+int64(len(l)) > lim { | ||
143 | + return nil, errMessageTooLarge | ||
144 | + } | ||
145 | // Avoid the copy if the first call produced a full line. | ||
146 | if line == nil && !more { | ||
147 | return l, nil | ||
148 | @@ -93,7 +103,7 @@ func (r *Reader) readLineSlice() ([]byte, error) { | ||
149 | // A line consisting of only white space is never continued. | ||
150 | // | ||
151 | func (r *Reader) ReadContinuedLine() (string, error) { | ||
152 | - line, err := r.readContinuedLineSlice(noValidation) | ||
153 | + line, err := r.readContinuedLineSlice(-1, noValidation) | ||
154 | return string(line), err | ||
155 | } | ||
156 | |||
157 | @@ -114,7 +124,7 @@ func trim(s []byte) []byte { | ||
158 | // ReadContinuedLineBytes is like ReadContinuedLine but | ||
159 | // returns a []byte instead of a string. | ||
160 | func (r *Reader) ReadContinuedLineBytes() ([]byte, error) { | ||
161 | - line, err := r.readContinuedLineSlice(noValidation) | ||
162 | + line, err := r.readContinuedLineSlice(-1, noValidation) | ||
163 | if line != nil { | ||
164 | buf := make([]byte, len(line)) | ||
165 | copy(buf, line) | ||
166 | @@ -127,13 +137,14 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, error) { | ||
167 | // returning a byte slice with all lines. The validateFirstLine function | ||
168 | // is run on the first read line, and if it returns an error then this | ||
169 | // error is returned from readContinuedLineSlice. | ||
170 | -func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([]byte, error) { | ||
171 | +// It reads up to lim bytes of data (or unlimited if lim is less than 0). | ||
172 | +func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) { | ||
173 | if validateFirstLine == nil { | ||
174 | return nil, fmt.Errorf("missing validateFirstLine func") | ||
175 | } | ||
176 | |||
177 | // Read the first line. | ||
178 | - line, err := r.readLineSlice() | ||
179 | + line, err := r.readLineSlice(lim) | ||
180 | if err != nil { | ||
181 | return nil, err | ||
182 | } | ||
183 | @@ -161,13 +172,21 @@ func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([ | ||
184 | // copy the slice into buf. | ||
185 | r.buf = append(r.buf[:0], trim(line)...) | ||
186 | |||
187 | + if lim < 0 { | ||
188 | + lim = math.MaxInt64 | ||
189 | + } | ||
190 | + lim -= int64(len(r.buf)) | ||
191 | + | ||
192 | // Read continuation lines. | ||
193 | for r.skipSpace() > 0 { | ||
194 | - line, err := r.readLineSlice() | ||
195 | + r.buf = append(r.buf, ' ') | ||
196 | + if int64(len(r.buf)) >= lim { | ||
197 | + return nil, errMessageTooLarge | ||
198 | + } | ||
199 | + line, err := r.readLineSlice(lim - int64(len(r.buf))) | ||
200 | if err != nil { | ||
201 | break | ||
202 | } | ||
203 | - r.buf = append(r.buf, ' ') | ||
204 | r.buf = append(r.buf, trim(line)...) | ||
205 | } | ||
206 | return r.buf, nil | ||
207 | @@ -512,7 +531,8 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) | ||
208 | |||
209 | // The first line cannot start with a leading space. | ||
210 | if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { | ||
211 | - line, err := r.readLineSlice() | ||
212 | + const errorLimit = 80 // arbitrary limit on how much of the line we'll quote | ||
213 | + line, err := r.readLineSlice(errorLimit) | ||
214 | if err != nil { | ||
215 | return m, err | ||
216 | } | ||
217 | @@ -520,7 +540,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) | ||
218 | } | ||
219 | |||
220 | for { | ||
221 | - kv, err := r.readContinuedLineSlice(mustHaveFieldNameColon) | ||
222 | + kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon) | ||
223 | if len(kv) == 0 { | ||
224 | return m, err | ||
225 | } | ||
226 | @@ -541,7 +561,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) | ||
227 | |||
228 | maxHeaders-- | ||
229 | if maxHeaders < 0 { | ||
230 | - return nil, errors.New("message too large") | ||
231 | + return nil, errMessageTooLarge | ||
232 | } | ||
233 | |||
234 | // backport 5c55ac9bf1e5f779220294c843526536605f42ab | ||
235 | @@ -567,9 +587,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) | ||
236 | } | ||
237 | maxMemory -= int64(len(value)) | ||
238 | if maxMemory < 0 { | ||
239 | - // TODO: This should be a distinguishable error (ErrMessageTooLarge) | ||
240 | - // to allow mime/multipart to detect it. | ||
241 | - return m, errors.New("message too large") | ||
242 | + return m, errMessageTooLarge | ||
243 | } | ||
244 | if vv == nil && len(strs) > 0 { | ||
245 | // More than likely this will be a single-element key. | ||
246 | diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go | ||
247 | index 3ae0de1..db1ed91 100644 | ||
248 | --- a/src/net/textproto/reader_test.go | ||
249 | +++ b/src/net/textproto/reader_test.go | ||
250 | @@ -34,6 +34,18 @@ func TestReadLine(t *testing.T) { | ||
251 | } | ||
252 | } | ||
253 | |||
254 | +func TestReadLineLongLine(t *testing.T) { | ||
255 | + line := strings.Repeat("12345", 10000) | ||
256 | + r := reader(line + "\r\n") | ||
257 | + s, err := r.ReadLine() | ||
258 | + if err != nil { | ||
259 | + t.Fatalf("Line 1: %v", err) | ||
260 | + } | ||
261 | + if s != line { | ||
262 | + t.Fatalf("%v-byte line does not match expected %v-byte line", len(s), len(line)) | ||
263 | + } | ||
264 | +} | ||
265 | + | ||
266 | func TestReadContinuedLine(t *testing.T) { | ||
267 | r := reader("line1\nline\n 2\nline3\n") | ||
268 | s, err := r.ReadContinuedLine() | ||
269 | -- | ||
270 | 2.25.1 | ||
271 | |||