diff options
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch')
-rw-r--r-- | meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch | 635 |
1 files changed, 635 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch new file mode 100644 index 0000000000..f200c41e16 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch | |||
@@ -0,0 +1,635 @@ | |||
1 | From 6fc21505614f36178df0dad7034b6b8e3f7588d5 Mon Sep 17 00:00:00 2001 | ||
2 | From: empijei <robclap8@gmail.com> | ||
3 | Date: Fri, 27 Mar 2020 19:27:55 +0100 | ||
4 | Subject: [PATCH 2/6] html/template,text/template: switch to Unicode escapes | ||
5 | for JSON compatibility | ||
6 | MIME-Version: 1.0 | ||
7 | Content-Type: text/plain; charset=UTF-8 | ||
8 | Content-Transfer-Encoding: 8bit | ||
9 | |||
10 | The existing implementation is not compatible with JSON | ||
11 | escape as it uses hex escaping. | ||
12 | Unicode escape, instead, is valid for both JSON and JS. | ||
13 | This fix avoids creating a separate escaping context for | ||
14 | scripts of type "application/ld+json" and it is more | ||
15 | future-proof in case more JSON+JS contexts get added | ||
16 | to the platform (e.g. import maps). | ||
17 | |||
18 | Fixes #33671 | ||
19 | Fixes #37634 | ||
20 | |||
21 | Change-Id: Id6f6524b4abc52e81d9d744d46bbe5bf2e081543 | ||
22 | Reviewed-on: https://go-review.googlesource.com/c/go/+/226097 | ||
23 | Reviewed-by: Carl Johnson <me@carlmjohnson.net> | ||
24 | Reviewed-by: Daniel Martí <mvdan@mvdan.cc> | ||
25 | Run-TryBot: Daniel Martí <mvdan@mvdan.cc> | ||
26 | TryBot-Result: Gobot Gobot <gobot@golang.org> | ||
27 | |||
28 | Dependency Patch #2 | ||
29 | |||
30 | Upstream-Status: Backport from https://github.com/golang/go/commit/d4d298040d072ddacea0e0d6b55fb148fff18070 | ||
31 | CVE: CVE-2023-24538 | ||
32 | Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> | ||
33 | --- | ||
34 | src/html/template/content_test.go | 70 +++++++++++++++++++------------------- | ||
35 | src/html/template/escape_test.go | 6 ++-- | ||
36 | src/html/template/example_test.go | 6 ++-- | ||
37 | src/html/template/js.go | 70 +++++++++++++++++++++++--------------- | ||
38 | src/html/template/js_test.go | 68 ++++++++++++++++++------------------ | ||
39 | src/html/template/template_test.go | 39 +++++++++++++++++++++ | ||
40 | src/text/template/exec_test.go | 6 ++-- | ||
41 | src/text/template/funcs.go | 8 ++--- | ||
42 | 8 files changed, 163 insertions(+), 110 deletions(-) | ||
43 | |||
44 | diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go | ||
45 | index 72d56f5..bd86527 100644 | ||
46 | --- a/src/html/template/content_test.go | ||
47 | +++ b/src/html/template/content_test.go | ||
48 | @@ -18,7 +18,7 @@ func TestTypedContent(t *testing.T) { | ||
49 | HTML(`Hello, <b>World</b> &tc!`), | ||
50 | HTMLAttr(` dir="ltr"`), | ||
51 | JS(`c && alert("Hello, World!");`), | ||
52 | - JSStr(`Hello, World & O'Reilly\x21`), | ||
53 | + JSStr(`Hello, World & O'Reilly\u0021`), | ||
54 | URL(`greeting=H%69,&addressee=(World)`), | ||
55 | Srcset(`greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`), | ||
56 | URL(`,foo/,`), | ||
57 | @@ -70,7 +70,7 @@ func TestTypedContent(t *testing.T) { | ||
58 | `Hello, <b>World</b> &tc!`, | ||
59 | ` dir="ltr"`, | ||
60 | `c && alert("Hello, World!");`, | ||
61 | - `Hello, World & O'Reilly\x21`, | ||
62 | + `Hello, World & O'Reilly\u0021`, | ||
63 | `greeting=H%69,&addressee=(World)`, | ||
64 | `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, | ||
65 | `,foo/,`, | ||
66 | @@ -100,7 +100,7 @@ func TestTypedContent(t *testing.T) { | ||
67 | `Hello, World &tc!`, | ||
68 | ` dir="ltr"`, | ||
69 | `c && alert("Hello, World!");`, | ||
70 | - `Hello, World & O'Reilly\x21`, | ||
71 | + `Hello, World & O'Reilly\u0021`, | ||
72 | `greeting=H%69,&addressee=(World)`, | ||
73 | `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, | ||
74 | `,foo/,`, | ||
75 | @@ -115,7 +115,7 @@ func TestTypedContent(t *testing.T) { | ||
76 | `Hello, World &tc!`, | ||
77 | ` dir="ltr"`, | ||
78 | `c && alert("Hello, World!");`, | ||
79 | - `Hello, World & O'Reilly\x21`, | ||
80 | + `Hello, World & O'Reilly\u0021`, | ||
81 | `greeting=H%69,&addressee=(World)`, | ||
82 | `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, | ||
83 | `,foo/,`, | ||
84 | @@ -130,7 +130,7 @@ func TestTypedContent(t *testing.T) { | ||
85 | `Hello, <b>World</b> &tc!`, | ||
86 | ` dir="ltr"`, | ||
87 | `c && alert("Hello, World!");`, | ||
88 | - `Hello, World & O'Reilly\x21`, | ||
89 | + `Hello, World & O'Reilly\u0021`, | ||
90 | `greeting=H%69,&addressee=(World)`, | ||
91 | `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, | ||
92 | `,foo/,`, | ||
93 | @@ -146,7 +146,7 @@ func TestTypedContent(t *testing.T) { | ||
94 | // Not escaped. | ||
95 | `c && alert("Hello, World!");`, | ||
96 | // Escape sequence not over-escaped. | ||
97 | - `"Hello, World & O'Reilly\x21"`, | ||
98 | + `"Hello, World & O'Reilly\u0021"`, | ||
99 | `"greeting=H%69,\u0026addressee=(World)"`, | ||
100 | `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, | ||
101 | `",foo/,"`, | ||
102 | @@ -162,7 +162,7 @@ func TestTypedContent(t *testing.T) { | ||
103 | // Not JS escaped but HTML escaped. | ||
104 | `c && alert("Hello, World!");`, | ||
105 | // Escape sequence not over-escaped. | ||
106 | - `"Hello, World & O'Reilly\x21"`, | ||
107 | + `"Hello, World & O'Reilly\u0021"`, | ||
108 | `"greeting=H%69,\u0026addressee=(World)"`, | ||
109 | `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, | ||
110 | `",foo/,"`, | ||
111 | @@ -171,30 +171,30 @@ func TestTypedContent(t *testing.T) { | ||
112 | { | ||
113 | `<script>alert("{{.}}")</script>`, | ||
114 | []string{ | ||
115 | - `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, | ||
116 | - `a[href =~ \x22\/\/example.com\x22]#foo`, | ||
117 | - `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, | ||
118 | - ` dir=\x22ltr\x22`, | ||
119 | - `c \x26\x26 alert(\x22Hello, World!\x22);`, | ||
120 | + `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, | ||
121 | + `a[href =~ \u0022\/\/example.com\u0022]#foo`, | ||
122 | + `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, | ||
123 | + ` dir=\u0022ltr\u0022`, | ||
124 | + `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, | ||
125 | // Escape sequence not over-escaped. | ||
126 | - `Hello, World \x26 O\x27Reilly\x21`, | ||
127 | - `greeting=H%69,\x26addressee=(World)`, | ||
128 | - `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, | ||
129 | + `Hello, World \u0026 O\u0027Reilly\u0021`, | ||
130 | + `greeting=H%69,\u0026addressee=(World)`, | ||
131 | + `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, | ||
132 | `,foo\/,`, | ||
133 | }, | ||
134 | }, | ||
135 | { | ||
136 | `<script type="text/javascript">alert("{{.}}")</script>`, | ||
137 | []string{ | ||
138 | - `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, | ||
139 | - `a[href =~ \x22\/\/example.com\x22]#foo`, | ||
140 | - `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, | ||
141 | - ` dir=\x22ltr\x22`, | ||
142 | - `c \x26\x26 alert(\x22Hello, World!\x22);`, | ||
143 | + `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, | ||
144 | + `a[href =~ \u0022\/\/example.com\u0022]#foo`, | ||
145 | + `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, | ||
146 | + ` dir=\u0022ltr\u0022`, | ||
147 | + `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, | ||
148 | // Escape sequence not over-escaped. | ||
149 | - `Hello, World \x26 O\x27Reilly\x21`, | ||
150 | - `greeting=H%69,\x26addressee=(World)`, | ||
151 | - `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, | ||
152 | + `Hello, World \u0026 O\u0027Reilly\u0021`, | ||
153 | + `greeting=H%69,\u0026addressee=(World)`, | ||
154 | + `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, | ||
155 | `,foo\/,`, | ||
156 | }, | ||
157 | }, | ||
158 | @@ -208,7 +208,7 @@ func TestTypedContent(t *testing.T) { | ||
159 | // Not escaped. | ||
160 | `c && alert("Hello, World!");`, | ||
161 | // Escape sequence not over-escaped. | ||
162 | - `"Hello, World & O'Reilly\x21"`, | ||
163 | + `"Hello, World & O'Reilly\u0021"`, | ||
164 | `"greeting=H%69,\u0026addressee=(World)"`, | ||
165 | `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, | ||
166 | `",foo/,"`, | ||
167 | @@ -224,7 +224,7 @@ func TestTypedContent(t *testing.T) { | ||
168 | `Hello, <b>World</b> &tc!`, | ||
169 | ` dir="ltr"`, | ||
170 | `c && alert("Hello, World!");`, | ||
171 | - `Hello, World & O'Reilly\x21`, | ||
172 | + `Hello, World & O'Reilly\u0021`, | ||
173 | `greeting=H%69,&addressee=(World)`, | ||
174 | `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, | ||
175 | `,foo/,`, | ||
176 | @@ -233,15 +233,15 @@ func TestTypedContent(t *testing.T) { | ||
177 | { | ||
178 | `<button onclick='alert("{{.}}")'>`, | ||
179 | []string{ | ||
180 | - `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, | ||
181 | - `a[href =~ \x22\/\/example.com\x22]#foo`, | ||
182 | - `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, | ||
183 | - ` dir=\x22ltr\x22`, | ||
184 | - `c \x26\x26 alert(\x22Hello, World!\x22);`, | ||
185 | + `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, | ||
186 | + `a[href =~ \u0022\/\/example.com\u0022]#foo`, | ||
187 | + `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, | ||
188 | + ` dir=\u0022ltr\u0022`, | ||
189 | + `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, | ||
190 | // Escape sequence not over-escaped. | ||
191 | - `Hello, World \x26 O\x27Reilly\x21`, | ||
192 | - `greeting=H%69,\x26addressee=(World)`, | ||
193 | - `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, | ||
194 | + `Hello, World \u0026 O\u0027Reilly\u0021`, | ||
195 | + `greeting=H%69,\u0026addressee=(World)`, | ||
196 | + `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, | ||
197 | `,foo\/,`, | ||
198 | }, | ||
199 | }, | ||
200 | @@ -253,7 +253,7 @@ func TestTypedContent(t *testing.T) { | ||
201 | `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`, | ||
202 | `%20dir%3d%22ltr%22`, | ||
203 | `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`, | ||
204 | - `Hello%2c%20World%20%26%20O%27Reilly%5cx21`, | ||
205 | + `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`, | ||
206 | // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done. | ||
207 | `greeting=H%69,&addressee=%28World%29`, | ||
208 | `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`, | ||
209 | @@ -268,7 +268,7 @@ func TestTypedContent(t *testing.T) { | ||
210 | `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`, | ||
211 | `%20dir%3d%22ltr%22`, | ||
212 | `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`, | ||
213 | - `Hello%2c%20World%20%26%20O%27Reilly%5cx21`, | ||
214 | + `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`, | ||
215 | // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done. | ||
216 | `greeting=H%69,&addressee=%28World%29`, | ||
217 | `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`, | ||
218 | diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go | ||
219 | index e72a9ba..c709660 100644 | ||
220 | --- a/src/html/template/escape_test.go | ||
221 | +++ b/src/html/template/escape_test.go | ||
222 | @@ -238,7 +238,7 @@ func TestEscape(t *testing.T) { | ||
223 | { | ||
224 | "jsStr", | ||
225 | "<button onclick='alert("{{.H}}")'>", | ||
226 | - `<button onclick='alert("\x3cHello\x3e")'>`, | ||
227 | + `<button onclick='alert("\u003cHello\u003e")'>`, | ||
228 | }, | ||
229 | { | ||
230 | "badMarshaler", | ||
231 | @@ -259,7 +259,7 @@ func TestEscape(t *testing.T) { | ||
232 | { | ||
233 | "jsRe", | ||
234 | `<button onclick='alert(/{{"foo+bar"}}/.test(""))'>`, | ||
235 | - `<button onclick='alert(/foo\x2bbar/.test(""))'>`, | ||
236 | + `<button onclick='alert(/foo\u002bbar/.test(""))'>`, | ||
237 | }, | ||
238 | { | ||
239 | "jsReBlank", | ||
240 | @@ -825,7 +825,7 @@ func TestEscapeSet(t *testing.T) { | ||
241 | "main": `<button onclick="title='{{template "helper"}}'; ...">{{template "helper"}}</button>`, | ||
242 | "helper": `{{11}} of {{"<100>"}}`, | ||
243 | }, | ||
244 | - `<button onclick="title='11 of \x3c100\x3e'; ...">11 of <100></button>`, | ||
245 | + `<button onclick="title='11 of \u003c100\u003e'; ...">11 of <100></button>`, | ||
246 | }, | ||
247 | // A non-recursive template that ends in a different context. | ||
248 | // helper starts in jsCtxRegexp and ends in jsCtxDivOp. | ||
249 | diff --git a/src/html/template/example_test.go b/src/html/template/example_test.go | ||
250 | index 9d965f1..6cf936f 100644 | ||
251 | --- a/src/html/template/example_test.go | ||
252 | +++ b/src/html/template/example_test.go | ||
253 | @@ -116,9 +116,9 @@ func Example_escape() { | ||
254 | // "Fran & Freddie's Diner" <tasty@example.com> | ||
255 | // "Fran & Freddie's Diner" <tasty@example.com> | ||
256 | // "Fran & Freddie's Diner"32<tasty@example.com> | ||
257 | - // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E | ||
258 | - // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E | ||
259 | - // \"Fran \x26 Freddie\'s Diner\"32\x3Ctasty@example.com\x3E | ||
260 | + // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E | ||
261 | + // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E | ||
262 | + // \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E | ||
263 | // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E | ||
264 | |||
265 | } | ||
266 | diff --git a/src/html/template/js.go b/src/html/template/js.go | ||
267 | index 0e91458..ea9c183 100644 | ||
268 | --- a/src/html/template/js.go | ||
269 | +++ b/src/html/template/js.go | ||
270 | @@ -163,7 +163,6 @@ func jsValEscaper(args ...interface{}) string { | ||
271 | } | ||
272 | // TODO: detect cycles before calling Marshal which loops infinitely on | ||
273 | // cyclic data. This may be an unacceptable DoS risk. | ||
274 | - | ||
275 | b, err := json.Marshal(a) | ||
276 | if err != nil { | ||
277 | // Put a space before comment so that if it is flush against | ||
278 | @@ -178,8 +177,8 @@ func jsValEscaper(args ...interface{}) string { | ||
279 | // TODO: maybe post-process output to prevent it from containing | ||
280 | // "<!--", "-->", "<![CDATA[", "]]>", or "</script" | ||
281 | // in case custom marshalers produce output containing those. | ||
282 | - | ||
283 | - // TODO: Maybe abbreviate \u00ab to \xab to produce more compact output. | ||
284 | + // Note: Do not use \x escaping to save bytes because it is not JSON compatible and this escaper | ||
285 | + // supports ld+json content-type. | ||
286 | if len(b) == 0 { | ||
287 | // In, `x=y/{{.}}*z` a json.Marshaler that produces "" should | ||
288 | // not cause the output `x=y/*z`. | ||
289 | @@ -260,6 +259,8 @@ func replace(s string, replacementTable []string) string { | ||
290 | r, w = utf8.DecodeRuneInString(s[i:]) | ||
291 | var repl string | ||
292 | switch { | ||
293 | + case int(r) < len(lowUnicodeReplacementTable): | ||
294 | + repl = lowUnicodeReplacementTable[r] | ||
295 | case int(r) < len(replacementTable) && replacementTable[r] != "": | ||
296 | repl = replacementTable[r] | ||
297 | case r == '\u2028': | ||
298 | @@ -283,67 +284,80 @@ func replace(s string, replacementTable []string) string { | ||
299 | return b.String() | ||
300 | } | ||
301 | |||
302 | +var lowUnicodeReplacementTable = []string{ | ||
303 | + 0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`, | ||
304 | + '\a': `\u0007`, | ||
305 | + '\b': `\u0008`, | ||
306 | + '\t': `\t`, | ||
307 | + '\n': `\n`, | ||
308 | + '\v': `\u000b`, // "\v" == "v" on IE 6. | ||
309 | + '\f': `\f`, | ||
310 | + '\r': `\r`, | ||
311 | + 0xe: `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`, | ||
312 | + 0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`, | ||
313 | + 0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`, | ||
314 | +} | ||
315 | + | ||
316 | var jsStrReplacementTable = []string{ | ||
317 | - 0: `\0`, | ||
318 | + 0: `\u0000`, | ||
319 | '\t': `\t`, | ||
320 | '\n': `\n`, | ||
321 | - '\v': `\x0b`, // "\v" == "v" on IE 6. | ||
322 | + '\v': `\u000b`, // "\v" == "v" on IE 6. | ||
323 | '\f': `\f`, | ||
324 | '\r': `\r`, | ||
325 | // Encode HTML specials as hex so the output can be embedded | ||
326 | // in HTML attributes without further encoding. | ||
327 | - '"': `\x22`, | ||
328 | - '&': `\x26`, | ||
329 | - '\'': `\x27`, | ||
330 | - '+': `\x2b`, | ||
331 | + '"': `\u0022`, | ||
332 | + '&': `\u0026`, | ||
333 | + '\'': `\u0027`, | ||
334 | + '+': `\u002b`, | ||
335 | '/': `\/`, | ||
336 | - '<': `\x3c`, | ||
337 | - '>': `\x3e`, | ||
338 | + '<': `\u003c`, | ||
339 | + '>': `\u003e`, | ||
340 | '\\': `\\`, | ||
341 | } | ||
342 | |||
343 | // jsStrNormReplacementTable is like jsStrReplacementTable but does not | ||
344 | // overencode existing escapes since this table has no entry for `\`. | ||
345 | var jsStrNormReplacementTable = []string{ | ||
346 | - 0: `\0`, | ||
347 | + 0: `\u0000`, | ||
348 | '\t': `\t`, | ||
349 | '\n': `\n`, | ||
350 | - '\v': `\x0b`, // "\v" == "v" on IE 6. | ||
351 | + '\v': `\u000b`, // "\v" == "v" on IE 6. | ||
352 | '\f': `\f`, | ||
353 | '\r': `\r`, | ||
354 | // Encode HTML specials as hex so the output can be embedded | ||
355 | // in HTML attributes without further encoding. | ||
356 | - '"': `\x22`, | ||
357 | - '&': `\x26`, | ||
358 | - '\'': `\x27`, | ||
359 | - '+': `\x2b`, | ||
360 | + '"': `\u0022`, | ||
361 | + '&': `\u0026`, | ||
362 | + '\'': `\u0027`, | ||
363 | + '+': `\u002b`, | ||
364 | '/': `\/`, | ||
365 | - '<': `\x3c`, | ||
366 | - '>': `\x3e`, | ||
367 | + '<': `\u003c`, | ||
368 | + '>': `\u003e`, | ||
369 | } | ||
370 | - | ||
371 | var jsRegexpReplacementTable = []string{ | ||
372 | - 0: `\0`, | ||
373 | + 0: `\u0000`, | ||
374 | '\t': `\t`, | ||
375 | '\n': `\n`, | ||
376 | - '\v': `\x0b`, // "\v" == "v" on IE 6. | ||
377 | + '\v': `\u000b`, // "\v" == "v" on IE 6. | ||
378 | '\f': `\f`, | ||
379 | '\r': `\r`, | ||
380 | // Encode HTML specials as hex so the output can be embedded | ||
381 | // in HTML attributes without further encoding. | ||
382 | - '"': `\x22`, | ||
383 | + '"': `\u0022`, | ||
384 | '$': `\$`, | ||
385 | - '&': `\x26`, | ||
386 | - '\'': `\x27`, | ||
387 | + '&': `\u0026`, | ||
388 | + '\'': `\u0027`, | ||
389 | '(': `\(`, | ||
390 | ')': `\)`, | ||
391 | '*': `\*`, | ||
392 | - '+': `\x2b`, | ||
393 | + '+': `\u002b`, | ||
394 | '-': `\-`, | ||
395 | '.': `\.`, | ||
396 | '/': `\/`, | ||
397 | - '<': `\x3c`, | ||
398 | - '>': `\x3e`, | ||
399 | + '<': `\u003c`, | ||
400 | + '>': `\u003e`, | ||
401 | '?': `\?`, | ||
402 | '[': `\[`, | ||
403 | '\\': `\\`, | ||
404 | diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go | ||
405 | index 075adaa..d7ee47b 100644 | ||
406 | --- a/src/html/template/js_test.go | ||
407 | +++ b/src/html/template/js_test.go | ||
408 | @@ -137,7 +137,7 @@ func TestJSValEscaper(t *testing.T) { | ||
409 | {"foo", `"foo"`}, | ||
410 | // Newlines. | ||
411 | {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, | ||
412 | - // "\v" == "v" on IE 6 so use "\x0b" instead. | ||
413 | + // "\v" == "v" on IE 6 so use "\u000b" instead. | ||
414 | {"\t\x0b", `"\t\u000b"`}, | ||
415 | {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`}, | ||
416 | {[]interface{}{}, "[]"}, | ||
417 | @@ -173,7 +173,7 @@ func TestJSStrEscaper(t *testing.T) { | ||
418 | }{ | ||
419 | {"", ``}, | ||
420 | {"foo", `foo`}, | ||
421 | - {"\u0000", `\0`}, | ||
422 | + {"\u0000", `\u0000`}, | ||
423 | {"\t", `\t`}, | ||
424 | {"\n", `\n`}, | ||
425 | {"\r", `\r`}, | ||
426 | @@ -183,14 +183,14 @@ func TestJSStrEscaper(t *testing.T) { | ||
427 | {"\\n", `\\n`}, | ||
428 | {"foo\r\nbar", `foo\r\nbar`}, | ||
429 | // Preserve attribute boundaries. | ||
430 | - {`"`, `\x22`}, | ||
431 | - {`'`, `\x27`}, | ||
432 | + {`"`, `\u0022`}, | ||
433 | + {`'`, `\u0027`}, | ||
434 | // Allow embedding in HTML without further escaping. | ||
435 | - {`&`, `\x26amp;`}, | ||
436 | + {`&`, `\u0026amp;`}, | ||
437 | // Prevent breaking out of text node and element boundaries. | ||
438 | - {"</script>", `\x3c\/script\x3e`}, | ||
439 | - {"<![CDATA[", `\x3c![CDATA[`}, | ||
440 | - {"]]>", `]]\x3e`}, | ||
441 | + {"</script>", `\u003c\/script\u003e`}, | ||
442 | + {"<![CDATA[", `\u003c![CDATA[`}, | ||
443 | + {"]]>", `]]\u003e`}, | ||
444 | // https://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span | ||
445 | // "The text in style, script, title, and textarea elements | ||
446 | // must not have an escaping text span start that is not | ||
447 | @@ -201,11 +201,11 @@ func TestJSStrEscaper(t *testing.T) { | ||
448 | // allow regular text content to be interpreted as script | ||
449 | // allowing script execution via a combination of a JS string | ||
450 | // injection followed by an HTML text injection. | ||
451 | - {"<!--", `\x3c!--`}, | ||
452 | - {"-->", `--\x3e`}, | ||
453 | + {"<!--", `\u003c!--`}, | ||
454 | + {"-->", `--\u003e`}, | ||
455 | // From https://code.google.com/p/doctype/wiki/ArticleUtf7 | ||
456 | {"+ADw-script+AD4-alert(1)+ADw-/script+AD4-", | ||
457 | - `\x2bADw-script\x2bAD4-alert(1)\x2bADw-\/script\x2bAD4-`, | ||
458 | + `\u002bADw-script\u002bAD4-alert(1)\u002bADw-\/script\u002bAD4-`, | ||
459 | }, | ||
460 | // Invalid UTF-8 sequence | ||
461 | {"foo\xA0bar", "foo\xA0bar"}, | ||
462 | @@ -228,7 +228,7 @@ func TestJSRegexpEscaper(t *testing.T) { | ||
463 | }{ | ||
464 | {"", `(?:)`}, | ||
465 | {"foo", `foo`}, | ||
466 | - {"\u0000", `\0`}, | ||
467 | + {"\u0000", `\u0000`}, | ||
468 | {"\t", `\t`}, | ||
469 | {"\n", `\n`}, | ||
470 | {"\r", `\r`}, | ||
471 | @@ -238,19 +238,19 @@ func TestJSRegexpEscaper(t *testing.T) { | ||
472 | {"\\n", `\\n`}, | ||
473 | {"foo\r\nbar", `foo\r\nbar`}, | ||
474 | // Preserve attribute boundaries. | ||
475 | - {`"`, `\x22`}, | ||
476 | - {`'`, `\x27`}, | ||
477 | + {`"`, `\u0022`}, | ||
478 | + {`'`, `\u0027`}, | ||
479 | // Allow embedding in HTML without further escaping. | ||
480 | - {`&`, `\x26amp;`}, | ||
481 | + {`&`, `\u0026amp;`}, | ||
482 | // Prevent breaking out of text node and element boundaries. | ||
483 | - {"</script>", `\x3c\/script\x3e`}, | ||
484 | - {"<![CDATA[", `\x3c!\[CDATA\[`}, | ||
485 | - {"]]>", `\]\]\x3e`}, | ||
486 | + {"</script>", `\u003c\/script\u003e`}, | ||
487 | + {"<![CDATA[", `\u003c!\[CDATA\[`}, | ||
488 | + {"]]>", `\]\]\u003e`}, | ||
489 | // Escaping text spans. | ||
490 | - {"<!--", `\x3c!\-\-`}, | ||
491 | - {"-->", `\-\-\x3e`}, | ||
492 | + {"<!--", `\u003c!\-\-`}, | ||
493 | + {"-->", `\-\-\u003e`}, | ||
494 | {"*", `\*`}, | ||
495 | - {"+", `\x2b`}, | ||
496 | + {"+", `\u002b`}, | ||
497 | {"?", `\?`}, | ||
498 | {"[](){}", `\[\]\(\)\{\}`}, | ||
499 | {"$foo|x.y", `\$foo\|x\.y`}, | ||
500 | @@ -284,27 +284,27 @@ func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) { | ||
501 | { | ||
502 | "jsStrEscaper", | ||
503 | jsStrEscaper, | ||
504 | - "\\0\x01\x02\x03\x04\x05\x06\x07" + | ||
505 | - "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" + | ||
506 | - "\x10\x11\x12\x13\x14\x15\x16\x17" + | ||
507 | - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + | ||
508 | - ` !\x22#$%\x26\x27()*\x2b,-.\/` + | ||
509 | - `0123456789:;\x3c=\x3e?` + | ||
510 | + `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` + | ||
511 | + `\u0008\t\n\u000b\f\r\u000e\u000f` + | ||
512 | + `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` + | ||
513 | + `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` + | ||
514 | + ` !\u0022#$%\u0026\u0027()*\u002b,-.\/` + | ||
515 | + `0123456789:;\u003c=\u003e?` + | ||
516 | `@ABCDEFGHIJKLMNO` + | ||
517 | `PQRSTUVWXYZ[\\]^_` + | ||
518 | "`abcdefghijklmno" + | ||
519 | - "pqrstuvwxyz{|}~\x7f" + | ||
520 | + "pqrstuvwxyz{|}~\u007f" + | ||
521 | "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E", | ||
522 | }, | ||
523 | { | ||
524 | "jsRegexpEscaper", | ||
525 | jsRegexpEscaper, | ||
526 | - "\\0\x01\x02\x03\x04\x05\x06\x07" + | ||
527 | - "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" + | ||
528 | - "\x10\x11\x12\x13\x14\x15\x16\x17" + | ||
529 | - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + | ||
530 | - ` !\x22#\$%\x26\x27\(\)\*\x2b,\-\.\/` + | ||
531 | - `0123456789:;\x3c=\x3e\?` + | ||
532 | + `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` + | ||
533 | + `\u0008\t\n\u000b\f\r\u000e\u000f` + | ||
534 | + `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` + | ||
535 | + `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` + | ||
536 | + ` !\u0022#\$%\u0026\u0027\(\)\*\u002b,\-\.\/` + | ||
537 | + `0123456789:;\u003c=\u003e\?` + | ||
538 | `@ABCDEFGHIJKLMNO` + | ||
539 | `PQRSTUVWXYZ\[\\\]\^_` + | ||
540 | "`abcdefghijklmno" + | ||
541 | diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go | ||
542 | index 13e6ba4..86bd4db 100644 | ||
543 | --- a/src/html/template/template_test.go | ||
544 | +++ b/src/html/template/template_test.go | ||
545 | @@ -6,6 +6,7 @@ package template_test | ||
546 | |||
547 | import ( | ||
548 | "bytes" | ||
549 | + "encoding/json" | ||
550 | . "html/template" | ||
551 | "strings" | ||
552 | "testing" | ||
553 | @@ -121,6 +122,44 @@ func TestNumbers(t *testing.T) { | ||
554 | c.mustExecute(c.root, nil, "12.34 7.5") | ||
555 | } | ||
556 | |||
557 | +func TestStringsInScriptsWithJsonContentTypeAreCorrectlyEscaped(t *testing.T) { | ||
558 | + // See #33671 and #37634 for more context on this. | ||
559 | + tests := []struct{ name, in string }{ | ||
560 | + {"empty", ""}, | ||
561 | + {"invalid", string(rune(-1))}, | ||
562 | + {"null", "\u0000"}, | ||
563 | + {"unit separator", "\u001F"}, | ||
564 | + {"tab", "\t"}, | ||
565 | + {"gt and lt", "<>"}, | ||
566 | + {"quotes", `'"`}, | ||
567 | + {"ASCII letters", "ASCII letters"}, | ||
568 | + {"Unicode", "ʕ⊙ϖ⊙ʔ"}, | ||
569 | + {"Pizza", "P"}, | ||
570 | + } | ||
571 | + const ( | ||
572 | + prefix = `<script type="application/ld+json">` | ||
573 | + suffix = `</script>` | ||
574 | + templ = prefix + `"{{.}}"` + suffix | ||
575 | + ) | ||
576 | + tpl := Must(New("JS string is JSON string").Parse(templ)) | ||
577 | + for _, tt := range tests { | ||
578 | + t.Run(tt.name, func(t *testing.T) { | ||
579 | + var buf bytes.Buffer | ||
580 | + if err := tpl.Execute(&buf, tt.in); err != nil { | ||
581 | + t.Fatalf("Cannot render template: %v", err) | ||
582 | + } | ||
583 | + trimmed := bytes.TrimSuffix(bytes.TrimPrefix(buf.Bytes(), []byte(prefix)), []byte(suffix)) | ||
584 | + var got string | ||
585 | + if err := json.Unmarshal(trimmed, &got); err != nil { | ||
586 | + t.Fatalf("Cannot parse JS string %q as JSON: %v", trimmed[1:len(trimmed)-1], err) | ||
587 | + } | ||
588 | + if got != tt.in { | ||
589 | + t.Errorf("Serialization changed the string value: got %q want %q", got, tt.in) | ||
590 | + } | ||
591 | + }) | ||
592 | + } | ||
593 | +} | ||
594 | + | ||
595 | type testCase struct { | ||
596 | t *testing.T | ||
597 | root *Template | ||
598 | diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go | ||
599 | index 77294ed..b8a809e 100644 | ||
600 | --- a/src/text/template/exec_test.go | ||
601 | +++ b/src/text/template/exec_test.go | ||
602 | @@ -911,9 +911,9 @@ func TestJSEscaping(t *testing.T) { | ||
603 | {`Go "jump" \`, `Go \"jump\" \\`}, | ||
604 | {`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`}, | ||
605 | {"unprintable \uFDFF", `unprintable \uFDFF`}, | ||
606 | - {`<html>`, `\x3Chtml\x3E`}, | ||
607 | - {`no = in attributes`, `no \x3D in attributes`}, | ||
608 | - {`' does not become HTML entity`, `\x26#x27; does not become HTML entity`}, | ||
609 | + {`<html>`, `\u003Chtml\u003E`}, | ||
610 | + {`no = in attributes`, `no \u003D in attributes`}, | ||
611 | + {`' does not become HTML entity`, `\u0026#x27; does not become HTML entity`}, | ||
612 | } | ||
613 | for _, tc := range testCases { | ||
614 | s := JSEscapeString(tc.in) | ||
615 | diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go | ||
616 | index 46125bc..f3de9fb 100644 | ||
617 | --- a/src/text/template/funcs.go | ||
618 | +++ b/src/text/template/funcs.go | ||
619 | @@ -640,10 +640,10 @@ var ( | ||
620 | jsBackslash = []byte(`\\`) | ||
621 | jsApos = []byte(`\'`) | ||
622 | jsQuot = []byte(`\"`) | ||
623 | - jsLt = []byte(`\x3C`) | ||
624 | - jsGt = []byte(`\x3E`) | ||
625 | - jsAmp = []byte(`\x26`) | ||
626 | - jsEq = []byte(`\x3D`) | ||
627 | + jsLt = []byte(`\u003C`) | ||
628 | + jsGt = []byte(`\u003E`) | ||
629 | + jsAmp = []byte(`\u0026`) | ||
630 | + jsEq = []byte(`\u003D`) | ||
631 | ) | ||
632 | |||
633 | // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b. | ||
634 | -- | ||
635 | 2.7.4 | ||