diff options
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2023-24534.patch')
-rw-r--r-- | meta/recipes-devtools/go/go-1.14/CVE-2023-24534.patch | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24534.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24534.patch new file mode 100644 index 0000000000..d50db04bed --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24534.patch | |||
@@ -0,0 +1,200 @@ | |||
1 | From d6759e7a059f4208f07aa781402841d7ddaaef96 Mon Sep 17 00:00:00 2001 | ||
2 | From: Damien Neil <dneil@google.com> | ||
3 | Date: Fri, 10 Mar 2023 14:21:05 -0800 | ||
4 | Subject: [PATCH] [release-branch.go1.19] net/textproto: avoid overpredicting | ||
5 | the number of MIME header keys | ||
6 | |||
7 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802452 | ||
8 | Run-TryBot: Damien Neil <dneil@google.com> | ||
9 | Reviewed-by: Roland Shoemaker <bracewell@google.com> | ||
10 | Reviewed-by: Julie Qiu <julieqiu@google.com> | ||
11 | (cherry picked from commit f739f080a72fd5b06d35c8e244165159645e2ed6) | ||
12 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802393 | ||
13 | Reviewed-by: Damien Neil <dneil@google.com> | ||
14 | Run-TryBot: Roland Shoemaker <bracewell@google.com> | ||
15 | Change-Id: I675451438d619a9130360c56daf529559004903f | ||
16 | Reviewed-on: https://go-review.googlesource.com/c/go/+/481982 | ||
17 | Run-TryBot: Michael Knyszek <mknyszek@google.com> | ||
18 | TryBot-Result: Gopher Robot <gobot@golang.org> | ||
19 | Reviewed-by: Matthew Dempsky <mdempsky@google.com> | ||
20 | Auto-Submit: Michael Knyszek <mknyszek@google.com> | ||
21 | |||
22 | Upstream-Status: Backport [https://github.com/golang/go/commit/d6759e7a059f4208f07aa781402841d7ddaaef96] | ||
23 | CVE: CVE-2023-24534 | ||
24 | Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> | ||
25 | --- | ||
26 | src/bytes/bytes.go | 13 +++++++ | ||
27 | src/net/textproto/reader.go | 31 +++++++++++------ | ||
28 | src/net/textproto/reader_test.go | 59 ++++++++++++++++++++++++++++++++ | ||
29 | 3 files changed, 92 insertions(+), 11 deletions(-) | ||
30 | |||
31 | diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go | ||
32 | index e872cc2..1f0d760 100644 | ||
33 | --- a/src/bytes/bytes.go | ||
34 | +++ b/src/bytes/bytes.go | ||
35 | @@ -1078,6 +1078,19 @@ func Index(s, sep []byte) int { | ||
36 | return -1 | ||
37 | } | ||
38 | |||
39 | +// Cut slices s around the first instance of sep, | ||
40 | +// returning the text before and after sep. | ||
41 | +// The found result reports whether sep appears in s. | ||
42 | +// If sep does not appear in s, cut returns s, nil, false. | ||
43 | +// | ||
44 | +// Cut returns slices of the original slice s, not copies. | ||
45 | +func Cut(s, sep []byte) (before, after []byte, found bool) { | ||
46 | + if i := Index(s, sep); i >= 0 { | ||
47 | + return s[:i], s[i+len(sep):], true | ||
48 | + } | ||
49 | + return s, nil, false | ||
50 | +} | ||
51 | + | ||
52 | func indexRabinKarp(s, sep []byte) int { | ||
53 | // Rabin-Karp search | ||
54 | hashsep, pow := hashStr(sep) | ||
55 | diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go | ||
56 | index a505da9..8d547fe 100644 | ||
57 | --- a/src/net/textproto/reader.go | ||
58 | +++ b/src/net/textproto/reader.go | ||
59 | @@ -486,8 +487,11 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { | ||
60 | // large one ahead of time which we'll cut up into smaller | ||
61 | // slices. If this isn't big enough later, we allocate small ones. | ||
62 | var strs []string | ||
63 | - hint := r.upcomingHeaderNewlines() | ||
64 | + hint := r.upcomingHeaderKeys() | ||
65 | if hint > 0 { | ||
66 | + if hint > 1000 { | ||
67 | + hint = 1000 // set a cap to avoid overallocation | ||
68 | + } | ||
69 | strs = make([]string, hint) | ||
70 | } | ||
71 | |||
72 | @@ -562,9 +566,11 @@ func mustHaveFieldNameColon(line []byte) error { | ||
73 | return nil | ||
74 | } | ||
75 | |||
76 | -// upcomingHeaderNewlines returns an approximation of the number of newlines | ||
77 | +var nl = []byte("\n") | ||
78 | + | ||
79 | +// upcomingHeaderKeys returns an approximation of the number of keys | ||
80 | // that will be in this header. If it gets confused, it returns 0. | ||
81 | -func (r *Reader) upcomingHeaderNewlines() (n int) { | ||
82 | +func (r *Reader) upcomingHeaderKeys() (n int) { | ||
83 | // Try to determine the 'hint' size. | ||
84 | r.R.Peek(1) // force a buffer load if empty | ||
85 | s := r.R.Buffered() | ||
86 | @@ -572,17 +578,20 @@ func (r *Reader) upcomingHeaderNewlines() (n int) { | ||
87 | return | ||
88 | } | ||
89 | peek, _ := r.R.Peek(s) | ||
90 | - for len(peek) > 0 { | ||
91 | - i := bytes.IndexByte(peek, '\n') | ||
92 | - if i < 3 { | ||
93 | - // Not present (-1) or found within the next few bytes, | ||
94 | - // implying we're at the end ("\r\n\r\n" or "\n\n") | ||
95 | - return | ||
96 | + for len(peek) > 0 && n < 1000 { | ||
97 | + var line []byte | ||
98 | + line, peek, _ = bytes.Cut(peek, nl) | ||
99 | + if len(line) == 0 || (len(line) == 1 && line[0] == '\r') { | ||
100 | + // Blank line separating headers from the body. | ||
101 | + break | ||
102 | + } | ||
103 | + if line[0] == ' ' || line[0] == '\t' { | ||
104 | + // Folded continuation of the previous line. | ||
105 | + continue | ||
106 | } | ||
107 | n++ | ||
108 | - peek = peek[i+1:] | ||
109 | } | ||
110 | - return | ||
111 | + return n | ||
112 | } | ||
113 | |||
114 | // CanonicalMIMEHeaderKey returns the canonical format of the | ||
115 | diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go | ||
116 | index 3124d43..3ae0de1 100644 | ||
117 | --- a/src/net/textproto/reader_test.go | ||
118 | +++ b/src/net/textproto/reader_test.go | ||
119 | @@ -9,6 +9,7 @@ import ( | ||
120 | "bytes" | ||
121 | "io" | ||
122 | "reflect" | ||
123 | + "runtime" | ||
124 | "strings" | ||
125 | "testing" | ||
126 | ) | ||
127 | @@ -127,6 +128,42 @@ func TestReadMIMEHeaderSingle(t *testing.T) { | ||
128 | } | ||
129 | } | ||
130 | |||
131 | +// TestReaderUpcomingHeaderKeys is testing an internal function, but it's very | ||
132 | +// difficult to test well via the external API. | ||
133 | +func TestReaderUpcomingHeaderKeys(t *testing.T) { | ||
134 | + for _, test := range []struct { | ||
135 | + input string | ||
136 | + want int | ||
137 | + }{{ | ||
138 | + input: "", | ||
139 | + want: 0, | ||
140 | + }, { | ||
141 | + input: "A: v", | ||
142 | + want: 1, | ||
143 | + }, { | ||
144 | + input: "A: v\r\nB: v\r\n", | ||
145 | + want: 2, | ||
146 | + }, { | ||
147 | + input: "A: v\nB: v\n", | ||
148 | + want: 2, | ||
149 | + }, { | ||
150 | + input: "A: v\r\n continued\r\n still continued\r\nB: v\r\n\r\n", | ||
151 | + want: 2, | ||
152 | + }, { | ||
153 | + input: "A: v\r\n\r\nB: v\r\nC: v\r\n", | ||
154 | + want: 1, | ||
155 | + }, { | ||
156 | + input: "A: v" + strings.Repeat("\n", 1000), | ||
157 | + want: 1, | ||
158 | + }} { | ||
159 | + r := reader(test.input) | ||
160 | + got := r.upcomingHeaderKeys() | ||
161 | + if test.want != got { | ||
162 | + t.Fatalf("upcomingHeaderKeys(%q): %v; want %v", test.input, got, test.want) | ||
163 | + } | ||
164 | + } | ||
165 | +} | ||
166 | + | ||
167 | func TestReadMIMEHeaderNoKey(t *testing.T) { | ||
168 | r := reader(": bar\ntest-1: 1\n\n") | ||
169 | m, err := r.ReadMIMEHeader() | ||
170 | @@ -223,6 +260,28 @@ func TestReadMIMEHeaderTrimContinued(t *testing.T) { | ||
171 | } | ||
172 | } | ||
173 | |||
174 | +// Test that reading a header doesn't overallocate. Issue 58975. | ||
175 | +func TestReadMIMEHeaderAllocations(t *testing.T) { | ||
176 | + var totalAlloc uint64 | ||
177 | + const count = 200 | ||
178 | + for i := 0; i < count; i++ { | ||
179 | + r := reader("A: b\r\n\r\n" + strings.Repeat("\n", 4096)) | ||
180 | + var m1, m2 runtime.MemStats | ||
181 | + runtime.ReadMemStats(&m1) | ||
182 | + _, err := r.ReadMIMEHeader() | ||
183 | + if err != nil { | ||
184 | + t.Fatalf("ReadMIMEHeader: %v", err) | ||
185 | + } | ||
186 | + runtime.ReadMemStats(&m2) | ||
187 | + totalAlloc += m2.TotalAlloc - m1.TotalAlloc | ||
188 | + } | ||
189 | + // 32k is large and we actually allocate substantially less, | ||
190 | + // but prior to the fix for #58975 we allocated ~400k in this case. | ||
191 | + if got, want := totalAlloc/count, uint64(32768); got > want { | ||
192 | + t.Fatalf("ReadMIMEHeader allocated %v bytes, want < %v", got, want) | ||
193 | + } | ||
194 | +} | ||
195 | + | ||
196 | type readResponseTest struct { | ||
197 | in string | ||
198 | inCode int | ||
199 | -- | ||
200 | 2.25.1 | ||