diff options
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2024-24785.patch')
-rw-r--r-- | meta/recipes-devtools/go/go-1.14/CVE-2024-24785.patch | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2024-24785.patch b/meta/recipes-devtools/go/go-1.14/CVE-2024-24785.patch new file mode 100644 index 0000000000..1398a2ca48 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2024-24785.patch | |||
@@ -0,0 +1,197 @@ | |||
1 | From 3643147a29352ca2894fd5d0d2069bc4b4335a7e Mon Sep 17 00:00:00 2001 | ||
2 | From: Roland Shoemaker <roland@golang.org> | ||
3 | Date: Wed, 14 Feb 2024 17:18:36 -0800 | ||
4 | Subject: [PATCH] [release-branch.go1.21] html/template: escape additional | ||
5 | tokens in MarshalJSON errors | ||
6 | |||
7 | Escape "</script" and "<!--" in errors returned from MarshalJSON errors | ||
8 | when attempting to marshal types in script blocks. This prevents any | ||
9 | user controlled content from prematurely terminating the script block. | ||
10 | |||
11 | Updates #65697 | ||
12 | Fixes #65968 | ||
13 | |||
14 | Change-Id: Icf0e26c54ea7d9c1deed0bff11b6506c99ddef1b | ||
15 | Reviewed-on: https://go-review.googlesource.com/c/go/+/564196 | ||
16 | LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> | ||
17 | Reviewed-by: Damien Neil <dneil@google.com> | ||
18 | (cherry picked from commit ccbc725f2d678255df1bd326fa511a492aa3a0aa) | ||
19 | Reviewed-on: https://go-review.googlesource.com/c/go/+/567515 | ||
20 | Reviewed-by: Carlos Amedee <carlos@golang.org> | ||
21 | |||
22 | Upstream-Status: Backport [https://github.com/golang/go/commit/3643147a29352ca2894fd5d0d2069bc4b4335a7e] | ||
23 | CVE: CVE-2024-24785 | ||
24 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
25 | --- | ||
26 | src/html/template/js.go | 22 ++++++++- | ||
27 | src/html/template/js_test.go | 96 ++++++++++++++++++++---------------- | ||
28 | 2 files changed, 74 insertions(+), 44 deletions(-) | ||
29 | |||
30 | diff --git a/src/html/template/js.go b/src/html/template/js.go | ||
31 | index 35994f0..4d3b25d 100644 | ||
32 | --- a/src/html/template/js.go | ||
33 | +++ b/src/html/template/js.go | ||
34 | @@ -171,13 +171,31 @@ func jsValEscaper(args ...interface{}) string { | ||
35 | // cyclic data. This may be an unacceptable DoS risk. | ||
36 | b, err := json.Marshal(a) | ||
37 | if err != nil { | ||
38 | - // Put a space before comment so that if it is flush against | ||
39 | + // While the standard JSON marshaller does not include user controlled | ||
40 | + // information in the error message, if a type has a MarshalJSON method, | ||
41 | + // the content of the error message is not guaranteed. Since we insert | ||
42 | + // the error into the template, as part of a comment, we attempt to | ||
43 | + // prevent the error from either terminating the comment, or the script | ||
44 | + // block itself. | ||
45 | + // | ||
46 | + // In particular we: | ||
47 | + // * replace "*/" comment end tokens with "* /", which does not | ||
48 | + // terminate the comment | ||
49 | + // * replace "</script" with "\x3C/script", and "<!--" with | ||
50 | + // "\x3C!--", which prevents confusing script block termination | ||
51 | + // semantics | ||
52 | + // | ||
53 | + // We also put a space before the comment so that if it is flush against | ||
54 | // a division operator it is not turned into a line comment: | ||
55 | // x/{{y}} | ||
56 | // turning into | ||
57 | // x//* error marshaling y: | ||
58 | // second line of error message */null | ||
59 | - return fmt.Sprintf(" /* %s */null ", strings.ReplaceAll(err.Error(), "*/", "* /")) | ||
60 | + errStr := err.Error() | ||
61 | + errStr = strings.ReplaceAll(errStr, "*/", "* /") | ||
62 | + errStr = strings.ReplaceAll(errStr, "</script", `\x3C/script`) | ||
63 | + errStr = strings.ReplaceAll(errStr, "<!--", `\x3C!--`) | ||
64 | + return fmt.Sprintf(" /* %s */null ", errStr) | ||
65 | } | ||
66 | |||
67 | // TODO: maybe post-process output to prevent it from containing | ||
68 | diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go | ||
69 | index de9ef28..3fc3baf 100644 | ||
70 | --- a/src/html/template/js_test.go | ||
71 | +++ b/src/html/template/js_test.go | ||
72 | @@ -5,6 +5,7 @@ | ||
73 | package template | ||
74 | |||
75 | import ( | ||
76 | + "errors" | ||
77 | "bytes" | ||
78 | "math" | ||
79 | "strings" | ||
80 | @@ -104,61 +105,72 @@ func TestNextJsCtx(t *testing.T) { | ||
81 | } | ||
82 | } | ||
83 | |||
84 | +type jsonErrType struct{} | ||
85 | + | ||
86 | +func (e *jsonErrType) MarshalJSON() ([]byte, error) { | ||
87 | + return nil, errors.New("beep */ boop </script blip <!--") | ||
88 | +} | ||
89 | + | ||
90 | func TestJSValEscaper(t *testing.T) { | ||
91 | tests := []struct { | ||
92 | - x interface{} | ||
93 | - js string | ||
94 | + x interface{} | ||
95 | + js string | ||
96 | + skipNest bool | ||
97 | }{ | ||
98 | - {int(42), " 42 "}, | ||
99 | - {uint(42), " 42 "}, | ||
100 | - {int16(42), " 42 "}, | ||
101 | - {uint16(42), " 42 "}, | ||
102 | - {int32(-42), " -42 "}, | ||
103 | - {uint32(42), " 42 "}, | ||
104 | - {int16(-42), " -42 "}, | ||
105 | - {uint16(42), " 42 "}, | ||
106 | - {int64(-42), " -42 "}, | ||
107 | - {uint64(42), " 42 "}, | ||
108 | - {uint64(1) << 53, " 9007199254740992 "}, | ||
109 | + {int(42), " 42 ", false}, | ||
110 | + {uint(42), " 42 ", false}, | ||
111 | + {int16(42), " 42 ", false}, | ||
112 | + {uint16(42), " 42 ", false}, | ||
113 | + {int32(-42), " -42 ", false}, | ||
114 | + {uint32(42), " 42 ", false}, | ||
115 | + {int16(-42), " -42 ", false}, | ||
116 | + {uint16(42), " 42 ", false}, | ||
117 | + {int64(-42), " -42 ", false}, | ||
118 | + {uint64(42), " 42 ", false}, | ||
119 | + {uint64(1) << 53, " 9007199254740992 ", false}, | ||
120 | // ulp(1 << 53) > 1 so this loses precision in JS | ||
121 | // but it is still a representable integer literal. | ||
122 | - {uint64(1)<<53 + 1, " 9007199254740993 "}, | ||
123 | - {float32(1.0), " 1 "}, | ||
124 | - {float32(-1.0), " -1 "}, | ||
125 | - {float32(0.5), " 0.5 "}, | ||
126 | - {float32(-0.5), " -0.5 "}, | ||
127 | - {float32(1.0) / float32(256), " 0.00390625 "}, | ||
128 | - {float32(0), " 0 "}, | ||
129 | - {math.Copysign(0, -1), " -0 "}, | ||
130 | - {float64(1.0), " 1 "}, | ||
131 | - {float64(-1.0), " -1 "}, | ||
132 | - {float64(0.5), " 0.5 "}, | ||
133 | - {float64(-0.5), " -0.5 "}, | ||
134 | - {float64(0), " 0 "}, | ||
135 | - {math.Copysign(0, -1), " -0 "}, | ||
136 | - {"", `""`}, | ||
137 | - {"foo", `"foo"`}, | ||
138 | + {uint64(1)<<53 + 1, " 9007199254740993 ", false}, | ||
139 | + {float32(1.0), " 1 ", false}, | ||
140 | + {float32(-1.0), " -1 ", false}, | ||
141 | + {float32(0.5), " 0.5 ", false}, | ||
142 | + {float32(-0.5), " -0.5 ", false}, | ||
143 | + {float32(1.0) / float32(256), " 0.00390625 ", false}, | ||
144 | + {float32(0), " 0 ", false}, | ||
145 | + {math.Copysign(0, -1), " -0 ", false}, | ||
146 | + {float64(1.0), " 1 ", false}, | ||
147 | + {float64(-1.0), " -1 ", false}, | ||
148 | + {float64(0.5), " 0.5 ", false}, | ||
149 | + {float64(-0.5), " -0.5 ", false}, | ||
150 | + {float64(0), " 0 ", false}, | ||
151 | + {math.Copysign(0, -1), " -0 ", false}, | ||
152 | + {"", `""`, false}, | ||
153 | + {"foo", `"foo"`, false}, | ||
154 | // Newlines. | ||
155 | - {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, | ||
156 | + {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`, false}, | ||
157 | // "\v" == "v" on IE 6 so use "\u000b" instead. | ||
158 | - {"\t\x0b", `"\t\u000b"`}, | ||
159 | - {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`}, | ||
160 | - {[]interface{}{}, "[]"}, | ||
161 | - {[]interface{}{42, "foo", nil}, `[42,"foo",null]`}, | ||
162 | - {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`}, | ||
163 | - {"<!--", `"\u003c!--"`}, | ||
164 | - {"-->", `"--\u003e"`}, | ||
165 | - {"<![CDATA[", `"\u003c![CDATA["`}, | ||
166 | - {"]]>", `"]]\u003e"`}, | ||
167 | - {"</script", `"\u003c/script"`}, | ||
168 | - {"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E" | ||
169 | - {nil, " null "}, | ||
170 | + {"\t\x0b", `"\t\u000b"`, false}, | ||
171 | + {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`, false}, | ||
172 | + {[]interface{}{}, "[]", false}, | ||
173 | + {[]interface{}{42, "foo", nil}, `[42,"foo",null]`, false}, | ||
174 | + {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`, false}, | ||
175 | + {"<!--", `"\u003c!--"`, false}, | ||
176 | + {"-->", `"--\u003e"`, false}, | ||
177 | + {"<![CDATA[", `"\u003c![CDATA["`, false}, | ||
178 | + {"]]>", `"]]\u003e"`, false}, | ||
179 | + {"</script", `"\u003c/script"`, false}, | ||
180 | + {"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E" | ||
181 | + {nil, " null ", false}, | ||
182 | + {&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true}, | ||
183 | } | ||
184 | |||
185 | for _, test := range tests { | ||
186 | if js := jsValEscaper(test.x); js != test.js { | ||
187 | t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js) | ||
188 | } | ||
189 | + if test.skipNest { | ||
190 | + continue | ||
191 | + } | ||
192 | // Make sure that escaping corner cases are not broken | ||
193 | // by nesting. | ||
194 | a := []interface{}{test.x} | ||
195 | -- | ||
196 | 2.25.1 | ||
197 | |||