diff mbox series

[dunfell,04/11] golang: fix CVE-2022-24291

Message ID 20221117165456.1029099-4-ralph.siemsen@linaro.org
State Accepted, archived
Commit a2d3d80a7df5b8f57105ef2b680e9e01a9da6486
Headers show
Series [dunfell,01/11] golang: fix CVE-2021-33195 | expand

Commit Message

Ralph Siemsen Nov. 17, 2022, 4:54 p.m. UTC
Upstream-Status: Backport [https://github.com/golang/go/commit/2b65cde5868d8245ef8a0b8eba1e361440252d3b]
CVE: CVE-2022-24921
Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org
---
 meta/recipes-devtools/go/go-1.14.inc          |   1 +
 .../go/go-1.14/CVE-2022-24921.patch           | 198 ++++++++++++++++++
 2 files changed, 199 insertions(+)
 create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2022-24921.patch
diff mbox series

Patch

diff --git a/meta/recipes-devtools/go/go-1.14.inc b/meta/recipes-devtools/go/go-1.14.inc
index ae3f724c53..d670d637cd 100644
--- a/meta/recipes-devtools/go/go-1.14.inc
+++ b/meta/recipes-devtools/go/go-1.14.inc
@@ -45,6 +45,7 @@  SRC_URI += "\
     file://CVE-2021-33195.patch \
     file://CVE-2021-33198.patch \
     file://CVE-2021-44716.patch \
+    file://CVE-2022-24921.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-24921.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-24921.patch
new file mode 100644
index 0000000000..e4270d8a75
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-24921.patch
@@ -0,0 +1,198 @@ 
+From ba99f699d26483ea1045f47c760e9be30799e311 Mon Sep 17 00:00:00 2001
+From: Russ Cox <rsc@golang.org>
+Date: Wed, 2 Feb 2022 16:41:32 -0500
+Subject: [PATCH] regexp/syntax: reject very deeply nested regexps in Parse
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Upstream-Status: Backport [https://github.com/golang/go/commit/2b65cde5868d8245ef8a0b8eba1e361440252d3b]
+CVE: CVE-2022-24921
+Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org
+
+
+The regexp code assumes it can recurse over the structure of
+a regexp safely. Go's growable stacks make that reasonable
+for all plausible regexps, but implausible ones can reach the
+“infinite recursion?” stack limit.
+
+This CL limits the depth of any parsed regexp to 1000.
+That is, the depth of the parse tree is required to be ≤ 1000.
+Regexps that require deeper parse trees will return ErrInternalError.
+A future CL will change the error to ErrInvalidDepth,
+but using ErrInternalError for now avoids introducing new API
+in point releases when this is backported.
+
+Fixes #51112.
+Fixes #51117.
+
+Change-Id: I97d2cd82195946eb43a4ea8561f5b95f91fb14c5
+Reviewed-on: https://go-review.googlesource.com/c/go/+/384616
+Trust: Russ Cox <rsc@golang.org>
+Run-TryBot: Russ Cox <rsc@golang.org>
+Reviewed-by: Ian Lance Taylor <iant@golang.org>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/384855
+---
+ src/regexp/syntax/parse.go      | 72 ++++++++++++++++++++++++++++++++-
+ src/regexp/syntax/parse_test.go |  7 ++++
+ 2 files changed, 77 insertions(+), 2 deletions(-)
+
+diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go
+index 8c6d43a..55bd20d 100644
+--- a/src/regexp/syntax/parse.go
++++ b/src/regexp/syntax/parse.go
+@@ -76,13 +76,29 @@ const (
+ 	opVerticalBar
+ )
+ 
++// maxHeight is the maximum height of a regexp parse tree.
++// It is somewhat arbitrarily chosen, but the idea is to be large enough
++// that no one will actually hit in real use but at the same time small enough
++// that recursion on the Regexp tree will not hit the 1GB Go stack limit.
++// The maximum amount of stack for a single recursive frame is probably
++// closer to 1kB, so this could potentially be raised, but it seems unlikely
++// that people have regexps nested even this deeply.
++// We ran a test on Google's C++ code base and turned up only
++// a single use case with depth > 100; it had depth 128.
++// Using depth 1000 should be plenty of margin.
++// As an optimization, we don't even bother calculating heights
++// until we've allocated at least maxHeight Regexp structures.
++const maxHeight = 1000
++
+ type parser struct {
+ 	flags       Flags     // parse mode flags
+ 	stack       []*Regexp // stack of parsed expressions
+ 	free        *Regexp
+ 	numCap      int // number of capturing groups seen
+ 	wholeRegexp string
+-	tmpClass    []rune // temporary char class work space
++	tmpClass    []rune          // temporary char class work space
++	numRegexp   int             // number of regexps allocated
++	height      map[*Regexp]int // regexp height for height limit check
+ }
+ 
+ func (p *parser) newRegexp(op Op) *Regexp {
+@@ -92,16 +108,52 @@ func (p *parser) newRegexp(op Op) *Regexp {
+ 		*re = Regexp{}
+ 	} else {
+ 		re = new(Regexp)
++		p.numRegexp++
+ 	}
+ 	re.Op = op
+ 	return re
+ }
+ 
+ func (p *parser) reuse(re *Regexp) {
++	if p.height != nil {
++		delete(p.height, re)
++	}
+ 	re.Sub0[0] = p.free
+ 	p.free = re
+ }
+ 
++func (p *parser) checkHeight(re *Regexp) {
++	if p.numRegexp < maxHeight {
++		return
++	}
++	if p.height == nil {
++		p.height = make(map[*Regexp]int)
++		for _, re := range p.stack {
++			p.checkHeight(re)
++		}
++	}
++	if p.calcHeight(re, true) > maxHeight {
++		panic(ErrInternalError)
++	}
++}
++
++func (p *parser) calcHeight(re *Regexp, force bool) int {
++	if !force {
++		if h, ok := p.height[re]; ok {
++			return h
++		}
++	}
++	h := 1
++	for _, sub := range re.Sub {
++		hsub := p.calcHeight(sub, false)
++		if h < 1+hsub {
++			h = 1 + hsub
++		}
++	}
++	p.height[re] = h
++	return h
++}
++
+ // Parse stack manipulation.
+ 
+ // push pushes the regexp re onto the parse stack and returns the regexp.
+@@ -137,6 +189,7 @@ func (p *parser) push(re *Regexp) *Regexp {
+ 	}
+ 
+ 	p.stack = append(p.stack, re)
++	p.checkHeight(re)
+ 	return re
+ }
+ 
+@@ -252,6 +305,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (
+ 	re.Sub = re.Sub0[:1]
+ 	re.Sub[0] = sub
+ 	p.stack[n-1] = re
++	p.checkHeight(re)
+ 
+ 	if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) {
+ 		return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]}
+@@ -699,6 +753,21 @@ func literalRegexp(s string, flags Flags) *Regexp {
+ // Flags, and returns a regular expression parse tree. The syntax is
+ // described in the top-level comment.
+ func Parse(s string, flags Flags) (*Regexp, error) {
++	return parse(s, flags)
++}
++
++func parse(s string, flags Flags) (_ *Regexp, err error) {
++	defer func() {
++		switch r := recover(); r {
++		default:
++			panic(r)
++		case nil:
++			// ok
++		case ErrInternalError:
++			err = &Error{Code: ErrInternalError, Expr: s}
++		}
++	}()
++
+ 	if flags&Literal != 0 {
+ 		// Trivial parser for literal string.
+ 		if err := checkUTF8(s); err != nil {
+@@ -710,7 +779,6 @@ func Parse(s string, flags Flags) (*Regexp, error) {
+ 	// Otherwise, must do real work.
+ 	var (
+ 		p          parser
+-		err        error
+ 		c          rune
+ 		op         Op
+ 		lastRepeat string
+diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go
+index 5581ba1..1ef6d8a 100644
+--- a/src/regexp/syntax/parse_test.go
++++ b/src/regexp/syntax/parse_test.go
+@@ -207,6 +207,11 @@ var parseTests = []parseTest{
+ 	// Valid repetitions.
+ 	{`((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}))`, ``},
+ 	{`((((((((((x{1}){2}){2}){2}){2}){2}){2}){2}){2}){2})`, ``},
++
++	// Valid nesting.
++	{strings.Repeat("(", 999) + strings.Repeat(")", 999), ``},
++	{strings.Repeat("(?:", 999) + strings.Repeat(")*", 999), ``},
++	{"(" + strings.Repeat("|", 12345) + ")", ``}, // not nested at all
+ }
+ 
+ const testFlags = MatchNL | PerlX | UnicodeGroups
+@@ -482,6 +487,8 @@ var invalidRegexps = []string{
+ 	`a{100000}`,
+ 	`a{100000,}`,
+ 	"((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})",
++	strings.Repeat("(", 1000) + strings.Repeat(")", 1000),
++	strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000),
+ 	`\Q\E*`,
+ }
+