diff options
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.patch | 349 |
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 @@ +From 7917b5f31204528ea72e0629f0b7d52b35b27538 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Mon, 20 Mar 2023 10:43:19 -0700 +Subject: [PATCH] [release-branch.go1.19] mime/multipart: limit parsed mime message sizes + +The parsed forms of MIME headers and multipart forms can consume +substantially more memory than the size of the input data. +A malicious input containing a very large number of headers or +form parts can cause excessively large memory allocations. + +Set limits on the size of MIME data: + +Reader.NextPart and Reader.NextRawPart limit the the number +of headers in a part to 10000. + +Reader.ReadForm limits the total number of headers in all +FileHeaders to 10000. + +Both of these limits may be set with with +GODEBUG=multipartmaxheaders=<values>. + +Reader.ReadForm limits the number of parts in a form to 1000. +This limit may be set with GODEBUG=multipartmaxparts=<value>. + +Thanks for Jakob Ackermann (@das7pad) for reporting this issue. + +For CVE-2023-24536 +For #59153 +For #59269 + +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802455 +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1801087 +Reviewed-by: Damien Neil <dneil@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Change-Id: If134890d75f0d95c681d67234daf191ba08e6424 +Reviewed-on: https://go-review.googlesource.com/c/go/+/481985 +Run-TryBot: Michael Knyszek <mknyszek@google.com> +Auto-Submit: Michael Knyszek <mknyszek@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Matthew Dempsky <mdempsky@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/7917b5f31204528ea72e0629f0b7d52b35b27538] +CVE: CVE-2023-24536 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/mime/multipart/formdata.go | 19 ++++++++- + src/mime/multipart/formdata_test.go | 61 ++++++++++++++++++++++++++++ + src/mime/multipart/multipart.go | 31 ++++++++++---- + src/mime/multipart/readmimeheader.go | 2 +- + src/net/textproto/reader.go | 19 +++++---- + 5 files changed, 115 insertions(+), 17 deletions(-) + +diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go +index 216cccb..0b508ae 100644 +--- a/src/mime/multipart/formdata.go ++++ b/src/mime/multipart/formdata.go +@@ -13,6 +13,7 @@ import ( + "math" + "net/textproto" + "os" ++ "strconv" + ) + + // ErrMessageTooLarge is returned by ReadForm if the message form +@@ -42,6 +43,15 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + numDiskFiles := 0 + multipartFiles := godebug.Get("multipartfiles") + combineFiles := multipartFiles != "distinct" ++ maxParts := 1000 ++ multipartMaxParts := godebug.Get("multipartmaxparts") ++ if multipartMaxParts != "" { ++ if v, err := strconv.Atoi(multipartMaxParts); err == nil && v >= 0 { ++ maxParts = v ++ } ++ } ++ maxHeaders := maxMIMEHeaders() ++ + defer func() { + if file != nil { + if cerr := file.Close(); err == nil { +@@ -87,13 +97,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + } + var copyBuf []byte + for { +- p, err := r.nextPart(false, maxMemoryBytes) ++ p, err := r.nextPart(false, maxMemoryBytes, maxHeaders) + if err == io.EOF { + break + } + if err != nil { + return nil, err + } ++ if maxParts <= 0 { ++ return nil, ErrMessageTooLarge ++ } ++ maxParts-- + + name := p.FormName() + if name == "" { +@@ -137,6 +151,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + if maxMemoryBytes < 0 { + return nil, ErrMessageTooLarge + } ++ for _, v := range p.Header { ++ maxHeaders -= int64(len(v)) ++ } + fh := &FileHeader{ + Filename: filename, + Header: p.Header, +diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go +index 8ed26e0..c78eeb7 100644 +--- a/src/mime/multipart/formdata_test.go ++++ b/src/mime/multipart/formdata_test.go +@@ -360,6 +360,67 @@ func testReadFormManyFiles(t *testing.T, distinct bool) { + } + } + ++func TestReadFormLimits(t *testing.T) { ++ for _, test := range []struct { ++ values int ++ files int ++ extraKeysPerFile int ++ wantErr error ++ godebug string ++ }{ ++ {values: 1000}, ++ {values: 1001, wantErr: ErrMessageTooLarge}, ++ {values: 500, files: 500}, ++ {values: 501, files: 500, wantErr: ErrMessageTooLarge}, ++ {files: 1000}, ++ {files: 1001, wantErr: ErrMessageTooLarge}, ++ {files: 1, extraKeysPerFile: 9998}, // plus Content-Disposition and Content-Type ++ {files: 1, extraKeysPerFile: 10000, wantErr: ErrMessageTooLarge}, ++ {godebug: "multipartmaxparts=100", values: 100}, ++ {godebug: "multipartmaxparts=100", values: 101, wantErr: ErrMessageTooLarge}, ++ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 48}, ++ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 50, wantErr: ErrMessageTooLarge}, ++ } { ++ name := fmt.Sprintf("values=%v/files=%v/extraKeysPerFile=%v", test.values, test.files, test.extraKeysPerFile) ++ if test.godebug != "" { ++ name += fmt.Sprintf("/godebug=%v", test.godebug) ++ } ++ t.Run(name, func(t *testing.T) { ++ if test.godebug != "" { ++ t.Setenv("GODEBUG", test.godebug) ++ } ++ var buf bytes.Buffer ++ fw := NewWriter(&buf) ++ for i := 0; i < test.values; i++ { ++ w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i)) ++ fmt.Fprintf(w, "value %v", i) ++ } ++ for i := 0; i < test.files; i++ { ++ h := make(textproto.MIMEHeader) ++ h.Set("Content-Disposition", ++ fmt.Sprintf(`form-data; name="file%v"; filename="file%v"`, i, i)) ++ h.Set("Content-Type", "application/octet-stream") ++ for j := 0; j < test.extraKeysPerFile; j++ { ++ h.Set(fmt.Sprintf("k%v", j), "v") ++ } ++ w, _ := fw.CreatePart(h) ++ fmt.Fprintf(w, "value %v", i) ++ } ++ if err := fw.Close(); err != nil { ++ t.Fatal(err) ++ } ++ fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary()) ++ form, err := fr.ReadForm(1 << 10) ++ if err == nil { ++ defer form.RemoveAll() ++ } ++ if err != test.wantErr { ++ t.Errorf("ReadForm = %v, want %v", err, test.wantErr) ++ } ++ }) ++ } ++} ++ + func BenchmarkReadForm(b *testing.B) { + for _, test := range []struct { + name string +diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go +index 958cef8..94464a8 100644 +--- a/src/mime/multipart/multipart.go ++++ b/src/mime/multipart/multipart.go +@@ -16,11 +16,13 @@ import ( + "bufio" + "bytes" + "fmt" ++ "internal/godebug" + "io" + "io/ioutil" + "mime" + "mime/quotedprintable" + "net/textproto" ++ "strconv" + "strings" + ) + +@@ -121,12 +123,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) { + return n, r.err + } + +-func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { ++func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) { + bp := &Part{ + Header: make(map[string][]string), + mr: mr, + } +- if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil { ++ if err := bp.populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders); err != nil { + return nil, err + } + bp.r = partReader{bp} +@@ -142,9 +144,9 @@ func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { + return bp, nil + } + +-func (bp *Part) populateHeaders(maxMIMEHeaderSize int64) error { ++func (bp *Part) populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders int64) error { + r := textproto.NewReader(bp.mr.bufReader) +- header, err := readMIMEHeader(r, maxMIMEHeaderSize) ++ header, err := readMIMEHeader(r, maxMIMEHeaderSize, maxMIMEHeaders) + if err == nil { + bp.Header = header + } +@@ -306,6 +308,19 @@ type Reader struct { + // including header keys, values, and map overhead. + const maxMIMEHeaderSize = 10 << 20 + ++func maxMIMEHeaders() int64 { ++ // multipartMaxHeaders is the maximum number of header entries NextPart will return, ++ // as well as the maximum combined total of header entries Reader.ReadForm will return ++ // in FileHeaders. ++ multipartMaxHeaders := godebug.Get("multipartmaxheaders") ++ if multipartMaxHeaders != "" { ++ if v, err := strconv.ParseInt(multipartMaxHeaders, 10, 64); err == nil && v >= 0 { ++ return v ++ } ++ } ++ return 10000 ++} ++ + // NextPart returns the next part in the multipart or an error. + // When there are no more parts, the error io.EOF is returned. + // +@@ -313,7 +328,7 @@ const maxMIMEHeaderSize = 10 << 20 + // has a value of "quoted-printable", that header is instead + // hidden and the body is transparently decoded during Read calls. + func (r *Reader) NextPart() (*Part, error) { +- return r.nextPart(false, maxMIMEHeaderSize) ++ return r.nextPart(false, maxMIMEHeaderSize, maxMIMEHeaders()) + } + + // NextRawPart returns the next part in the multipart or an error. +@@ -322,10 +337,10 @@ func (r *Reader) NextPart() (*Part, error) { + // Unlike NextPart, it does not have special handling for + // "Content-Transfer-Encoding: quoted-printable". + func (r *Reader) NextRawPart() (*Part, error) { +- return r.nextPart(true, maxMIMEHeaderSize) ++ return r.nextPart(true, maxMIMEHeaderSize, maxMIMEHeaders()) + } + +-func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { ++func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) { + if r.currentPart != nil { + r.currentPart.Close() + } +@@ -350,7 +365,7 @@ func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) + + if r.isBoundaryDelimiterLine(line) { + r.partsRead++ +- bp, err := newPart(r, rawPart, maxMIMEHeaderSize) ++ bp, err := newPart(r, rawPart, maxMIMEHeaderSize, maxMIMEHeaders) + if err != nil { + return nil, err + } +diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go +index 6836928..25aa6e2 100644 +--- a/src/mime/multipart/readmimeheader.go ++++ b/src/mime/multipart/readmimeheader.go +@@ -11,4 +11,4 @@ import ( + // readMIMEHeader is defined in package net/textproto. + // + //go:linkname readMIMEHeader net/textproto.readMIMEHeader +-func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error) ++func readMIMEHeader(r *textproto.Reader, maxMemory, maxHeaders int64) (textproto.MIMEHeader, error) +diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go +index 1c79f0a..ad2d777 100644 +--- a/src/net/textproto/reader.go ++++ b/src/net/textproto/reader.go +@@ -484,12 +484,12 @@ func (r *Reader) ReadDotLines() ([]string, error) { + // } + // + func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { +- return readMIMEHeader(r, math.MaxInt64) ++ return readMIMEHeader(r, math.MaxInt64, math.MaxInt64) + } + + // readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. + // It is called by the mime/multipart package. +-func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { ++func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) { + // Avoid lots of small slice allocations later by allocating one + // large one ahead of time which we'll cut up into smaller + // slices. If this isn't big enough later, we allocate small ones. +@@ -507,7 +507,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. + // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large + // MIMEHeaders average about 200 bytes per entry. +- lim -= 400 ++ maxMemory -= 400 + const mapEntryOverhead = 200 + + // The first line cannot start with a leading space. +@@ -539,6 +539,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + continue + } + ++ maxHeaders-- ++ if maxHeaders < 0 { ++ return nil, errors.New("message too large") ++ } ++ + // backport 5c55ac9bf1e5f779220294c843526536605f42ab + // + // value is computed as +@@ -557,11 +562,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + + vv := m[key] + if vv == nil { +- lim -= int64(len(key)) +- lim -= mapEntryOverhead ++ maxMemory -= int64(len(key)) ++ maxMemory -= mapEntryOverhead + } +- lim -= int64(len(value)) +- if lim < 0 { ++ maxMemory -= int64(len(value)) ++ if maxMemory < 0 { + // TODO: This should be a distinguishable error (ErrMessageTooLarge) + // to allow mime/multipart to detect it. + return m, errors.New("message too large") +-- +2.25.1 + |