summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch')
-rw-r--r--meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch357
1 files changed, 357 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch
new file mode 100644
index 0000000000..b2ab5d0669
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch
@@ -0,0 +1,357 @@
1From ba8788ebcead55e99e631c6a1157ad7b35535d11 Mon Sep 17 00:00:00 2001
2From: Roland Shoemaker <bracewell@google.com>
3Date: Wed, 15 Jun 2022 10:43:05 -0700
4Subject: [PATCH] [release-branch.go1.17] go/parser: limit recursion depth
5
6Limit nested parsing to 100,000, which prevents stack exhaustion when
7parsing deeply nested statements, types, and expressions. Also limit
8the scope depth to 1,000 during object resolution.
9
10Thanks to Juho Nurminen of Mattermost for reporting this issue.
11
12Fixes #53707
13Updates #53616
14Fixes CVE-2022-1962
15
16Change-Id: I4d7b86c1d75d0bf3c7af1fdea91582aa74272c64
17Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1491025
18Reviewed-by: Russ Cox <rsc@google.com>
19Reviewed-by: Damien Neil <dneil@google.com>
20(cherry picked from commit 6a856f08d58e4b6705c0c337d461c540c1235c83)
21Reviewed-on: https://go-review.googlesource.com/c/go/+/417070
22Reviewed-by: Heschi Kreinick <heschi@google.com>
23TryBot-Result: Gopher Robot <gobot@golang.org>
24Run-TryBot: Michael Knyszek <mknyszek@google.com>
25
26Upstream-Status: Backport [https://github.com/golang/go/commit/ba8788ebcead55e99e631c6a1157ad7b35535d11]
27CVE: CVE-2022-1962
28Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com>
29---
30 src/go/parser/interface.go | 10 ++-
31 src/go/parser/parser.go | 48 ++++++++--
32 src/go/parser/parser_test.go | 169 +++++++++++++++++++++++++++++++++++
33 3 files changed, 220 insertions(+), 7 deletions(-)
34
35diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go
36index 54f9d7b..537b327 100644
37--- a/src/go/parser/interface.go
38+++ b/src/go/parser/interface.go
39@@ -92,8 +92,11 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
40 defer func() {
41 if e := recover(); e != nil {
42 // resume same panic if it's not a bailout
43- if _, ok := e.(bailout); !ok {
44+ bail, ok := e.(bailout)
45+ if !ok {
46 panic(e)
47+ } else if bail.msg != "" {
48+ p.errors.Add(p.file.Position(bail.pos), bail.msg)
49 }
50 }
51
52@@ -188,8 +191,11 @@ func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode M
53 defer func() {
54 if e := recover(); e != nil {
55 // resume same panic if it's not a bailout
56- if _, ok := e.(bailout); !ok {
57+ bail, ok := e.(bailout)
58+ if !ok {
59 panic(e)
60+ } else if bail.msg != "" {
61+ p.errors.Add(p.file.Position(bail.pos), bail.msg)
62 }
63 }
64 p.errors.Sort()
65diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
66index 31a7398..586fe90 100644
67--- a/src/go/parser/parser.go
68+++ b/src/go/parser/parser.go
69@@ -64,6 +64,10 @@ type parser struct {
70 unresolved []*ast.Ident // unresolved identifiers
71 imports []*ast.ImportSpec // list of imports
72
73+ // nestLev is used to track and limit the recursion depth
74+ // during parsing.
75+ nestLev int
76+
77 // Label scopes
78 // (maintained by open/close LabelScope)
79 labelScope *ast.Scope // label scope for current function
80@@ -236,6 +240,24 @@ func un(p *parser) {
81 p.printTrace(")")
82 }
83
84+// maxNestLev is the deepest we're willing to recurse during parsing
85+const maxNestLev int = 1e5
86+
87+func incNestLev(p *parser) *parser {
88+ p.nestLev++
89+ if p.nestLev > maxNestLev {
90+ p.error(p.pos, "exceeded max nesting depth")
91+ panic(bailout{})
92+ }
93+ return p
94+}
95+
96+// decNestLev is used to track nesting depth during parsing to prevent stack exhaustion.
97+// It is used along with incNestLev in a similar fashion to how un and trace are used.
98+func decNestLev(p *parser) {
99+ p.nestLev--
100+}
101+
102 // Advance to the next token.
103 func (p *parser) next0() {
104 // Because of one-token look-ahead, print the previous token
105@@ -348,8 +370,12 @@ func (p *parser) next() {
106 }
107 }
108
109-// A bailout panic is raised to indicate early termination.
110-type bailout struct{}
111+// A bailout panic is raised to indicate early termination. pos and msg are
112+// only populated when bailing out of object resolution.
113+type bailout struct {
114+ pos token.Pos
115+ msg string
116+}
117
118 func (p *parser) error(pos token.Pos, msg string) {
119 epos := p.file.Position(pos)
120@@ -1030,6 +1056,8 @@ func (p *parser) parseChanType() *ast.ChanType {
121
122 // If the result is an identifier, it is not resolved.
123 func (p *parser) tryIdentOrType() ast.Expr {
124+ defer decNestLev(incNestLev(p))
125+
126 switch p.tok {
127 case token.IDENT:
128 return p.parseTypeName()
129@@ -1609,7 +1637,13 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
130 }
131
132 x := p.parseUnaryExpr(lhs)
133- for {
134+ // We track the nesting here rather than at the entry for the function,
135+ // since it can iteratively produce a nested output, and we want to
136+ // limit how deep a structure we generate.
137+ var n int
138+ defer func() { p.nestLev -= n }()
139+ for n = 1; ; n++ {
140+ incNestLev(p)
141 op, oprec := p.tokPrec()
142 if oprec < prec1 {
143 return x
144@@ -1628,7 +1662,7 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
145 // The result may be a type or even a raw type ([...]int). Callers must
146 // check the result (using checkExpr or checkExprOrType), depending on
147 // context.
148-func (p *parser) parseExpr(lhs bool) ast.Expr {
149+func (p *parser) parseExpr(lhs bool) ast.Expr {
150 if p.trace {
151 defer un(trace(p, "Expression"))
152 }
153@@ -1899,6 +1933,8 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) {
154 }
155
156 func (p *parser) parseIfStmt() *ast.IfStmt {
157+ defer decNestLev(incNestLev(p))
158+
159 if p.trace {
160 defer un(trace(p, "IfStmt"))
161 }
162@@ -2214,6 +2250,8 @@ func (p *parser) parseForStmt() ast.Stmt {
163 }
164
165 func (p *parser) parseStmt() (s ast.Stmt) {
166+ defer decNestLev(incNestLev(p))
167+
168 if p.trace {
169 defer un(trace(p, "Statement"))
170 }
171diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go
172index 25a374e..37a6a2b 100644
173--- a/src/go/parser/parser_test.go
174+++ b/src/go/parser/parser_test.go
175@@ -10,6 +10,7 @@ import (
176 "go/ast"
177 "go/token"
178 "os"
179+ "runtime"
180 "strings"
181 "testing"
182 )
183@@ -569,3 +570,171 @@ type x int // comment
184 t.Errorf("got %q, want %q", comment, "// comment")
185 }
186 }
187+
188+var parseDepthTests = []struct {
189+ name string
190+ format string
191+ // multipler is used when a single statement may result in more than one
192+ // change in the depth level, for instance "1+(..." produces a BinaryExpr
193+ // followed by a UnaryExpr, which increments the depth twice. The test
194+ // case comment explains which nodes are triggering the multiple depth
195+ // changes.
196+ parseMultiplier int
197+ // scope is true if we should also test the statement for the resolver scope
198+ // depth limit.
199+ scope bool
200+ // scopeMultiplier does the same as parseMultiplier, but for the scope
201+ // depths.
202+ scopeMultiplier int
203+}{
204+ // The format expands the part inside « » many times.
205+ // A second set of brackets nested inside the first stops the repetition,
206+ // so that for example «(«1»)» expands to (((...((((1))))...))).
207+ {name: "array", format: "package main; var x «[1]»int"},
208+ {name: "slice", format: "package main; var x «[]»int"},
209+ {name: "struct", format: "package main; var x «struct { X «int» }»", scope: true},
210+ {name: "pointer", format: "package main; var x «*»int"},
211+ {name: "func", format: "package main; var x «func()»int", scope: true},
212+ {name: "chan", format: "package main; var x «chan »int"},
213+ {name: "chan2", format: "package main; var x «<-chan »int"},
214+ {name: "interface", format: "package main; var x «interface { M() «int» }»", scope: true, scopeMultiplier: 2}, // Scopes: InterfaceType, FuncType
215+ {name: "map", format: "package main; var x «map[int]»int"},
216+ {name: "slicelit", format: "package main; var x = «[]any{«»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit
217+ {name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit
218+ {name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit
219+ {name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 2}, // Parser nodes: CompositeLit, KeyValueExpr
220+ {name: "dot", format: "package main; var x = «x.»x"},
221+ {name: "index", format: "package main; var x = x«[1]»"},
222+ {name: "slice", format: "package main; var x = x«[1:2]»"},
223+ {name: "slice3", format: "package main; var x = x«[1:2:3]»"},
224+ {name: "dottype", format: "package main; var x = x«.(any)»"},
225+ {name: "callseq", format: "package main; var x = x«()»"},
226+ {name: "methseq", format: "package main; var x = x«.m()»", parseMultiplier: 2}, // Parser nodes: SelectorExpr, CallExpr
227+ {name: "binary", format: "package main; var x = «1+»1"},
228+ {name: "binaryparen", format: "package main; var x = «1+(«1»)»", parseMultiplier: 2}, // Parser nodes: BinaryExpr, ParenExpr
229+ {name: "unary", format: "package main; var x = «^»1"},
230+ {name: "addr", format: "package main; var x = «& »x"},
231+ {name: "star", format: "package main; var x = «*»x"},
232+ {name: "recv", format: "package main; var x = «<-»x"},
233+ {name: "call", format: "package main; var x = «f(«1»)»", parseMultiplier: 2}, // Parser nodes: Ident, CallExpr
234+ {name: "conv", format: "package main; var x = «(*T)(«1»)»", parseMultiplier: 2}, // Parser nodes: ParenExpr, CallExpr
235+ {name: "label", format: "package main; func main() { «Label:» }"},
236+ {name: "if", format: "package main; func main() { «if true { «» }»}", parseMultiplier: 2, scope: true, scopeMultiplier: 2}, // Parser nodes: IfStmt, BlockStmt. Scopes: IfStmt, BlockStmt
237+ {name: "ifelse", format: "package main; func main() { «if true {} else » {} }", scope: true},
238+ {name: "switch", format: "package main; func main() { «switch { default: «» }»}", scope: true, scopeMultiplier: 2}, // Scopes: TypeSwitchStmt, CaseClause
239+ {name: "typeswitch", format: "package main; func main() { «switch x.(type) { default: «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: TypeSwitchStmt, CaseClause
240+ {name: "for0", format: "package main; func main() { «for { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt
241+ {name: "for1", format: "package main; func main() { «for x { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt
242+ {name: "for3", format: "package main; func main() { «for f(); g(); h() { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt
243+ {name: "forrange0", format: "package main; func main() { «for range x { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt
244+ {name: "forrange1", format: "package main; func main() { «for x = range z { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt
245+ {name: "forrange2", format: "package main; func main() { «for x, y = range z { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt
246+ {name: "go", format: "package main; func main() { «go func() { «» }()» }", parseMultiplier: 2, scope: true}, // Parser nodes: GoStmt, FuncLit
247+ {name: "defer", format: "package main; func main() { «defer func() { «» }()» }", parseMultiplier: 2, scope: true}, // Parser nodes: DeferStmt, FuncLit
248+ {name: "select", format: "package main; func main() { «select { default: «» }» }", scope: true},
249+}
250+
251+// split splits pre«mid»post into pre, mid, post.
252+// If the string does not have that form, split returns x, "", "".
253+func split(x string) (pre, mid, post string) {
254+ start, end := strings.Index(x, "«"), strings.LastIndex(x, "»")
255+ if start < 0 || end < 0 {
256+ return x, "", ""
257+ }
258+ return x[:start], x[start+len("«") : end], x[end+len("»"):]
259+}
260+
261+func TestParseDepthLimit(t *testing.T) {
262+ if runtime.GOARCH == "wasm" {
263+ t.Skip("causes call stack exhaustion on js/wasm")
264+ }
265+ for _, tt := range parseDepthTests {
266+ for _, size := range []string{"small", "big"} {
267+ t.Run(tt.name+"/"+size, func(t *testing.T) {
268+ n := maxNestLev + 1
269+ if tt.parseMultiplier > 0 {
270+ n /= tt.parseMultiplier
271+ }
272+ if size == "small" {
273+ // Decrease the number of statements by 10, in order to check
274+ // that we do not fail when under the limit. 10 is used to
275+ // provide some wiggle room for cases where the surrounding
276+ // scaffolding syntax adds some noise to the depth that changes
277+ // on a per testcase basis.
278+ n -= 10
279+ }
280+
281+ pre, mid, post := split(tt.format)
282+ if strings.Contains(mid, "«") {
283+ left, base, right := split(mid)
284+ mid = strings.Repeat(left, n) + base + strings.Repeat(right, n)
285+ } else {
286+ mid = strings.Repeat(mid, n)
287+ }
288+ input := pre + mid + post
289+
290+ fset := token.NewFileSet()
291+ _, err := ParseFile(fset, "", input, ParseComments|SkipObjectResolution)
292+ if size == "small" {
293+ if err != nil {
294+ t.Errorf("ParseFile(...): %v (want success)", err)
295+ }
296+ } else {
297+ expected := "exceeded max nesting depth"
298+ if err == nil || !strings.HasSuffix(err.Error(), expected) {
299+ t.Errorf("ParseFile(...) = _, %v, want %q", err, expected)
300+ }
301+ }
302+ })
303+ }
304+ }
305+}
306+
307+func TestScopeDepthLimit(t *testing.T) {
308+ if runtime.GOARCH == "wasm" {
309+ t.Skip("causes call stack exhaustion on js/wasm")
310+ }
311+ for _, tt := range parseDepthTests {
312+ if !tt.scope {
313+ continue
314+ }
315+ for _, size := range []string{"small", "big"} {
316+ t.Run(tt.name+"/"+size, func(t *testing.T) {
317+ n := maxScopeDepth + 1
318+ if tt.scopeMultiplier > 0 {
319+ n /= tt.scopeMultiplier
320+ }
321+ if size == "small" {
322+ // Decrease the number of statements by 10, in order to check
323+ // that we do not fail when under the limit. 10 is used to
324+ // provide some wiggle room for cases where the surrounding
325+ // scaffolding syntax adds some noise to the depth that changes
326+ // on a per testcase basis.
327+ n -= 10
328+ }
329+
330+ pre, mid, post := split(tt.format)
331+ if strings.Contains(mid, "«") {
332+ left, base, right := split(mid)
333+ mid = strings.Repeat(left, n) + base + strings.Repeat(right, n)
334+ } else {
335+ mid = strings.Repeat(mid, n)
336+ }
337+ input := pre + mid + post
338+
339+ fset := token.NewFileSet()
340+ _, err := ParseFile(fset, "", input, DeclarationErrors)
341+ if size == "small" {
342+ if err != nil {
343+ t.Errorf("ParseFile(...): %v (want success)", err)
344+ }
345+ } else {
346+ expected := "exceeded max scope depth during object resolution"
347+ if err == nil || !strings.HasSuffix(err.Error(), expected) {
348+ t.Errorf("ParseFile(...) = _, %v, want %q", err, expected)
349+ }
350+ }
351+ })
352+ }
353+ }
354+}
355--
3562.30.2
357