diff options
| -rw-r--r-- | meta/recipes-devtools/go/go-1.17.13.inc | 3 | ||||
| -rw-r--r-- | meta/recipes-devtools/go/go-1.20/CVE-2023-39319.patch | 254 |
2 files changed, 256 insertions, 1 deletions
diff --git a/meta/recipes-devtools/go/go-1.17.13.inc b/meta/recipes-devtools/go/go-1.17.13.inc index 91dd886cd0..c753a26a7e 100644 --- a/meta/recipes-devtools/go/go-1.17.13.inc +++ b/meta/recipes-devtools/go/go-1.17.13.inc | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | require go-common.inc | 1 | require go-common.inc |
| 2 | 2 | ||
| 3 | FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/go-1.21:${FILE_DIRNAME}/go-1.19:${FILE_DIRNAME}/go-1.18:" | 3 | FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/go-1.21:${FILE_DIRNAME}/go-1.20:${FILE_DIRNAME}/go-1.19:${FILE_DIRNAME}/go-1.18:" |
| 4 | 4 | ||
| 5 | LIC_FILES_CHKSUM = "file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" | 5 | LIC_FILES_CHKSUM = "file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" |
| 6 | 6 | ||
| @@ -43,6 +43,7 @@ SRC_URI += "\ | |||
| 43 | file://CVE-2023-24531_1.patch \ | 43 | file://CVE-2023-24531_1.patch \ |
| 44 | file://CVE-2023-24531_2.patch \ | 44 | file://CVE-2023-24531_2.patch \ |
| 45 | file://CVE-2023-29409.patch \ | 45 | file://CVE-2023-29409.patch \ |
| 46 | file://CVE-2023-39319.patch \ | ||
| 46 | " | 47 | " |
| 47 | SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" | 48 | SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" |
| 48 | 49 | ||
diff --git a/meta/recipes-devtools/go/go-1.20/CVE-2023-39319.patch b/meta/recipes-devtools/go/go-1.20/CVE-2023-39319.patch new file mode 100644 index 0000000000..1554aa975c --- /dev/null +++ b/meta/recipes-devtools/go/go-1.20/CVE-2023-39319.patch | |||
| @@ -0,0 +1,254 @@ | |||
| 1 | From 2070531d2f53df88e312edace6c8dfc9686ab2f5 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Roland Shoemaker <bracewell@google.com> | ||
| 3 | Date: Thu Aug 3 12:28:28 2023 -0700 | ||
| 4 | Subject: [PATCH] html/template: properly handle special tags within the script | ||
| 5 | context | ||
| 6 | |||
| 7 | The HTML specification has incredibly complex rules for how to handle | ||
| 8 | "<!--", "<script", and "</script" when they appear within literals in | ||
| 9 | the script context. Rather than attempting to apply these restrictions | ||
| 10 | (which require a significantly more complex state machine) we apply | ||
| 11 | the workaround suggested in section 4.12.1.3 of the HTML specification [1]. | ||
| 12 | |||
| 13 | More precisely, when "<!--", "<script", and "</script" appear within | ||
| 14 | literals (strings and regular expressions, ignoring comments since we | ||
| 15 | already elide their content) we replace the "<" with "\x3C". This avoids | ||
| 16 | the unintuitive behavior that using these tags within literals can cause, | ||
| 17 | by simply preventing the rendered content from triggering it. This may | ||
| 18 | break some correct usages of these tags, but on balance is more likely | ||
| 19 | to prevent XSS attacks where users are unknowingly either closing or not | ||
| 20 | closing the script blocks where they think they are. | ||
| 21 | |||
| 22 | Thanks to Takeshi Kaneko (GMO Cybersecurity by Ierae, Inc.) for | ||
| 23 | reporting this issue. | ||
| 24 | |||
| 25 | Fixes #62197 | ||
| 26 | Fixes #62397 | ||
| 27 | Fixes CVE-2023-39319 | ||
| 28 | |||
| 29 | [1] https://html.spec.whatwg.org/#restrictions-for-contents-of-script-elements | ||
| 30 | |||
| 31 | Change-Id: Iab57b0532694827e3eddf57a7497ba1fab1746dc | ||
| 32 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1976594 | ||
| 33 | Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> | ||
| 34 | Reviewed-by: Tatiana Bradley <tatianabradley@google.com> | ||
| 35 | Reviewed-by: Damien Neil <dneil@google.com> | ||
| 36 | Run-TryBot: Roland Shoemaker <bracewell@google.com> | ||
| 37 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2014621 | ||
| 38 | Reviewed-on: https://go-review.googlesource.com/c/go/+/526099 | ||
| 39 | TryBot-Result: Gopher Robot <gobot@golang.org> | ||
| 40 | Run-TryBot: Cherry Mui <cherryyz@google.com> | ||
| 41 | |||
| 42 | CVE: CVE-2023-39319 | ||
| 43 | |||
| 44 | Upstream-Status: Backport [https://github.com/golang/go/commit/2070531d2f53df88e312edace6c8dfc9686ab2f5] | ||
| 45 | |||
| 46 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
| 47 | --- | ||
| 48 | src/go/build/deps_test.go | 6 ++-- | ||
| 49 | src/html/template/context.go | 14 ++++++++++ | ||
| 50 | src/html/template/escape.go | 26 ++++++++++++++++++ | ||
| 51 | src/html/template/escape_test.go | 47 +++++++++++++++++++++++++++++++- | ||
| 52 | src/html/template/transition.go | 15 ++++++++++ | ||
| 53 | 5 files changed, 104 insertions(+), 4 deletions(-) | ||
| 54 | |||
| 55 | diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go | ||
| 56 | index dc3bb8c..359a00a 100644 | ||
| 57 | --- a/src/go/build/deps_test.go | ||
| 58 | +++ b/src/go/build/deps_test.go | ||
| 59 | @@ -255,15 +255,15 @@ var depsRules = ` | ||
| 60 | < text/template | ||
| 61 | < internal/lazytemplate; | ||
| 62 | |||
| 63 | - encoding/json, html, text/template | ||
| 64 | - < html/template; | ||
| 65 | - | ||
| 66 | # regexp | ||
| 67 | FMT | ||
| 68 | < regexp/syntax | ||
| 69 | < regexp | ||
| 70 | < internal/lazyregexp; | ||
| 71 | |||
| 72 | + encoding/json, html, text/template, regexp | ||
| 73 | + < html/template; | ||
| 74 | + | ||
| 75 | # suffix array | ||
| 76 | encoding/binary, regexp | ||
| 77 | < index/suffixarray; | ||
| 78 | diff --git a/src/html/template/context.go b/src/html/template/context.go | ||
| 79 | index 0b65313..f5f44a1 100644 | ||
| 80 | --- a/src/html/template/context.go | ||
| 81 | +++ b/src/html/template/context.go | ||
| 82 | @@ -164,6 +164,20 @@ func isInTag(s state) bool { | ||
| 83 | return false | ||
| 84 | } | ||
| 85 | |||
| 86 | +// isInScriptLiteral returns true if s is one of the literal states within a | ||
| 87 | +// <script> tag, and as such occurances of "<!--", "<script", and "</script" | ||
| 88 | +// need to be treated specially. | ||
| 89 | +func isInScriptLiteral(s state) bool { | ||
| 90 | + // Ignore the comment states (stateJSBlockCmt, stateJSLineCmt, | ||
| 91 | + // stateJSHTMLOpenCmt, stateJSHTMLCloseCmt) because their content is already | ||
| 92 | + // omitted from the output. | ||
| 93 | + switch s { | ||
| 94 | + case stateJSDqStr, stateJSSqStr, stateJSBqStr, stateJSRegexp: | ||
| 95 | + return true | ||
| 96 | + } | ||
| 97 | + return false | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | // delim is the delimiter that will end the current HTML attribute. | ||
| 101 | type delim uint8 | ||
| 102 | |||
| 103 | diff --git a/src/html/template/escape.go b/src/html/template/escape.go | ||
| 104 | index bdccc65..1747ec9 100644 | ||
| 105 | --- a/src/html/template/escape.go | ||
| 106 | +++ b/src/html/template/escape.go | ||
| 107 | @@ -10,6 +10,7 @@ import ( | ||
| 108 | "html" | ||
| 109 | "internal/godebug" | ||
| 110 | "io" | ||
| 111 | + "regexp" | ||
| 112 | "text/template" | ||
| 113 | "text/template/parse" | ||
| 114 | ) | ||
| 115 | @@ -652,6 +653,26 @@ var delimEnds = [...]string{ | ||
| 116 | delimSpaceOrTagEnd: " \t\n\f\r>", | ||
| 117 | } | ||
| 118 | |||
| 119 | +var ( | ||
| 120 | + // Per WHATWG HTML specification, section 4.12.1.3, there are extremely | ||
| 121 | + // complicated rules for how to handle the set of opening tags <!--, | ||
| 122 | + // <script, and </script when they appear in JS literals (i.e. strings, | ||
| 123 | + // regexs, and comments). The specification suggests a simple solution, | ||
| 124 | + // rather than implementing the arcane ABNF, which involves simply escaping | ||
| 125 | + // the opening bracket with \x3C. We use the below regex for this, since it | ||
| 126 | + // makes doing the case-insensitive find-replace much simpler. | ||
| 127 | + specialScriptTagRE = regexp.MustCompile("(?i)<(script|/script|!--)") | ||
| 128 | + specialScriptTagReplacement = []byte("\\x3C$1") | ||
| 129 | +) | ||
| 130 | + | ||
| 131 | +func containsSpecialScriptTag(s []byte) bool { | ||
| 132 | + return specialScriptTagRE.Match(s) | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | +func escapeSpecialScriptTags(s []byte) []byte { | ||
| 136 | + return specialScriptTagRE.ReplaceAll(s, specialScriptTagReplacement) | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | var doctypeBytes = []byte("<!DOCTYPE") | ||
| 140 | |||
| 141 | // escapeText escapes a text template node. | ||
| 142 | @@ -707,6 +728,11 @@ func (e *escaper) escapeText(c context, n *parse.TextNode) context { | ||
| 143 | b.Write(s[written:cs]) | ||
| 144 | written = i1 | ||
| 145 | } | ||
| 146 | + if isInScriptLiteral(c.state) && containsSpecialScriptTag(s[i:i1]) { | ||
| 147 | + b.Write(s[written:i]) | ||
| 148 | + b.Write(escapeSpecialScriptTags(s[i:i1])) | ||
| 149 | + written = i1 | ||
| 150 | + } | ||
| 151 | if i == i1 && c.state == c1.state { | ||
| 152 | panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:])) | ||
| 153 | } | ||
| 154 | diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go | ||
| 155 | index 4f48afe..7853daa 100644 | ||
| 156 | --- a/src/html/template/escape_test.go | ||
| 157 | +++ b/src/html/template/escape_test.go | ||
| 158 | @@ -503,6 +503,21 @@ func TestEscape(t *testing.T) { | ||
| 159 | "<script>var a/*b*///c\nd</script>", | ||
| 160 | "<script>var a \nd</script>", | ||
| 161 | }, | ||
| 162 | + { | ||
| 163 | + "Special tags in <script> string literals", | ||
| 164 | + `<script>var a = "asd < 123 <!-- 456 < fgh <script jkl < 789 </script"</script>`, | ||
| 165 | + `<script>var a = "asd < 123 \x3C!-- 456 < fgh \x3Cscript jkl < 789 \x3C/script"</script>`, | ||
| 166 | + }, | ||
| 167 | + { | ||
| 168 | + "Special tags in <script> string literals (mixed case)", | ||
| 169 | + `<script>var a = "<!-- <ScripT </ScripT"</script>`, | ||
| 170 | + `<script>var a = "\x3C!-- \x3CScripT \x3C/ScripT"</script>`, | ||
| 171 | + }, | ||
| 172 | + { | ||
| 173 | + "Special tags in <script> regex literals (mixed case)", | ||
| 174 | + `<script>var a = /<!-- <ScripT </ScripT/</script>`, | ||
| 175 | + `<script>var a = /\x3C!-- \x3CScripT \x3C/ScripT/</script>`, | ||
| 176 | + }, | ||
| 177 | { | ||
| 178 | "CSS comments", | ||
| 179 | "<style>p// paragraph\n" + | ||
| 180 | @@ -1491,8 +1506,38 @@ func TestEscapeText(t *testing.T) { | ||
| 181 | context{state: stateJS, element: elementScript}, | ||
| 182 | }, | ||
| 183 | { | ||
| 184 | + // <script and </script tags are escaped, so </script> should not | ||
| 185 | + // cause us to exit the JS state. | ||
| 186 | `<script>document.write("<script>alert(1)</script>");`, | ||
| 187 | - context{state: stateText}, | ||
| 188 | + context{state: stateJS, element: elementScript}, | ||
| 189 | + }, | ||
| 190 | + { | ||
| 191 | + `<script>document.write("<script>`, | ||
| 192 | + context{state: stateJSDqStr, element: elementScript}, | ||
| 193 | + }, | ||
| 194 | + { | ||
| 195 | + `<script>document.write("<script>alert(1)</script>`, | ||
| 196 | + context{state: stateJSDqStr, element: elementScript}, | ||
| 197 | + }, | ||
| 198 | + { | ||
| 199 | + `<script>document.write("<script>alert(1)<!--`, | ||
| 200 | + context{state: stateJSDqStr, element: elementScript}, | ||
| 201 | + }, | ||
| 202 | + { | ||
| 203 | + `<script>document.write("<script>alert(1)</Script>");`, | ||
| 204 | + context{state: stateJS, element: elementScript}, | ||
| 205 | + }, | ||
| 206 | + { | ||
| 207 | + `<script>document.write("<!--");`, | ||
| 208 | + context{state: stateJS, element: elementScript}, | ||
| 209 | + }, | ||
| 210 | + { | ||
| 211 | + `<script>let a = /</script`, | ||
| 212 | + context{state: stateJSRegexp, element: elementScript}, | ||
| 213 | + }, | ||
| 214 | + { | ||
| 215 | + `<script>let a = /</script/`, | ||
| 216 | + context{state: stateJS, element: elementScript, jsCtx: jsCtxDivOp}, | ||
| 217 | }, | ||
| 218 | { | ||
| 219 | `<script type="text/template">`, | ||
| 220 | diff --git a/src/html/template/transition.go b/src/html/template/transition.go | ||
| 221 | index 92eb351..e2660cc 100644 | ||
| 222 | --- a/src/html/template/transition.go | ||
| 223 | +++ b/src/html/template/transition.go | ||
| 224 | @@ -212,6 +212,11 @@ var ( | ||
| 225 | // element states. | ||
| 226 | func tSpecialTagEnd(c context, s []byte) (context, int) { | ||
| 227 | if c.element != elementNone { | ||
| 228 | + // script end tags ("</script") within script literals are ignored, so that | ||
| 229 | + // we can properly escape them. | ||
| 230 | + if c.element == elementScript && (isInScriptLiteral(c.state) || isComment(c.state)) { | ||
| 231 | + return c, len(s) | ||
| 232 | + } | ||
| 233 | if i := indexTagEnd(s, specialTagEndMarkers[c.element]); i != -1 { | ||
| 234 | return context{}, i | ||
| 235 | } | ||
| 236 | @@ -331,6 +336,16 @@ func tJSDelimited(c context, s []byte) (context, int) { | ||
| 237 | inCharset = true | ||
| 238 | case ']': | ||
| 239 | inCharset = false | ||
| 240 | + case '/': | ||
| 241 | + // If "</script" appears in a regex literal, the '/' should not | ||
| 242 | + // close the regex literal, and it will later be escaped to | ||
| 243 | + // "\x3C/script" in escapeText. | ||
| 244 | + if i > 0 && i+7 <= len(s) && bytes.Compare(bytes.ToLower(s[i-1:i+7]), []byte("</script")) == 0 { | ||
| 245 | + i++ | ||
| 246 | + } else if !inCharset { | ||
| 247 | + c.state, c.jsCtx = stateJS, jsCtxDivOp | ||
| 248 | + return c, i + 1 | ||
| 249 | + } | ||
| 250 | default: | ||
| 251 | // end delimiter | ||
| 252 | if !inCharset { | ||
| 253 | -- | ||
| 254 | 2.40.0 | ||
