summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch')
-rw-r--r--meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch349
1 files changed, 349 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch
new file mode 100644
index 0000000000..58c0a484ee
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch
@@ -0,0 +1,349 @@
1From 7917b5f31204528ea72e0629f0b7d52b35b27538 Mon Sep 17 00:00:00 2001
2From: Damien Neil <dneil@google.com>
3Date: Mon, 20 Mar 2023 10:43:19 -0700
4Subject: [PATCH] [release-branch.go1.19] mime/multipart: limit parsed mime message sizes
5
6The parsed forms of MIME headers and multipart forms can consume
7substantially more memory than the size of the input data.
8A malicious input containing a very large number of headers or
9form parts can cause excessively large memory allocations.
10
11Set limits on the size of MIME data:
12
13Reader.NextPart and Reader.NextRawPart limit the the number
14of headers in a part to 10000.
15
16Reader.ReadForm limits the total number of headers in all
17FileHeaders to 10000.
18
19Both of these limits may be set with with
20GODEBUG=multipartmaxheaders=<values>.
21
22Reader.ReadForm limits the number of parts in a form to 1000.
23This limit may be set with GODEBUG=multipartmaxparts=<value>.
24
25Thanks for Jakob Ackermann (@das7pad) for reporting this issue.
26
27For CVE-2023-24536
28For #59153
29For #59269
30
31Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802455
32Run-TryBot: Damien Neil <dneil@google.com>
33Reviewed-by: Roland Shoemaker <bracewell@google.com>
34Reviewed-by: Julie Qiu <julieqiu@google.com>
35Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1801087
36Reviewed-by: Damien Neil <dneil@google.com>
37Run-TryBot: Roland Shoemaker <bracewell@google.com>
38Change-Id: If134890d75f0d95c681d67234daf191ba08e6424
39Reviewed-on: https://go-review.googlesource.com/c/go/+/481985
40Run-TryBot: Michael Knyszek <mknyszek@google.com>
41Auto-Submit: Michael Knyszek <mknyszek@google.com>
42TryBot-Result: Gopher Robot <gobot@golang.org>
43Reviewed-by: Matthew Dempsky <mdempsky@google.com>
44
45Upstream-Status: Backport [https://github.com/golang/go/commit/7917b5f31204528ea72e0629f0b7d52b35b27538]
46CVE: CVE-2023-24536
47Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
48---
49 src/mime/multipart/formdata.go | 19 ++++++++-
50 src/mime/multipart/formdata_test.go | 61 ++++++++++++++++++++++++++++
51 src/mime/multipart/multipart.go | 31 ++++++++++----
52 src/mime/multipart/readmimeheader.go | 2 +-
53 src/net/textproto/reader.go | 19 +++++----
54 5 files changed, 115 insertions(+), 17 deletions(-)
55
56diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go
57index 216cccb..0b508ae 100644
58--- a/src/mime/multipart/formdata.go
59+++ b/src/mime/multipart/formdata.go
60@@ -13,6 +13,7 @@ import (
61 "math"
62 "net/textproto"
63 "os"
64+ "strconv"
65 )
66
67 // ErrMessageTooLarge is returned by ReadForm if the message form
68@@ -42,6 +43,15 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
69 numDiskFiles := 0
70 multipartFiles := godebug.Get("multipartfiles")
71 combineFiles := multipartFiles != "distinct"
72+ maxParts := 1000
73+ multipartMaxParts := godebug.Get("multipartmaxparts")
74+ if multipartMaxParts != "" {
75+ if v, err := strconv.Atoi(multipartMaxParts); err == nil && v >= 0 {
76+ maxParts = v
77+ }
78+ }
79+ maxHeaders := maxMIMEHeaders()
80+
81 defer func() {
82 if file != nil {
83 if cerr := file.Close(); err == nil {
84@@ -87,13 +97,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
85 }
86 var copyBuf []byte
87 for {
88- p, err := r.nextPart(false, maxMemoryBytes)
89+ p, err := r.nextPart(false, maxMemoryBytes, maxHeaders)
90 if err == io.EOF {
91 break
92 }
93 if err != nil {
94 return nil, err
95 }
96+ if maxParts <= 0 {
97+ return nil, ErrMessageTooLarge
98+ }
99+ maxParts--
100
101 name := p.FormName()
102 if name == "" {
103@@ -137,6 +151,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
104 if maxMemoryBytes < 0 {
105 return nil, ErrMessageTooLarge
106 }
107+ for _, v := range p.Header {
108+ maxHeaders -= int64(len(v))
109+ }
110 fh := &FileHeader{
111 Filename: filename,
112 Header: p.Header,
113diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
114index 8ed26e0..c78eeb7 100644
115--- a/src/mime/multipart/formdata_test.go
116+++ b/src/mime/multipart/formdata_test.go
117@@ -360,6 +360,67 @@ func testReadFormManyFiles(t *testing.T, distinct bool) {
118 }
119 }
120
121+func TestReadFormLimits(t *testing.T) {
122+ for _, test := range []struct {
123+ values int
124+ files int
125+ extraKeysPerFile int
126+ wantErr error
127+ godebug string
128+ }{
129+ {values: 1000},
130+ {values: 1001, wantErr: ErrMessageTooLarge},
131+ {values: 500, files: 500},
132+ {values: 501, files: 500, wantErr: ErrMessageTooLarge},
133+ {files: 1000},
134+ {files: 1001, wantErr: ErrMessageTooLarge},
135+ {files: 1, extraKeysPerFile: 9998}, // plus Content-Disposition and Content-Type
136+ {files: 1, extraKeysPerFile: 10000, wantErr: ErrMessageTooLarge},
137+ {godebug: "multipartmaxparts=100", values: 100},
138+ {godebug: "multipartmaxparts=100", values: 101, wantErr: ErrMessageTooLarge},
139+ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 48},
140+ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 50, wantErr: ErrMessageTooLarge},
141+ } {
142+ name := fmt.Sprintf("values=%v/files=%v/extraKeysPerFile=%v", test.values, test.files, test.extraKeysPerFile)
143+ if test.godebug != "" {
144+ name += fmt.Sprintf("/godebug=%v", test.godebug)
145+ }
146+ t.Run(name, func(t *testing.T) {
147+ if test.godebug != "" {
148+ t.Setenv("GODEBUG", test.godebug)
149+ }
150+ var buf bytes.Buffer
151+ fw := NewWriter(&buf)
152+ for i := 0; i < test.values; i++ {
153+ w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i))
154+ fmt.Fprintf(w, "value %v", i)
155+ }
156+ for i := 0; i < test.files; i++ {
157+ h := make(textproto.MIMEHeader)
158+ h.Set("Content-Disposition",
159+ fmt.Sprintf(`form-data; name="file%v"; filename="file%v"`, i, i))
160+ h.Set("Content-Type", "application/octet-stream")
161+ for j := 0; j < test.extraKeysPerFile; j++ {
162+ h.Set(fmt.Sprintf("k%v", j), "v")
163+ }
164+ w, _ := fw.CreatePart(h)
165+ fmt.Fprintf(w, "value %v", i)
166+ }
167+ if err := fw.Close(); err != nil {
168+ t.Fatal(err)
169+ }
170+ fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary())
171+ form, err := fr.ReadForm(1 << 10)
172+ if err == nil {
173+ defer form.RemoveAll()
174+ }
175+ if err != test.wantErr {
176+ t.Errorf("ReadForm = %v, want %v", err, test.wantErr)
177+ }
178+ })
179+ }
180+}
181+
182 func BenchmarkReadForm(b *testing.B) {
183 for _, test := range []struct {
184 name string
185diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go
186index 958cef8..94464a8 100644
187--- a/src/mime/multipart/multipart.go
188+++ b/src/mime/multipart/multipart.go
189@@ -16,11 +16,13 @@ import (
190 "bufio"
191 "bytes"
192 "fmt"
193+ "internal/godebug"
194 "io"
195 "io/ioutil"
196 "mime"
197 "mime/quotedprintable"
198 "net/textproto"
199+ "strconv"
200 "strings"
201 )
202
203@@ -121,12 +123,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) {
204 return n, r.err
205 }
206
207-func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
208+func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) {
209 bp := &Part{
210 Header: make(map[string][]string),
211 mr: mr,
212 }
213- if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil {
214+ if err := bp.populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders); err != nil {
215 return nil, err
216 }
217 bp.r = partReader{bp}
218@@ -142,9 +144,9 @@ func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
219 return bp, nil
220 }
221
222-func (bp *Part) populateHeaders(maxMIMEHeaderSize int64) error {
223+func (bp *Part) populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders int64) error {
224 r := textproto.NewReader(bp.mr.bufReader)
225- header, err := readMIMEHeader(r, maxMIMEHeaderSize)
226+ header, err := readMIMEHeader(r, maxMIMEHeaderSize, maxMIMEHeaders)
227 if err == nil {
228 bp.Header = header
229 }
230@@ -306,6 +308,19 @@ type Reader struct {
231 // including header keys, values, and map overhead.
232 const maxMIMEHeaderSize = 10 << 20
233
234+func maxMIMEHeaders() int64 {
235+ // multipartMaxHeaders is the maximum number of header entries NextPart will return,
236+ // as well as the maximum combined total of header entries Reader.ReadForm will return
237+ // in FileHeaders.
238+ multipartMaxHeaders := godebug.Get("multipartmaxheaders")
239+ if multipartMaxHeaders != "" {
240+ if v, err := strconv.ParseInt(multipartMaxHeaders, 10, 64); err == nil && v >= 0 {
241+ return v
242+ }
243+ }
244+ return 10000
245+}
246+
247 // NextPart returns the next part in the multipart or an error.
248 // When there are no more parts, the error io.EOF is returned.
249 //
250@@ -313,7 +328,7 @@ const maxMIMEHeaderSize = 10 << 20
251 // has a value of "quoted-printable", that header is instead
252 // hidden and the body is transparently decoded during Read calls.
253 func (r *Reader) NextPart() (*Part, error) {
254- return r.nextPart(false, maxMIMEHeaderSize)
255+ return r.nextPart(false, maxMIMEHeaderSize, maxMIMEHeaders())
256 }
257
258 // NextRawPart returns the next part in the multipart or an error.
259@@ -322,10 +337,10 @@ func (r *Reader) NextPart() (*Part, error) {
260 // Unlike NextPart, it does not have special handling for
261 // "Content-Transfer-Encoding: quoted-printable".
262 func (r *Reader) NextRawPart() (*Part, error) {
263- return r.nextPart(true, maxMIMEHeaderSize)
264+ return r.nextPart(true, maxMIMEHeaderSize, maxMIMEHeaders())
265 }
266
267-func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
268+func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) {
269 if r.currentPart != nil {
270 r.currentPart.Close()
271 }
272@@ -350,7 +365,7 @@ func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error)
273
274 if r.isBoundaryDelimiterLine(line) {
275 r.partsRead++
276- bp, err := newPart(r, rawPart, maxMIMEHeaderSize)
277+ bp, err := newPart(r, rawPart, maxMIMEHeaderSize, maxMIMEHeaders)
278 if err != nil {
279 return nil, err
280 }
281diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go
282index 6836928..25aa6e2 100644
283--- a/src/mime/multipart/readmimeheader.go
284+++ b/src/mime/multipart/readmimeheader.go
285@@ -11,4 +11,4 @@ import (
286 // readMIMEHeader is defined in package net/textproto.
287 //
288 //go:linkname readMIMEHeader net/textproto.readMIMEHeader
289-func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error)
290+func readMIMEHeader(r *textproto.Reader, maxMemory, maxHeaders int64) (textproto.MIMEHeader, error)
291diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
292index 1c79f0a..ad2d777 100644
293--- a/src/net/textproto/reader.go
294+++ b/src/net/textproto/reader.go
295@@ -484,12 +484,12 @@ func (r *Reader) ReadDotLines() ([]string, error) {
296 // }
297 //
298 func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
299- return readMIMEHeader(r, math.MaxInt64)
300+ return readMIMEHeader(r, math.MaxInt64, math.MaxInt64)
301 }
302
303 // readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size.
304 // It is called by the mime/multipart package.
305-func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
306+func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) {
307 // Avoid lots of small slice allocations later by allocating one
308 // large one ahead of time which we'll cut up into smaller
309 // slices. If this isn't big enough later, we allocate small ones.
310@@ -507,7 +507,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
311 // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry.
312 // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large
313 // MIMEHeaders average about 200 bytes per entry.
314- lim -= 400
315+ maxMemory -= 400
316 const mapEntryOverhead = 200
317
318 // The first line cannot start with a leading space.
319@@ -539,6 +539,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
320 continue
321 }
322
323+ maxHeaders--
324+ if maxHeaders < 0 {
325+ return nil, errors.New("message too large")
326+ }
327+
328 // backport 5c55ac9bf1e5f779220294c843526536605f42ab
329 //
330 // value is computed as
331@@ -557,11 +562,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
332
333 vv := m[key]
334 if vv == nil {
335- lim -= int64(len(key))
336- lim -= mapEntryOverhead
337+ maxMemory -= int64(len(key))
338+ maxMemory -= mapEntryOverhead
339 }
340- lim -= int64(len(value))
341- if lim < 0 {
342+ maxMemory -= int64(len(value))
343+ if maxMemory < 0 {
344 // TODO: This should be a distinguishable error (ErrMessageTooLarge)
345 // to allow mime/multipart to detect it.
346 return m, errors.New("message too large")
347--
3482.25.1
349