diff options
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2023-24536_2.patch')
-rw-r--r-- | meta/recipes-devtools/go/go-1.14/CVE-2023-24536_2.patch | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_2.patch new file mode 100644 index 0000000000..9ba5114c82 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_2.patch | |||
@@ -0,0 +1,184 @@ | |||
1 | From 7a359a651c7ebdb29e0a1c03102fce793e9f58f0 Mon Sep 17 00:00:00 2001 | ||
2 | From: Damien Neil <dneil@google.com> | ||
3 | Date: Thu, 16 Mar 2023 16:56:12 -0700 | ||
4 | Subject: [PATCH] [release-branch.go1.19] net/textproto, mime/multipart: | ||
5 | improve accounting of non-file data | ||
6 | |||
7 | For requests containing large numbers of small parts, | ||
8 | memory consumption of a parsed form could be about 250% | ||
9 | over the estimated size. | ||
10 | |||
11 | When considering the size of parsed forms, account for the size of | ||
12 | FileHeader structs and increase the estimate of memory consumed by | ||
13 | map entries. | ||
14 | |||
15 | Thanks to Jakob Ackermann (@das7pad) for reporting this issue. | ||
16 | |||
17 | For CVE-2023-24536 | ||
18 | For #59153 | ||
19 | For #59269 | ||
20 | |||
21 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802454 | ||
22 | Run-TryBot: Damien Neil <dneil@google.com> | ||
23 | Reviewed-by: Roland Shoemaker <bracewell@google.com> | ||
24 | Reviewed-by: Julie Qiu <julieqiu@google.com> | ||
25 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802396 | ||
26 | Run-TryBot: Roland Shoemaker <bracewell@google.com> | ||
27 | Reviewed-by: Damien Neil <dneil@google.com> | ||
28 | Change-Id: I31bc50e9346b4eee6fbe51a18c3c57230cc066db | ||
29 | Reviewed-on: https://go-review.googlesource.com/c/go/+/481984 | ||
30 | Reviewed-by: Matthew Dempsky <mdempsky@google.com> | ||
31 | Auto-Submit: Michael Knyszek <mknyszek@google.com> | ||
32 | TryBot-Result: Gopher Robot <gobot@golang.org> | ||
33 | Run-TryBot: Michael Knyszek <mknyszek@google.com> | ||
34 | |||
35 | Upstream-Status: Backport [https://github.com/golang/go/commit/7a359a651c7ebdb29e0a1c03102fce793e9f58f0] | ||
36 | CVE: CVE-2023-24536 | ||
37 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
38 | --- | ||
39 | src/mime/multipart/formdata.go | 9 +++-- | ||
40 | src/mime/multipart/formdata_test.go | 55 ++++++++++++----------------- | ||
41 | src/net/textproto/reader.go | 8 ++++- | ||
42 | 3 files changed, 37 insertions(+), 35 deletions(-) | ||
43 | |||
44 | diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go | ||
45 | index 975dcb6b26db4..3f6ff697ca608 100644 | ||
46 | --- a/src/mime/multipart/formdata.go | ||
47 | +++ b/src/mime/multipart/formdata.go | ||
48 | @@ -103,8 +103,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { | ||
49 | // Multiple values for the same key (one map entry, longer slice) are cheaper | ||
50 | // than the same number of values for different keys (many map entries), but | ||
51 | // using a consistent per-value cost for overhead is simpler. | ||
52 | + const mapEntryOverhead = 200 | ||
53 | maxMemoryBytes -= int64(len(name)) | ||
54 | - maxMemoryBytes -= 100 // map overhead | ||
55 | + maxMemoryBytes -= mapEntryOverhead | ||
56 | if maxMemoryBytes < 0 { | ||
57 | // We can't actually take this path, since nextPart would already have | ||
58 | // rejected the MIME headers for being too large. Check anyway. | ||
59 | @@ -128,7 +129,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { | ||
60 | } | ||
61 | |||
62 | // file, store in memory or on disk | ||
63 | + const fileHeaderSize = 100 | ||
64 | maxMemoryBytes -= mimeHeaderSize(p.Header) | ||
65 | + maxMemoryBytes -= mapEntryOverhead | ||
66 | + maxMemoryBytes -= fileHeaderSize | ||
67 | if maxMemoryBytes < 0 { | ||
68 | return nil, ErrMessageTooLarge | ||
69 | } | ||
70 | @@ -183,9 +187,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { | ||
71 | } | ||
72 | |||
73 | func mimeHeaderSize(h textproto.MIMEHeader) (size int64) { | ||
74 | + size = 400 | ||
75 | for k, vs := range h { | ||
76 | size += int64(len(k)) | ||
77 | - size += 100 // map entry overhead | ||
78 | + size += 200 // map entry overhead | ||
79 | for _, v := range vs { | ||
80 | size += int64(len(v)) | ||
81 | } | ||
82 | diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go | ||
83 | index f5b56083b2377..8ed26e0c34081 100644 | ||
84 | --- a/src/mime/multipart/formdata_test.go | ||
85 | +++ b/src/mime/multipart/formdata_test.go | ||
86 | @@ -192,10 +192,10 @@ func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) { | ||
87 | // TestReadForm_NonFileMaxMemory asserts that the ReadForm maxMemory limit is applied | ||
88 | // while processing non-file form data as well as file form data. | ||
89 | func TestReadForm_NonFileMaxMemory(t *testing.T) { | ||
90 | - n := 10<<20 + 25 | ||
91 | if testing.Short() { | ||
92 | - n = 10<<10 + 25 | ||
93 | + t.Skip("skipping in -short mode") | ||
94 | } | ||
95 | + n := 10 << 20 | ||
96 | largeTextValue := strings.Repeat("1", n) | ||
97 | message := `--MyBoundary | ||
98 | Content-Disposition: form-data; name="largetext" | ||
99 | @@ -203,38 +203,29 @@ Content-Disposition: form-data; name="largetext" | ||
100 | ` + largeTextValue + ` | ||
101 | --MyBoundary-- | ||
102 | ` | ||
103 | - | ||
104 | testBody := strings.ReplaceAll(message, "\n", "\r\n") | ||
105 | - testCases := []struct { | ||
106 | - name string | ||
107 | - maxMemory int64 | ||
108 | - err error | ||
109 | - }{ | ||
110 | - {"smaller", 50 + int64(len("largetext")) + 100, nil}, | ||
111 | - {"exact-fit", 25 + int64(len("largetext")) + 100, nil}, | ||
112 | - {"too-large", 0, ErrMessageTooLarge}, | ||
113 | - } | ||
114 | - for _, tc := range testCases { | ||
115 | - t.Run(tc.name, func(t *testing.T) { | ||
116 | - if tc.maxMemory == 0 && testing.Short() { | ||
117 | - t.Skip("skipping in -short mode") | ||
118 | - } | ||
119 | - b := strings.NewReader(testBody) | ||
120 | - r := NewReader(b, boundary) | ||
121 | - f, err := r.ReadForm(tc.maxMemory) | ||
122 | - if err == nil { | ||
123 | - defer f.RemoveAll() | ||
124 | - } | ||
125 | - if tc.err != err { | ||
126 | - t.Fatalf("ReadForm error - got: %v; expected: %v", err, tc.err) | ||
127 | - } | ||
128 | - if err == nil { | ||
129 | - if g := f.Value["largetext"][0]; g != largeTextValue { | ||
130 | - t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) | ||
131 | - } | ||
132 | - } | ||
133 | - }) | ||
134 | + // Try parsing the form with increasing maxMemory values. | ||
135 | + // Changes in how we account for non-file form data may cause the exact point | ||
136 | + // where we change from rejecting the form as too large to accepting it to vary, | ||
137 | + // but we should see both successes and failures. | ||
138 | + const failWhenMaxMemoryLessThan = 128 | ||
139 | + for maxMemory := int64(0); maxMemory < failWhenMaxMemoryLessThan*2; maxMemory += 16 { | ||
140 | + b := strings.NewReader(testBody) | ||
141 | + r := NewReader(b, boundary) | ||
142 | + f, err := r.ReadForm(maxMemory) | ||
143 | + if err != nil { | ||
144 | + continue | ||
145 | + } | ||
146 | + if g := f.Value["largetext"][0]; g != largeTextValue { | ||
147 | + t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) | ||
148 | + } | ||
149 | + f.RemoveAll() | ||
150 | + if maxMemory < failWhenMaxMemoryLessThan { | ||
151 | + t.Errorf("ReadForm(%v): no error, expect to hit memory limit when maxMemory < %v", maxMemory, failWhenMaxMemoryLessThan) | ||
152 | + } | ||
153 | + return | ||
154 | } | ||
155 | + t.Errorf("ReadForm(x) failed for x < 1024, expect success") | ||
156 | } | ||
157 | |||
158 | // TestReadForm_MetadataTooLarge verifies that we account for the size of field names, | ||
159 | diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go | ||
160 | index 9a21777df8be0..c1284fde25eb7 100644 | ||
161 | --- a/src/net/textproto/reader.go | ||
162 | +++ b/src/net/textproto/reader.go | ||
163 | @@ -503,6 +503,12 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { | ||
164 | |||
165 | m := make(MIMEHeader, hint) | ||
166 | |||
167 | + // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. | ||
168 | + // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large | ||
169 | + // MIMEHeaders average about 200 bytes per entry. | ||
170 | + lim -= 400 | ||
171 | + const mapEntryOverhead = 200 | ||
172 | + | ||
173 | // The first line cannot start with a leading space. | ||
174 | if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { | ||
175 | line, err := r.readLineSlice() | ||
176 | @@ -538,7 +544,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { | ||
177 | vv := m[key] | ||
178 | if vv == nil { | ||
179 | lim -= int64(len(key)) | ||
180 | - lim -= 100 // map entry overhead | ||
181 | + lim -= mapEntryOverhead | ||
182 | } | ||
183 | lim -= int64(len(value)) | ||
184 | if lim < 0 { | ||