summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch')
-rw-r--r--meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch271
1 files changed, 271 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch
new file mode 100644
index 0000000000..fac0ebe94c
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch
@@ -0,0 +1,271 @@
1From e9017c2416ad0ef642f5e0c2eab2dbf3cba4d997 Mon Sep 17 00:00:00 2001
2From: Russ Cox <rsc@golang.org>
3Date: Wed, 28 Sep 2022 11:18:51 -0400
4Subject: [PATCH] [release-branch.go1.18] regexp: limit size of parsed regexps
5
6Set a 128 MB limit on the amount of space used by []syntax.Inst
7in the compiled form corresponding to a given regexp.
8
9Also set a 128 MB limit on the rune storage in the *syntax.Regexp
10tree itself.
11
12Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting this issue.
13
14Fixes CVE-2022-41715.
15Updates #55949.
16Fixes #55950.
17
18Change-Id: Ia656baed81564436368cf950e1c5409752f28e1b
19Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1592136
20TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
21Reviewed-by: Damien Neil <dneil@google.com>
22Run-TryBot: Roland Shoemaker <bracewell@google.com>
23Reviewed-by: Julie Qiu <julieqiu@google.com>
24Reviewed-on: https://go-review.googlesource.com/c/go/+/438501
25Run-TryBot: Carlos Amedee <carlos@golang.org>
26Reviewed-by: Carlos Amedee <carlos@golang.org>
27Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
28TryBot-Result: Gopher Robot <gobot@golang.org>
29Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
30
31Upstream-Status: Backport [https://github.com/golang/go/commit/e9017c2416ad0ef642f5e0c2eab2dbf3cba4d997]
32CVE: CVE-2022-41715
33Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
34
35---
36 src/regexp/syntax/parse.go | 145 ++++++++++++++++++++++++++++++--
37 src/regexp/syntax/parse_test.go | 13 +--
38 2 files changed, 148 insertions(+), 10 deletions(-)
39
40diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go
41index 55bd20d..60491d5 100644
42--- a/src/regexp/syntax/parse.go
43+++ b/src/regexp/syntax/parse.go
44@@ -90,15 +90,49 @@ const (
45 // until we've allocated at least maxHeight Regexp structures.
46 const maxHeight = 1000
47
48+// maxSize is the maximum size of a compiled regexp in Insts.
49+// It too is somewhat arbitrarily chosen, but the idea is to be large enough
50+// to allow significant regexps while at the same time small enough that
51+// the compiled form will not take up too much memory.
52+// 128 MB is enough for a 3.3 million Inst structures, which roughly
53+// corresponds to a 3.3 MB regexp.
54+const (
55+ maxSize = 128 << 20 / instSize
56+ instSize = 5 * 8 // byte, 2 uint32, slice is 5 64-bit words
57+)
58+
59+// maxRunes is the maximum number of runes allowed in a regexp tree
60+// counting the runes in all the nodes.
61+// Ignoring character classes p.numRunes is always less than the length of the regexp.
62+// Character classes can make it much larger: each \pL adds 1292 runes.
63+// 128 MB is enough for 32M runes, which is over 26k \pL instances.
64+// Note that repetitions do not make copies of the rune slices,
65+// so \pL{1000} is only one rune slice, not 1000.
66+// We could keep a cache of character classes we've seen,
67+// so that all the \pL we see use the same rune list,
68+// but that doesn't remove the problem entirely:
69+// consider something like [\pL01234][\pL01235][\pL01236]...[\pL^&*()].
70+// And because the Rune slice is exposed directly in the Regexp,
71+// there is not an opportunity to change the representation to allow
72+// partial sharing between different character classes.
73+// So the limit is the best we can do.
74+const (
75+ maxRunes = 128 << 20 / runeSize
76+ runeSize = 4 // rune is int32
77+)
78+
79 type parser struct {
80 flags Flags // parse mode flags
81 stack []*Regexp // stack of parsed expressions
82 free *Regexp
83 numCap int // number of capturing groups seen
84 wholeRegexp string
85- tmpClass []rune // temporary char class work space
86- numRegexp int // number of regexps allocated
87- height map[*Regexp]int // regexp height for height limit check
88+ tmpClass []rune // temporary char class work space
89+ numRegexp int // number of regexps allocated
90+ numRunes int // number of runes in char classes
91+ repeats int64 // product of all repetitions seen
92+ height map[*Regexp]int // regexp height, for height limit check
93+ size map[*Regexp]int64 // regexp compiled size, for size limit check
94 }
95
96 func (p *parser) newRegexp(op Op) *Regexp {
97@@ -122,6 +156,104 @@ func (p *parser) reuse(re *Regexp) {
98 p.free = re
99 }
100
101+func (p *parser) checkLimits(re *Regexp) {
102+ if p.numRunes > maxRunes {
103+ panic(ErrInternalError)
104+ }
105+ p.checkSize(re)
106+ p.checkHeight(re)
107+}
108+
109+func (p *parser) checkSize(re *Regexp) {
110+ if p.size == nil {
111+ // We haven't started tracking size yet.
112+ // Do a relatively cheap check to see if we need to start.
113+ // Maintain the product of all the repeats we've seen
114+ // and don't track if the total number of regexp nodes
115+ // we've seen times the repeat product is in budget.
116+ if p.repeats == 0 {
117+ p.repeats = 1
118+ }
119+ if re.Op == OpRepeat {
120+ n := re.Max
121+ if n == -1 {
122+ n = re.Min
123+ }
124+ if n <= 0 {
125+ n = 1
126+ }
127+ if int64(n) > maxSize/p.repeats {
128+ p.repeats = maxSize
129+ } else {
130+ p.repeats *= int64(n)
131+ }
132+ }
133+ if int64(p.numRegexp) < maxSize/p.repeats {
134+ return
135+ }
136+
137+ // We need to start tracking size.
138+ // Make the map and belatedly populate it
139+ // with info about everything we've constructed so far.
140+ p.size = make(map[*Regexp]int64)
141+ for _, re := range p.stack {
142+ p.checkSize(re)
143+ }
144+ }
145+
146+ if p.calcSize(re, true) > maxSize {
147+ panic(ErrInternalError)
148+ }
149+}
150+
151+func (p *parser) calcSize(re *Regexp, force bool) int64 {
152+ if !force {
153+ if size, ok := p.size[re]; ok {
154+ return size
155+ }
156+ }
157+
158+ var size int64
159+ switch re.Op {
160+ case OpLiteral:
161+ size = int64(len(re.Rune))
162+ case OpCapture, OpStar:
163+ // star can be 1+ or 2+; assume 2 pessimistically
164+ size = 2 + p.calcSize(re.Sub[0], false)
165+ case OpPlus, OpQuest:
166+ size = 1 + p.calcSize(re.Sub[0], false)
167+ case OpConcat:
168+ for _, sub := range re.Sub {
169+ size += p.calcSize(sub, false)
170+ }
171+ case OpAlternate:
172+ for _, sub := range re.Sub {
173+ size += p.calcSize(sub, false)
174+ }
175+ if len(re.Sub) > 1 {
176+ size += int64(len(re.Sub)) - 1
177+ }
178+ case OpRepeat:
179+ sub := p.calcSize(re.Sub[0], false)
180+ if re.Max == -1 {
181+ if re.Min == 0 {
182+ size = 2 + sub // x*
183+ } else {
184+ size = 1 + int64(re.Min)*sub // xxx+
185+ }
186+ break
187+ }
188+ // x{2,5} = xx(x(x(x)?)?)?
189+ size = int64(re.Max)*sub + int64(re.Max-re.Min)
190+ }
191+
192+ if size < 1 {
193+ size = 1
194+ }
195+ p.size[re] = size
196+ return size
197+}
198+
199 func (p *parser) checkHeight(re *Regexp) {
200 if p.numRegexp < maxHeight {
201 return
202@@ -158,6 +290,7 @@ func (p *parser) calcHeight(re *Regexp, force bool) int {
203
204 // push pushes the regexp re onto the parse stack and returns the regexp.
205 func (p *parser) push(re *Regexp) *Regexp {
206+ p.numRunes += len(re.Rune)
207 if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] {
208 // Single rune.
209 if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) {
210@@ -189,7 +322,7 @@ func (p *parser) push(re *Regexp) *Regexp {
211 }
212
213 p.stack = append(p.stack, re)
214- p.checkHeight(re)
215+ p.checkLimits(re)
216 return re
217 }
218
219@@ -305,7 +438,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (
220 re.Sub = re.Sub0[:1]
221 re.Sub[0] = sub
222 p.stack[n-1] = re
223- p.checkHeight(re)
224+ p.checkLimits(re)
225
226 if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) {
227 return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]}
228@@ -509,6 +642,7 @@ func (p *parser) factor(sub []*Regexp) []*Regexp {
229
230 for j := start; j < i; j++ {
231 sub[j] = p.removeLeadingString(sub[j], len(str))
232+ p.checkLimits(sub[j])
233 }
234 suffix := p.collapse(sub[start:i], OpAlternate) // recurse
235
236@@ -566,6 +700,7 @@ func (p *parser) factor(sub []*Regexp) []*Regexp {
237 for j := start; j < i; j++ {
238 reuse := j != start // prefix came from sub[start]
239 sub[j] = p.removeLeadingRegexp(sub[j], reuse)
240+ p.checkLimits(sub[j])
241 }
242 suffix := p.collapse(sub[start:i], OpAlternate) // recurse
243
244diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go
245index 1ef6d8a..67e3c56 100644
246--- a/src/regexp/syntax/parse_test.go
247+++ b/src/regexp/syntax/parse_test.go
248@@ -484,12 +484,15 @@ var invalidRegexps = []string{
249 `(?P<>a)`,
250 `[a-Z]`,
251 `(?i)[a-Z]`,
252- `a{100000}`,
253- `a{100000,}`,
254- "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})",
255- strings.Repeat("(", 1000) + strings.Repeat(")", 1000),
256- strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000),
257 `\Q\E*`,
258+ `a{100000}`, // too much repetition
259+ `a{100000,}`, // too much repetition
260+ "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", // too much repetition
261+ strings.Repeat("(", 1000) + strings.Repeat(")", 1000), // too deep
262+ strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000), // too deep
263+ "(" + strings.Repeat("(xx?)", 1000) + "){1000}", // too long
264+ strings.Repeat("(xx?){1000}", 1000), // too long
265+ strings.Repeat(`\pL`, 27000), // too many runes
266 }
267
268 var onlyPerl = []string{
269--
2702.25.1
271