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 @@
+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
+