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 | ||