diff options
| -rw-r--r-- | meta/recipes-devtools/go/go-1.14.inc | 1 | ||||
| -rw-r--r-- | meta/recipes-devtools/go/go-1.14/CVE-2022-24921.patch | 198 |
2 files changed, 199 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14.inc b/meta/recipes-devtools/go/go-1.14.inc index 73b981db2b..08eefdcb5c 100644 --- a/meta/recipes-devtools/go/go-1.14.inc +++ b/meta/recipes-devtools/go/go-1.14.inc | |||
| @@ -46,6 +46,7 @@ SRC_URI += "\ | |||
| 46 | file://CVE-2021-33195.patch \ | 46 | file://CVE-2021-33195.patch \ |
| 47 | file://CVE-2021-33198.patch \ | 47 | file://CVE-2021-33198.patch \ |
| 48 | file://CVE-2021-44716.patch \ | 48 | file://CVE-2021-44716.patch \ |
| 49 | file://CVE-2022-24921.patch \ | ||
| 49 | " | 50 | " |
| 50 | 51 | ||
| 51 | SRC_URI_append_libc-musl = " file://0009-ld-replace-glibc-dynamic-linker-with-musl.patch" | 52 | 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 @@ | |||
| 1 | From ba99f699d26483ea1045f47c760e9be30799e311 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Russ Cox <rsc@golang.org> | ||
| 3 | Date: Wed, 2 Feb 2022 16:41:32 -0500 | ||
| 4 | Subject: [PATCH] regexp/syntax: reject very deeply nested regexps in Parse | ||
| 5 | MIME-Version: 1.0 | ||
| 6 | Content-Type: text/plain; charset=UTF-8 | ||
| 7 | Content-Transfer-Encoding: 8bit | ||
| 8 | |||
| 9 | Upstream-Status: Backport [https://github.com/golang/go/commit/2b65cde5868d8245ef8a0b8eba1e361440252d3b] | ||
| 10 | CVE: CVE-2022-24921 | ||
| 11 | Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org | ||
| 12 | |||
| 13 | |||
| 14 | The regexp code assumes it can recurse over the structure of | ||
| 15 | a regexp safely. Go's growable stacks make that reasonable | ||
| 16 | for all plausible regexps, but implausible ones can reach the | ||
| 17 | “infinite recursion?” stack limit. | ||
| 18 | |||
| 19 | This CL limits the depth of any parsed regexp to 1000. | ||
| 20 | That is, the depth of the parse tree is required to be ≤ 1000. | ||
| 21 | Regexps that require deeper parse trees will return ErrInternalError. | ||
| 22 | A future CL will change the error to ErrInvalidDepth, | ||
| 23 | but using ErrInternalError for now avoids introducing new API | ||
| 24 | in point releases when this is backported. | ||
| 25 | |||
| 26 | Fixes #51112. | ||
| 27 | Fixes #51117. | ||
| 28 | |||
| 29 | Change-Id: I97d2cd82195946eb43a4ea8561f5b95f91fb14c5 | ||
| 30 | Reviewed-on: https://go-review.googlesource.com/c/go/+/384616 | ||
| 31 | Trust: Russ Cox <rsc@golang.org> | ||
| 32 | Run-TryBot: Russ Cox <rsc@golang.org> | ||
| 33 | Reviewed-by: Ian Lance Taylor <iant@golang.org> | ||
| 34 | Reviewed-on: https://go-review.googlesource.com/c/go/+/384855 | ||
| 35 | --- | ||
| 36 | src/regexp/syntax/parse.go | 72 ++++++++++++++++++++++++++++++++- | ||
| 37 | src/regexp/syntax/parse_test.go | 7 ++++ | ||
| 38 | 2 files changed, 77 insertions(+), 2 deletions(-) | ||
| 39 | |||
| 40 | diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go | ||
| 41 | index 8c6d43a..55bd20d 100644 | ||
| 42 | --- a/src/regexp/syntax/parse.go | ||
| 43 | +++ b/src/regexp/syntax/parse.go | ||
| 44 | @@ -76,13 +76,29 @@ const ( | ||
| 45 | opVerticalBar | ||
| 46 | ) | ||
| 47 | |||
| 48 | +// maxHeight is the maximum height of a regexp parse tree. | ||
| 49 | +// It is somewhat arbitrarily chosen, but the idea is to be large enough | ||
| 50 | +// that no one will actually hit in real use but at the same time small enough | ||
| 51 | +// that recursion on the Regexp tree will not hit the 1GB Go stack limit. | ||
| 52 | +// The maximum amount of stack for a single recursive frame is probably | ||
| 53 | +// closer to 1kB, so this could potentially be raised, but it seems unlikely | ||
| 54 | +// that people have regexps nested even this deeply. | ||
| 55 | +// We ran a test on Google's C++ code base and turned up only | ||
| 56 | +// a single use case with depth > 100; it had depth 128. | ||
| 57 | +// Using depth 1000 should be plenty of margin. | ||
| 58 | +// As an optimization, we don't even bother calculating heights | ||
| 59 | +// until we've allocated at least maxHeight Regexp structures. | ||
| 60 | +const maxHeight = 1000 | ||
| 61 | + | ||
| 62 | type parser struct { | ||
| 63 | flags Flags // parse mode flags | ||
| 64 | stack []*Regexp // stack of parsed expressions | ||
| 65 | free *Regexp | ||
| 66 | numCap int // number of capturing groups seen | ||
| 67 | wholeRegexp string | ||
| 68 | - tmpClass []rune // temporary char class work space | ||
| 69 | + tmpClass []rune // temporary char class work space | ||
| 70 | + numRegexp int // number of regexps allocated | ||
| 71 | + height map[*Regexp]int // regexp height for height limit check | ||
| 72 | } | ||
| 73 | |||
| 74 | func (p *parser) newRegexp(op Op) *Regexp { | ||
| 75 | @@ -92,16 +108,52 @@ func (p *parser) newRegexp(op Op) *Regexp { | ||
| 76 | *re = Regexp{} | ||
| 77 | } else { | ||
| 78 | re = new(Regexp) | ||
| 79 | + p.numRegexp++ | ||
| 80 | } | ||
| 81 | re.Op = op | ||
| 82 | return re | ||
| 83 | } | ||
| 84 | |||
| 85 | func (p *parser) reuse(re *Regexp) { | ||
| 86 | + if p.height != nil { | ||
| 87 | + delete(p.height, re) | ||
| 88 | + } | ||
| 89 | re.Sub0[0] = p.free | ||
| 90 | p.free = re | ||
| 91 | } | ||
| 92 | |||
| 93 | +func (p *parser) checkHeight(re *Regexp) { | ||
| 94 | + if p.numRegexp < maxHeight { | ||
| 95 | + return | ||
| 96 | + } | ||
| 97 | + if p.height == nil { | ||
| 98 | + p.height = make(map[*Regexp]int) | ||
| 99 | + for _, re := range p.stack { | ||
| 100 | + p.checkHeight(re) | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + if p.calcHeight(re, true) > maxHeight { | ||
| 104 | + panic(ErrInternalError) | ||
| 105 | + } | ||
| 106 | +} | ||
| 107 | + | ||
| 108 | +func (p *parser) calcHeight(re *Regexp, force bool) int { | ||
| 109 | + if !force { | ||
| 110 | + if h, ok := p.height[re]; ok { | ||
| 111 | + return h | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + h := 1 | ||
| 115 | + for _, sub := range re.Sub { | ||
| 116 | + hsub := p.calcHeight(sub, false) | ||
| 117 | + if h < 1+hsub { | ||
| 118 | + h = 1 + hsub | ||
| 119 | + } | ||
| 120 | + } | ||
| 121 | + p.height[re] = h | ||
| 122 | + return h | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | // Parse stack manipulation. | ||
| 126 | |||
| 127 | // push pushes the regexp re onto the parse stack and returns the regexp. | ||
| 128 | @@ -137,6 +189,7 @@ func (p *parser) push(re *Regexp) *Regexp { | ||
| 129 | } | ||
| 130 | |||
| 131 | p.stack = append(p.stack, re) | ||
| 132 | + p.checkHeight(re) | ||
| 133 | return re | ||
| 134 | } | ||
| 135 | |||
| 136 | @@ -252,6 +305,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) ( | ||
| 137 | re.Sub = re.Sub0[:1] | ||
| 138 | re.Sub[0] = sub | ||
| 139 | p.stack[n-1] = re | ||
| 140 | + p.checkHeight(re) | ||
| 141 | |||
| 142 | if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { | ||
| 143 | return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} | ||
| 144 | @@ -699,6 +753,21 @@ func literalRegexp(s string, flags Flags) *Regexp { | ||
| 145 | // Flags, and returns a regular expression parse tree. The syntax is | ||
| 146 | // described in the top-level comment. | ||
| 147 | func Parse(s string, flags Flags) (*Regexp, error) { | ||
| 148 | + return parse(s, flags) | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +func parse(s string, flags Flags) (_ *Regexp, err error) { | ||
| 152 | + defer func() { | ||
| 153 | + switch r := recover(); r { | ||
| 154 | + default: | ||
| 155 | + panic(r) | ||
| 156 | + case nil: | ||
| 157 | + // ok | ||
| 158 | + case ErrInternalError: | ||
| 159 | + err = &Error{Code: ErrInternalError, Expr: s} | ||
| 160 | + } | ||
| 161 | + }() | ||
| 162 | + | ||
| 163 | if flags&Literal != 0 { | ||
| 164 | // Trivial parser for literal string. | ||
| 165 | if err := checkUTF8(s); err != nil { | ||
| 166 | @@ -710,7 +779,6 @@ func Parse(s string, flags Flags) (*Regexp, error) { | ||
| 167 | // Otherwise, must do real work. | ||
| 168 | var ( | ||
| 169 | p parser | ||
| 170 | - err error | ||
| 171 | c rune | ||
| 172 | op Op | ||
| 173 | lastRepeat string | ||
| 174 | diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go | ||
| 175 | index 5581ba1..1ef6d8a 100644 | ||
| 176 | --- a/src/regexp/syntax/parse_test.go | ||
| 177 | +++ b/src/regexp/syntax/parse_test.go | ||
| 178 | @@ -207,6 +207,11 @@ var parseTests = []parseTest{ | ||
| 179 | // Valid repetitions. | ||
| 180 | {`((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}))`, ``}, | ||
| 181 | {`((((((((((x{1}){2}){2}){2}){2}){2}){2}){2}){2}){2})`, ``}, | ||
| 182 | + | ||
| 183 | + // Valid nesting. | ||
| 184 | + {strings.Repeat("(", 999) + strings.Repeat(")", 999), ``}, | ||
| 185 | + {strings.Repeat("(?:", 999) + strings.Repeat(")*", 999), ``}, | ||
| 186 | + {"(" + strings.Repeat("|", 12345) + ")", ``}, // not nested at all | ||
| 187 | } | ||
| 188 | |||
| 189 | const testFlags = MatchNL | PerlX | UnicodeGroups | ||
| 190 | @@ -482,6 +487,8 @@ var invalidRegexps = []string{ | ||
| 191 | `a{100000}`, | ||
| 192 | `a{100000,}`, | ||
| 193 | "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", | ||
| 194 | + strings.Repeat("(", 1000) + strings.Repeat(")", 1000), | ||
| 195 | + strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000), | ||
| 196 | `\Q\E*`, | ||
| 197 | } | ||
| 198 | |||
