summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
authorVivek Kumbhar <vkumbhar@mvista.com>2023-04-29 08:34:36 +0530
committerSteve Sakoman <steve@sakoman.com>2023-05-10 04:19:56 -1000
commitf6b797d05d24368922555a6d5394032a2fd0cfda (patch)
treea9f78b31ccbc780df83e2b957822eb8a18380830 /meta
parentf90eb43a15929b7fe42eaff160bf674b7d117e76 (diff)
downloadpoky-f6b797d05d24368922555a6d5394032a2fd0cfda.tar.gz
go: fix CVE-2023-24534 denial of service from excessive memory allocation
A parsed MIME header is a map[string][]string. In the common case, a header contains many one-element []string slices. To avoid allocating a separate slice for each key, ReadMIMEHeader looks ahead in the input to predict the number of keys that will be parsed, and allocates a single []string of that length. The individual slices are then allocated out of the larger one. The prediction of the number of header keys was done by counting newlines in the input buffer, which does not take into account header continuation lines (where a header key/value spans multiple lines) or the end of the header block and the start of the body. This could lead to a substantial amount of overallocation, for example when the body consists of nothing but a large block of newlines. Fix header key count prediction to take into account the end of the headers (indicated by a blank line) and continuation lines (starting with whitespace). Thanks to Jakob Ackermann (@das7pad) for reporting this issue. Fixes CVE-2023-24534 For #58975 Fixes #59267 (From OE-Core rev: 28bfa033ce965d7316a8b4296d10f3ad74d711db) Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
Diffstat (limited to 'meta')
-rw-r--r--meta/recipes-devtools/go/go-1.17.13.inc1
-rw-r--r--meta/recipes-devtools/go/go-1.18/CVE-2023-24534.patch200
2 files changed, 201 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.17.13.inc b/meta/recipes-devtools/go/go-1.17.13.inc
index cda9227042..c5260569e2 100644
--- a/meta/recipes-devtools/go/go-1.17.13.inc
+++ b/meta/recipes-devtools/go/go-1.17.13.inc
@@ -28,6 +28,7 @@ SRC_URI += "\
28 file://cve-2022-41725.patch \ 28 file://cve-2022-41725.patch \
29 file://CVE-2022-41722.patch \ 29 file://CVE-2022-41722.patch \
30 file://CVE-2023-24537.patch \ 30 file://CVE-2023-24537.patch \
31 file://CVE-2023-24534.patch \
31" 32"
32SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" 33SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd"
33 34
diff --git a/meta/recipes-devtools/go/go-1.18/CVE-2023-24534.patch b/meta/recipes-devtools/go/go-1.18/CVE-2023-24534.patch
new file mode 100644
index 0000000000..c65c7852d5
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.18/CVE-2023-24534.patch
@@ -0,0 +1,200 @@
1From d6759e7a059f4208f07aa781402841d7ddaaef96 Mon Sep 17 00:00:00 2001
2From: Damien Neil <dneil@google.com>
3Date: Fri, 10 Mar 2023 14:21:05 -0800
4Subject: [PATCH] [release-branch.go1.19] net/textproto: avoid overpredicting
5 the number of MIME header keys
6
7Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802452
8Run-TryBot: Damien Neil <dneil@google.com>
9Reviewed-by: Roland Shoemaker <bracewell@google.com>
10Reviewed-by: Julie Qiu <julieqiu@google.com>
11(cherry picked from commit f739f080a72fd5b06d35c8e244165159645e2ed6)
12Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802393
13Reviewed-by: Damien Neil <dneil@google.com>
14Run-TryBot: Roland Shoemaker <bracewell@google.com>
15Change-Id: I675451438d619a9130360c56daf529559004903f
16Reviewed-on: https://go-review.googlesource.com/c/go/+/481982
17Run-TryBot: Michael Knyszek <mknyszek@google.com>
18TryBot-Result: Gopher Robot <gobot@golang.org>
19Reviewed-by: Matthew Dempsky <mdempsky@google.com>
20Auto-Submit: Michael Knyszek <mknyszek@google.com>
21
22Upstream-Status: Backport [https://github.com/golang/go/commit/d6759e7a059f4208f07aa781402841d7ddaaef96]
23CVE: CVE-2023-24534
24Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com>
25
26---
27 src/bytes/bytes.go | 14 ++++++++
28 src/net/textproto/reader.go | 30 ++++++++++------
29 src/net/textproto/reader_test.go | 59 ++++++++++++++++++++++++++++++++
30 3 files changed, 92 insertions(+), 11 deletions(-)
31
32diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
33index ce52649..95ff31c 100644
34--- a/src/bytes/bytes.go
35+++ b/src/bytes/bytes.go
36@@ -1174,3 +1174,17 @@ func Index(s, sep []byte) int {
37 }
38 return -1
39 }
40+
41+// Cut slices s around the first instance of sep,
42+// returning the text before and after sep.
43+// The found result reports whether sep appears in s.
44+// If sep does not appear in s, cut returns s, nil, false.
45+//
46+// Cut returns slices of the original slice s, not copies.
47+func Cut(s, sep []byte) (before, after []byte, found bool) {
48+ if i := Index(s, sep); i >= 0 {
49+ return s[:i], s[i+len(sep):], true
50+ }
51+ return s, nil, false
52+}
53+
54diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
55index 6a680f4..fcbede8 100644
56--- a/src/net/textproto/reader.go
57+++ b/src/net/textproto/reader.go
58@@ -493,8 +493,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
59 // large one ahead of time which we'll cut up into smaller
60 // slices. If this isn't big enough later, we allocate small ones.
61 var strs []string
62- hint := r.upcomingHeaderNewlines()
63+ hint := r.upcomingHeaderKeys()
64 if hint > 0 {
65+ if hint > 1000 {
66+ hint = 1000 // set a cap to avoid overallocation
67+ }
68 strs = make([]string, hint)
69 }
70
71@@ -589,9 +592,11 @@ func mustHaveFieldNameColon(line []byte) error {
72 return nil
73 }
74
75-// upcomingHeaderNewlines returns an approximation of the number of newlines
76+var nl = []byte("\n")
77+
78+// upcomingHeaderKeys returns an approximation of the number of keys
79 // that will be in this header. If it gets confused, it returns 0.
80-func (r *Reader) upcomingHeaderNewlines() (n int) {
81+func (r *Reader) upcomingHeaderKeys() (n int) {
82 // Try to determine the 'hint' size.
83 r.R.Peek(1) // force a buffer load if empty
84 s := r.R.Buffered()
85@@ -599,17 +604,20 @@ func (r *Reader) upcomingHeaderNewlines() (n int) {
86 return
87 }
88 peek, _ := r.R.Peek(s)
89- for len(peek) > 0 {
90- i := bytes.IndexByte(peek, '\n')
91- if i < 3 {
92- // Not present (-1) or found within the next few bytes,
93- // implying we're at the end ("\r\n\r\n" or "\n\n")
94- return
95+ for len(peek) > 0 && n < 1000 {
96+ var line []byte
97+ line, peek, _ = bytes.Cut(peek, nl)
98+ if len(line) == 0 || (len(line) == 1 && line[0] == '\r') {
99+ // Blank line separating headers from the body.
100+ break
101+ }
102+ if line[0] == ' ' || line[0] == '\t' {
103+ // Folded continuation of the previous line.
104+ continue
105 }
106 n++
107- peek = peek[i+1:]
108 }
109- return
110+ return n
111 }
112
113 // CanonicalMIMEHeaderKey returns the canonical format of the
114diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
115index 3124d43..3ae0de1 100644
116--- a/src/net/textproto/reader_test.go
117+++ b/src/net/textproto/reader_test.go
118@@ -9,6 +9,7 @@ import (
119 "bytes"
120 "io"
121 "reflect"
122+ "runtime"
123 "strings"
124 "testing"
125 )
126@@ -127,6 +128,42 @@ func TestReadMIMEHeaderSingle(t *testing.T) {
127 }
128 }
129
130+// TestReaderUpcomingHeaderKeys is testing an internal function, but it's very
131+// difficult to test well via the external API.
132+func TestReaderUpcomingHeaderKeys(t *testing.T) {
133+ for _, test := range []struct {
134+ input string
135+ want int
136+ }{{
137+ input: "",
138+ want: 0,
139+ }, {
140+ input: "A: v",
141+ want: 1,
142+ }, {
143+ input: "A: v\r\nB: v\r\n",
144+ want: 2,
145+ }, {
146+ input: "A: v\nB: v\n",
147+ want: 2,
148+ }, {
149+ input: "A: v\r\n continued\r\n still continued\r\nB: v\r\n\r\n",
150+ want: 2,
151+ }, {
152+ input: "A: v\r\n\r\nB: v\r\nC: v\r\n",
153+ want: 1,
154+ }, {
155+ input: "A: v" + strings.Repeat("\n", 1000),
156+ want: 1,
157+ }} {
158+ r := reader(test.input)
159+ got := r.upcomingHeaderKeys()
160+ if test.want != got {
161+ t.Fatalf("upcomingHeaderKeys(%q): %v; want %v", test.input, got, test.want)
162+ }
163+ }
164+}
165+
166 func TestReadMIMEHeaderNoKey(t *testing.T) {
167 r := reader(": bar\ntest-1: 1\n\n")
168 m, err := r.ReadMIMEHeader()
169@@ -223,6 +260,28 @@ func TestReadMIMEHeaderTrimContinued(t *testing.T) {
170 }
171 }
172
173+// Test that reading a header doesn't overallocate. Issue 58975.
174+func TestReadMIMEHeaderAllocations(t *testing.T) {
175+ var totalAlloc uint64
176+ const count = 200
177+ for i := 0; i < count; i++ {
178+ r := reader("A: b\r\n\r\n" + strings.Repeat("\n", 4096))
179+ var m1, m2 runtime.MemStats
180+ runtime.ReadMemStats(&m1)
181+ _, err := r.ReadMIMEHeader()
182+ if err != nil {
183+ t.Fatalf("ReadMIMEHeader: %v", err)
184+ }
185+ runtime.ReadMemStats(&m2)
186+ totalAlloc += m2.TotalAlloc - m1.TotalAlloc
187+ }
188+ // 32k is large and we actually allocate substantially less,
189+ // but prior to the fix for #58975 we allocated ~400k in this case.
190+ if got, want := totalAlloc/count, uint64(32768); got > want {
191+ t.Fatalf("ReadMIMEHeader allocated %v bytes, want < %v", got, want)
192+ }
193+}
194+
195 type readResponseTest struct {
196 in string
197 inCode int
198--
1992.25.1
200