From: Vivek Kumbhar <[email protected]>

Signed-off-by: Vivek Kumbhar <[email protected]>
Signed-off-by: Steve Sakoman <[email protected]>
---
 meta/recipes-devtools/go/go-1.14.inc          |   1 +
 .../go/go-1.14/CVE-2022-1962.patch            | 357 ++++++++++++++++++
 2 files changed, 358 insertions(+)
 create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch

diff --git a/meta/recipes-devtools/go/go-1.14.inc 
b/meta/recipes-devtools/go/go-1.14.inc
index 1d97001654..be9abb5b2d 100644
--- a/meta/recipes-devtools/go/go-1.14.inc
+++ b/meta/recipes-devtools/go/go-1.14.inc
@@ -51,6 +51,7 @@ SRC_URI += "\
     file://CVE-2022-28327.patch \
     file://CVE-2022-41715.patch \
     file://CVE-2022-41717.patch \
+    file://CVE-2022-1962.patch \
 "
 
 SRC_URI_append_libc-musl = " 
file://0009-ld-replace-glibc-dynamic-linker-with-musl.patch"
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 @@
+From ba8788ebcead55e99e631c6a1157ad7b35535d11 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <[email protected]>
+Date: Wed, 15 Jun 2022 10:43:05 -0700
+Subject: [PATCH] [release-branch.go1.17] go/parser: limit recursion depth
+
+Limit nested parsing to 100,000, which prevents stack exhaustion when
+parsing deeply nested statements, types, and expressions. Also limit
+the scope depth to 1,000 during object resolution.
+
+Thanks to Juho Nurminen of Mattermost for reporting this issue.
+
+Fixes #53707
+Updates #53616
+Fixes CVE-2022-1962
+
+Change-Id: I4d7b86c1d75d0bf3c7af1fdea91582aa74272c64
+Reviewed-on: 
https://team-review.git.corp.google.com/c/golang/go-private/+/1491025
+Reviewed-by: Russ Cox <[email protected]>
+Reviewed-by: Damien Neil <[email protected]>
+(cherry picked from commit 6a856f08d58e4b6705c0c337d461c540c1235c83)
+Reviewed-on: https://go-review.googlesource.com/c/go/+/417070
+Reviewed-by: Heschi Kreinick <[email protected]>
+TryBot-Result: Gopher Robot <[email protected]>
+Run-TryBot: Michael Knyszek <[email protected]>
+
+Upstream-Status: Backport 
[https://github.com/golang/go/commit/ba8788ebcead55e99e631c6a1157ad7b35535d11]
+CVE: CVE-2022-1962
+Signed-off-by: Vivek Kumbhar <[email protected]>
+---
+ src/go/parser/interface.go   |  10 ++-
+ src/go/parser/parser.go      |  48 ++++++++--
+ src/go/parser/parser_test.go | 169 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 220 insertions(+), 7 deletions(-)
+
+diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go
+index 54f9d7b..537b327 100644
+--- a/src/go/parser/interface.go
++++ b/src/go/parser/interface.go
+@@ -92,8 +92,11 @@ func ParseFile(fset *token.FileSet, filename string, src 
interface{}, mode Mode)
+       defer func() {
+               if e := recover(); e != nil {
+                       // resume same panic if it's not a bailout
+-                      if _, ok := e.(bailout); !ok {
++                      bail, ok := e.(bailout)
++                      if !ok {
+                               panic(e)
++                      } else if bail.msg != "" {
++                              p.errors.Add(p.file.Position(bail.pos), 
bail.msg)
+                       }
+               }
+ 
+@@ -188,8 +191,11 @@ func ParseExprFrom(fset *token.FileSet, filename string, 
src interface{}, mode M
+       defer func() {
+               if e := recover(); e != nil {
+                       // resume same panic if it's not a bailout
+-                      if _, ok := e.(bailout); !ok {
++                      bail, ok := e.(bailout)
++                      if !ok {
+                               panic(e)
++                      } else if bail.msg != "" {
++                              p.errors.Add(p.file.Position(bail.pos), 
bail.msg)
+                       }
+               }
+               p.errors.Sort()
+diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
+index 31a7398..586fe90 100644
+--- a/src/go/parser/parser.go
++++ b/src/go/parser/parser.go
+@@ -64,6 +64,10 @@ type parser struct {
+       unresolved []*ast.Ident      // unresolved identifiers
+       imports    []*ast.ImportSpec // list of imports
+ 
++      // nestLev is used to track and limit the recursion depth
++      // during parsing.
++      nestLev int
++      
+       // Label scopes
+       // (maintained by open/close LabelScope)
+       labelScope  *ast.Scope     // label scope for current function
+@@ -236,6 +240,24 @@ func un(p *parser) {
+       p.printTrace(")")
+ }
+ 
++// maxNestLev is the deepest we're willing to recurse during parsing
++const maxNestLev int = 1e5
++
++func incNestLev(p *parser) *parser {
++      p.nestLev++
++      if p.nestLev > maxNestLev {
++              p.error(p.pos, "exceeded max nesting depth")
++              panic(bailout{})
++      }
++      return p
++}
++
++// decNestLev is used to track nesting depth during parsing to prevent stack 
exhaustion.
++// It is used along with incNestLev in a similar fashion to how un and trace 
are used.
++func decNestLev(p *parser) {
++      p.nestLev--
++}
++
+ // Advance to the next token.
+ func (p *parser) next0() {
+       // Because of one-token look-ahead, print the previous token
+@@ -348,8 +370,12 @@ func (p *parser) next() {
+       }
+ }
+ 
+-// A bailout panic is raised to indicate early termination.
+-type bailout struct{}
++// A bailout panic is raised to indicate early termination. pos and msg are
++// only populated when bailing out of object resolution.
++type bailout struct {
++      pos token.Pos
++      msg string
++}
+ 
+ func (p *parser) error(pos token.Pos, msg string) {
+       epos := p.file.Position(pos)
+@@ -1030,6 +1056,8 @@ func (p *parser) parseChanType() *ast.ChanType {
+ 
+ // If the result is an identifier, it is not resolved.
+ func (p *parser) tryIdentOrType() ast.Expr {
++      defer decNestLev(incNestLev(p))
++
+       switch p.tok {
+       case token.IDENT:
+               return p.parseTypeName()
+@@ -1609,7 +1637,13 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) 
ast.Expr {
+       }
+ 
+       x := p.parseUnaryExpr(lhs)
+-      for {
++      // We track the nesting here rather than at the entry for the function,
++      // since it can iteratively produce a nested output, and we want to
++      // limit how deep a structure we generate.
++      var n int
++      defer func() { p.nestLev -= n }()
++      for n = 1; ; n++ {
++              incNestLev(p)
+               op, oprec := p.tokPrec()
+               if oprec < prec1 {
+                       return x
+@@ -1628,7 +1662,7 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) 
ast.Expr {
+ // The result may be a type or even a raw type ([...]int). Callers must
+ // check the result (using checkExpr or checkExprOrType), depending on
+ // context.
+-func (p *parser) parseExpr(lhs bool) ast.Expr {
++func (p *parser) parseExpr(lhs bool) ast.Expr {    
+       if p.trace {
+               defer un(trace(p, "Expression"))
+       }
+@@ -1899,6 +1933,8 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond 
ast.Expr) {
+ }
+ 
+ func (p *parser) parseIfStmt() *ast.IfStmt {
++      defer decNestLev(incNestLev(p))
++
+       if p.trace {
+               defer un(trace(p, "IfStmt"))
+       }
+@@ -2214,6 +2250,8 @@ func (p *parser) parseForStmt() ast.Stmt {
+ }
+ 
+ func (p *parser) parseStmt() (s ast.Stmt) {
++      defer decNestLev(incNestLev(p))
++
+       if p.trace {
+               defer un(trace(p, "Statement"))
+       }
+diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go
+index 25a374e..37a6a2b 100644
+--- a/src/go/parser/parser_test.go
++++ b/src/go/parser/parser_test.go
+@@ -10,6 +10,7 @@ import (
+       "go/ast"
+       "go/token"
+       "os"
++      "runtime"
+       "strings"
+       "testing"
+ )
+@@ -569,3 +570,171 @@ type x int // comment
+               t.Errorf("got %q, want %q", comment, "// comment")
+       }
+ }
++
++var parseDepthTests = []struct {
++      name   string
++      format string
++      // multipler is used when a single statement may result in more than one
++      // change in the depth level, for instance "1+(..." produces a 
BinaryExpr
++      // followed by a UnaryExpr, which increments the depth twice. The test
++      // case comment explains which nodes are triggering the multiple depth
++      // changes.
++      parseMultiplier int
++      // scope is true if we should also test the statement for the resolver 
scope
++      // depth limit.
++      scope bool
++      // scopeMultiplier does the same as parseMultiplier, but for the scope
++      // depths.
++      scopeMultiplier int
++}{
++      // The format expands the part inside « » many times.
++      // A second set of brackets nested inside the first stops the 
repetition,
++      // so that for example «(«1»)» expands to (((...((((1))))...))).
++      {name: "array", format: "package main; var x «[1]»int"},
++      {name: "slice", format: "package main; var x «[]»int"},
++      {name: "struct", format: "package main; var x «struct { X «int» }»", 
scope: true},
++      {name: "pointer", format: "package main; var x «*»int"},
++      {name: "func", format: "package main; var x «func()»int", scope: true},
++      {name: "chan", format: "package main; var x «chan »int"},
++      {name: "chan2", format: "package main; var x «<-chan »int"},
++      {name: "interface", format: "package main; var x «interface { M() «int» 
}»", scope: true, scopeMultiplier: 2}, // Scopes: InterfaceType, FuncType
++      {name: "map", format: "package main; var x «map[int]»int"},
++      {name: "slicelit", format: "package main; var x = «[]any{«»}»", 
parseMultiplier: 2},             // Parser nodes: UnaryExpr, CompositeLit
++      {name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", 
parseMultiplier: 2},         // Parser nodes: UnaryExpr, CompositeLit
++      {name: "structlit", format: "package main; var x = «struct{x 
any}{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit
++      {name: "maplit", format: "package main; var x = 
«map[int]any{1:«nil»}»", parseMultiplier: 2},    // Parser nodes: CompositeLit, 
KeyValueExpr
++      {name: "dot", format: "package main; var x = «x.»x"},
++      {name: "index", format: "package main; var x = x«[1]»"},
++      {name: "slice", format: "package main; var x = x«[1:2]»"},
++      {name: "slice3", format: "package main; var x = x«[1:2:3]»"},
++      {name: "dottype", format: "package main; var x = x«.(any)»"},
++      {name: "callseq", format: "package main; var x = x«()»"},
++      {name: "methseq", format: "package main; var x = x«.m()»", 
parseMultiplier: 2}, // Parser nodes: SelectorExpr, CallExpr
++      {name: "binary", format: "package main; var x = «1+»1"},
++      {name: "binaryparen", format: "package main; var x = «1+(«1»)»", 
parseMultiplier: 2}, // Parser nodes: BinaryExpr, ParenExpr
++      {name: "unary", format: "package main; var x = «^»1"},
++      {name: "addr", format: "package main; var x = «& »x"},
++      {name: "star", format: "package main; var x = «*»x"},
++      {name: "recv", format: "package main; var x = «<-»x"},
++      {name: "call", format: "package main; var x = «f(«1»)»", 
parseMultiplier: 2},    // Parser nodes: Ident, CallExpr
++      {name: "conv", format: "package main; var x = «(*T)(«1»)»", 
parseMultiplier: 2}, // Parser nodes: ParenExpr, CallExpr
++      {name: "label", format: "package main; func main() { «Label:» }"},
++      {name: "if", format: "package main; func main() { «if true { «» }»}", 
parseMultiplier: 2, scope: true, scopeMultiplier: 2}, // Parser nodes: IfStmt, 
BlockStmt. Scopes: IfStmt, BlockStmt
++      {name: "ifelse", format: "package main; func main() { «if true {} else 
» {} }", scope: true},
++      {name: "switch", format: "package main; func main() { «switch { 
default: «» }»}", scope: true, scopeMultiplier: 2},               // Scopes: 
TypeSwitchStmt, CaseClause
++      {name: "typeswitch", format: "package main; func main() { «switch 
x.(type) { default: «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: 
TypeSwitchStmt, CaseClause
++      {name: "for0", format: "package main; func main() { «for { «» }» }", 
scope: true, scopeMultiplier: 2},                            // Scopes: 
ForStmt, BlockStmt
++      {name: "for1", format: "package main; func main() { «for x { «» }» }", 
scope: true, scopeMultiplier: 2},                          // Scopes: ForStmt, 
BlockStmt
++      {name: "for3", format: "package main; func main() { «for f(); g(); h() 
{ «» }» }", scope: true, scopeMultiplier: 2},              // Scopes: ForStmt, 
BlockStmt
++      {name: "forrange0", format: "package main; func main() { «for range x { 
«» }» }", scope: true, scopeMultiplier: 2},               // Scopes: RangeStmt, 
BlockStmt
++      {name: "forrange1", format: "package main; func main() { «for x = range 
z { «» }» }", scope: true, scopeMultiplier: 2},           // Scopes: RangeStmt, 
BlockStmt
++      {name: "forrange2", format: "package main; func main() { «for x, y = 
range z { «» }» }", scope: true, scopeMultiplier: 2},        // Scopes: 
RangeStmt, BlockStmt
++      {name: "go", format: "package main; func main() { «go func() { «» }()» 
}", parseMultiplier: 2, scope: true},                      // Parser nodes: 
GoStmt, FuncLit
++      {name: "defer", format: "package main; func main() { «defer func() { «» 
}()» }", parseMultiplier: 2, scope: true},                // Parser nodes: 
DeferStmt, FuncLit
++      {name: "select", format: "package main; func main() { «select { 
default: «» }» }", scope: true},
++}
++
++// split splits pre«mid»post into pre, mid, post.
++// If the string does not have that form, split returns x, "", "".
++func split(x string) (pre, mid, post string) {
++      start, end := strings.Index(x, "«"), strings.LastIndex(x, "»")
++      if start < 0 || end < 0 {
++              return x, "", ""
++      }
++      return x[:start], x[start+len("«") : end], x[end+len("»"):]
++}
++
++func TestParseDepthLimit(t *testing.T) {
++      if runtime.GOARCH == "wasm" {
++              t.Skip("causes call stack exhaustion on js/wasm")
++      }
++      for _, tt := range parseDepthTests {
++              for _, size := range []string{"small", "big"} {
++                      t.Run(tt.name+"/"+size, func(t *testing.T) {
++                              n := maxNestLev + 1
++                              if tt.parseMultiplier > 0 {
++                                      n /= tt.parseMultiplier
++                              }
++                              if size == "small" {
++                                      // Decrease the number of statements by 
10, in order to check
++                                      // that we do not fail when under the 
limit. 10 is used to
++                                      // provide some wiggle room for cases 
where the surrounding
++                                      // scaffolding syntax adds some noise 
to the depth that changes
++                                      // on a per testcase basis.
++                                      n -= 10
++                              }
++
++                              pre, mid, post := split(tt.format)
++                              if strings.Contains(mid, "«") {
++                                      left, base, right := split(mid)
++                                      mid = strings.Repeat(left, n) + base + 
strings.Repeat(right, n)
++                              } else {
++                                      mid = strings.Repeat(mid, n)
++                              }
++                              input := pre + mid + post
++
++                              fset := token.NewFileSet()
++                              _, err := ParseFile(fset, "", input, 
ParseComments|SkipObjectResolution)
++                              if size == "small" {
++                                      if err != nil {
++                                              t.Errorf("ParseFile(...): %v 
(want success)", err)
++                                      }
++                              } else {
++                                      expected := "exceeded max nesting depth"
++                                      if err == nil || 
!strings.HasSuffix(err.Error(), expected) {
++                                              t.Errorf("ParseFile(...) = _, 
%v, want %q", err, expected)
++                                      }
++                              }
++                      })
++              }
++      }
++}
++
++func TestScopeDepthLimit(t *testing.T) {
++      if runtime.GOARCH == "wasm" {
++              t.Skip("causes call stack exhaustion on js/wasm")
++      }
++      for _, tt := range parseDepthTests {
++              if !tt.scope {
++                      continue
++              }
++              for _, size := range []string{"small", "big"} {
++                      t.Run(tt.name+"/"+size, func(t *testing.T) {
++                              n := maxScopeDepth + 1
++                              if tt.scopeMultiplier > 0 {
++                                      n /= tt.scopeMultiplier
++                              }
++                              if size == "small" {
++                                      // Decrease the number of statements by 
10, in order to check
++                                      // that we do not fail when under the 
limit. 10 is used to
++                                      // provide some wiggle room for cases 
where the surrounding
++                                      // scaffolding syntax adds some noise 
to the depth that changes
++                                      // on a per testcase basis.
++                                      n -= 10
++                              }
++
++                              pre, mid, post := split(tt.format)
++                              if strings.Contains(mid, "«") {
++                                      left, base, right := split(mid)
++                                      mid = strings.Repeat(left, n) + base + 
strings.Repeat(right, n)
++                              } else {
++                                      mid = strings.Repeat(mid, n)
++                              }
++                              input := pre + mid + post
++
++                              fset := token.NewFileSet()
++                              _, err := ParseFile(fset, "", input, 
DeclarationErrors)
++                              if size == "small" {
++                                      if err != nil {
++                                              t.Errorf("ParseFile(...): %v 
(want success)", err)
++                                      }
++                              } else {
++                                      expected := "exceeded max scope depth 
during object resolution"
++                                      if err == nil || 
!strings.HasSuffix(err.Error(), expected) {
++                                              t.Errorf("ParseFile(...) = _, 
%v, want %q", err, expected)
++                                      }
++                              }
++                      })
++              }
++      }
++}
+-- 
+2.30.2
+
-- 
2.25.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#176769): 
https://lists.openembedded.org/g/openembedded-core/message/176769
Mute This Topic: https://lists.openembedded.org/mt/96751997/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to