diff options
author | Mingli Yu <mingli.yu@windriver.com> | 2022-03-29 14:13:44 +0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2022-04-03 20:49:03 +0100 |
commit | 9fc229578cc213be4cbb8bcebed653bd03cda244 (patch) | |
tree | c7837e90876b40bc78ec8cde207d3507fb3e5843 /meta | |
parent | 6e1ca0e922e7aee3eb945c0f04a2ace1c8b36100 (diff) | |
download | poky-9fc229578cc213be4cbb8bcebed653bd03cda244.tar.gz |
epiphany: fix CVEs
Backport patch [1] to fix below CVEs:
- CVE-2021-45085
- CVE-2021-45086
- CVE-2021-45087
- CVE-2021-45088
[1] https://sources.debian.org/data/main/e/epiphany-browser/3.38.2-1+deb11u2/debian/patches/encode-untrusted-data.patch
(From OE-Core rev: 125c6f5770542c3b509336b92d6c45c0c955027e)
Signed-off-by: Mingli Yu <mingli.yu@windriver.com>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r-- | meta/recipes-gnome/epiphany/epiphany_3.38.2.bb | 1 | ||||
-rw-r--r-- | meta/recipes-gnome/epiphany/files/encode-untrusted-data.patch | 707 |
2 files changed, 708 insertions, 0 deletions
diff --git a/meta/recipes-gnome/epiphany/epiphany_3.38.2.bb b/meta/recipes-gnome/epiphany/epiphany_3.38.2.bb index 04f340f133..72d116da69 100644 --- a/meta/recipes-gnome/epiphany/epiphany_3.38.2.bb +++ b/meta/recipes-gnome/epiphany/epiphany_3.38.2.bb | |||
@@ -18,6 +18,7 @@ SRC_URI = "${GNOME_MIRROR}/${GNOMEBN}/${@gnome_verdir("${PV}")}/${GNOMEBN}-${PV} | |||
18 | file://0002-help-meson.build-disable-the-use-of-yelp.patch \ | 18 | file://0002-help-meson.build-disable-the-use-of-yelp.patch \ |
19 | file://migrator.patch \ | 19 | file://migrator.patch \ |
20 | file://distributor.patch \ | 20 | file://distributor.patch \ |
21 | file://encode-untrusted-data.patch \ | ||
21 | " | 22 | " |
22 | SRC_URI[archive.sha256sum] = "8b05f2bcc1e80ecf4a10f6f01b3285087eb4cbdf5741dffb8c0355715ef5116d" | 23 | SRC_URI[archive.sha256sum] = "8b05f2bcc1e80ecf4a10f6f01b3285087eb4cbdf5741dffb8c0355715ef5116d" |
23 | 24 | ||
diff --git a/meta/recipes-gnome/epiphany/files/encode-untrusted-data.patch b/meta/recipes-gnome/epiphany/files/encode-untrusted-data.patch new file mode 100644 index 0000000000..4805ee4e6b --- /dev/null +++ b/meta/recipes-gnome/epiphany/files/encode-untrusted-data.patch | |||
@@ -0,0 +1,707 @@ | |||
1 | From: Michael Catanzaro <mcatanzaro@redhat.com> | ||
2 | Subject: Properly encode untrusted data when injecting into trusted pages | ||
3 | |||
4 | CVE: CVE-2021-45085 CVE-2021-45086 CVE-2021-45087 CVE-2021-45088 | ||
5 | |||
6 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/epiphany/-/compare/c27a8180e12e6ec92292dcf53b9243815ad9aa2e...abac58c5191b7d653fbefa8d44e5c2bd4d002825?from_project_id=1906] | ||
7 | |||
8 | Signed-off-by: Mingli Yu <mingli.yu@windriver.com> | ||
9 | Index: epiphany-browser/embed/ephy-about-handler.c | ||
10 | =================================================================== | ||
11 | --- epiphany-browser.orig/embed/ephy-about-handler.c | ||
12 | +++ epiphany-browser/embed/ephy-about-handler.c | ||
13 | @@ -27,6 +27,7 @@ | ||
14 | #include "ephy-file-helpers.h" | ||
15 | #include "ephy-flatpak-utils.h" | ||
16 | #include "ephy-history-service.h" | ||
17 | +#include "ephy-output-encoding.h" | ||
18 | #include "ephy-prefs.h" | ||
19 | #include "ephy-settings.h" | ||
20 | #include "ephy-smaps.h" | ||
21 | @@ -263,16 +264,34 @@ handle_applications_finished_cb (EphyAbo | ||
22 | |||
23 | for (p = applications; p; p = p->next) { | ||
24 | EphyWebApplication *app = (EphyWebApplication *)p->data; | ||
25 | - | ||
26 | + g_autofree char *html_encoded_id = NULL; | ||
27 | + g_autofree char *encoded_icon_url = NULL; | ||
28 | + g_autofree char *encoded_name = NULL; | ||
29 | + g_autofree char *encoded_url = NULL; | ||
30 | + g_autofree char *js_encoded_id = NULL; | ||
31 | + g_autofree char *encoded_install_date = NULL; | ||
32 | + | ||
33 | + /* Most of these fields are untrusted. The web app suggests its own title, | ||
34 | + * which gets used in the app ID and icon URL. The main URL could contain | ||
35 | + * anything. Install date is the only trusted field here in that it's | ||
36 | + * constructed by Epiphany, but it's a freeform string and we're encoding | ||
37 | + * everything else here anyway, so might as well encode this too. | ||
38 | + */ | ||
39 | + html_encoded_id = ephy_encode_for_html_attribute (app->id); | ||
40 | + encoded_icon_url = ephy_encode_for_html_attribute (app->icon_url); | ||
41 | + encoded_name = ephy_encode_for_html_entity (app->name); | ||
42 | + encoded_url = ephy_encode_for_html_entity (app->url); | ||
43 | + js_encoded_id = ephy_encode_for_javascript (app->id); | ||
44 | + encoded_install_date = ephy_encode_for_html_entity (app->install_date); | ||
45 | g_string_append_printf (data_str, | ||
46 | "<tbody><tr id =\"%s\">" | ||
47 | "<td class=\"icon\"><img width=64 height=64 src=\"file://%s\"></img></td>" | ||
48 | "<td class=\"data\"><div class=\"appname\">%s</div><div class=\"appurl\">%s</div></td>" | ||
49 | "<td class=\"input\"><input type=\"button\" value=\"%s\" onclick=\"deleteWebApp('%s');\"></td>" | ||
50 | "<td class=\"date\">%s <br /> %s</td></tr></tbody>", | ||
51 | - app->id, app->icon_url, app->name, app->url, _("Delete"), app->id, | ||
52 | + html_encoded_id, encoded_icon_url, encoded_name, encoded_url, _("Delete"), js_encoded_id, | ||
53 | /* Note for translators: this refers to the installation date. */ | ||
54 | - _("Installed on:"), app->install_date); | ||
55 | + _("Installed on:"), encoded_install_date); | ||
56 | } | ||
57 | |||
58 | g_string_append (data_str, "</table></div></body></html>"); | ||
59 | @@ -407,7 +426,9 @@ history_service_query_urls_cb (EphyHisto | ||
60 | EphyHistoryURL *url = (EphyHistoryURL *)l->data; | ||
61 | const char *snapshot; | ||
62 | g_autofree char *thumbnail_style = NULL; | ||
63 | - g_autofree char *markup = NULL; | ||
64 | + g_autofree char *entity_encoded_title = NULL; | ||
65 | + g_autofree char *attribute_encoded_title = NULL; | ||
66 | + g_autofree char *encoded_url = NULL; | ||
67 | |||
68 | snapshot = ephy_snapshot_service_lookup_cached_snapshot_path (snapshot_service, url->url); | ||
69 | if (snapshot) | ||
70 | @@ -415,15 +436,19 @@ history_service_query_urls_cb (EphyHisto | ||
71 | else | ||
72 | ephy_embed_shell_schedule_thumbnail_update (shell, url); | ||
73 | |||
74 | - markup = g_markup_escape_text (url->title, -1); | ||
75 | + /* Title and URL are controlled by web content and could be malicious. */ | ||
76 | + entity_encoded_title = ephy_encode_for_html_entity (url->title); | ||
77 | + attribute_encoded_title = ephy_encode_for_html_attribute (url->title); | ||
78 | + encoded_url = ephy_encode_for_html_attribute (url->url); | ||
79 | g_string_append_printf (data_str, | ||
80 | "<a class=\"overview-item\" title=\"%s\" href=\"%s\">" | ||
81 | " <div class=\"overview-close-button\" title=\"%s\"></div>" | ||
82 | " <span class=\"overview-thumbnail\"%s></span>" | ||
83 | " <span class=\"overview-title\">%s</span>" | ||
84 | "</a>", | ||
85 | - markup, url->url, _("Remove from overview"), | ||
86 | - thumbnail_style ? thumbnail_style : "", url->title); | ||
87 | + attribute_encoded_title, encoded_url, _("Remove from overview"), | ||
88 | + thumbnail_style ? thumbnail_style : "", | ||
89 | + entity_encoded_title); | ||
90 | } | ||
91 | |||
92 | data_str = g_string_append (data_str, | ||
93 | Index: epiphany-browser/embed/ephy-pdf-handler.c | ||
94 | =================================================================== | ||
95 | --- epiphany-browser.orig/embed/ephy-pdf-handler.c | ||
96 | +++ epiphany-browser/embed/ephy-pdf-handler.c | ||
97 | @@ -23,6 +23,7 @@ | ||
98 | |||
99 | #include "ephy-embed-container.h" | ||
100 | #include "ephy-embed-shell.h" | ||
101 | +#include "ephy-output-encoding.h" | ||
102 | #include "ephy-web-view.h" | ||
103 | |||
104 | #include <gio/gio.h> | ||
105 | @@ -124,8 +125,9 @@ pdf_file_loaded (GObject *source, | ||
106 | GBytes *html_file; | ||
107 | g_autoptr (GError) error = NULL; | ||
108 | g_autoptr (GString) html = NULL; | ||
109 | - g_autofree gchar *b64 = NULL; | ||
110 | g_autofree char *file_data = NULL; | ||
111 | + g_autofree char *encoded_file_data = NULL; | ||
112 | + g_autofree char *encoded_filename = NULL; | ||
113 | gsize len = 0; | ||
114 | |||
115 | if (!g_file_load_contents_finish (G_FILE (source), res, &file_data, &len, NULL, &error)) { | ||
116 | @@ -134,13 +136,13 @@ pdf_file_loaded (GObject *source, | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | - html_file = g_resources_lookup_data ("/org/gnome/epiphany/pdfjs/web/viewer.html", 0, NULL); | ||
121 | - | ||
122 | - b64 = g_base64_encode ((const guchar *)file_data, len); | ||
123 | g_file_delete_async (G_FILE (source), G_PRIORITY_DEFAULT, NULL, pdf_file_deleted, NULL); | ||
124 | |||
125 | - html = g_string_new (""); | ||
126 | - g_string_printf (html, g_bytes_get_data (html_file, NULL), b64, self->file_name ? self->file_name : ""); | ||
127 | + html = g_string_new (NULL); | ||
128 | + html_file = g_resources_lookup_data ("/org/gnome/epiphany/pdfjs/web/viewer.html", 0, NULL); | ||
129 | + encoded_file_data = g_base64_encode ((const guchar *)file_data, len); | ||
130 | + encoded_filename = self->file_name ? ephy_encode_for_html_attribute (self->file_name) : g_strdup (""); | ||
131 | + g_string_printf (html, g_bytes_get_data (html_file, NULL), encoded_file_data, encoded_filename); | ||
132 | |||
133 | finish_uri_scheme_request (self, g_strdup (html->str), NULL); | ||
134 | } | ||
135 | Index: epiphany-browser/embed/ephy-reader-handler.c | ||
136 | =================================================================== | ||
137 | --- epiphany-browser.orig/embed/ephy-reader-handler.c | ||
138 | +++ epiphany-browser/embed/ephy-reader-handler.c | ||
139 | @@ -24,6 +24,7 @@ | ||
140 | #include "ephy-embed-container.h" | ||
141 | #include "ephy-embed-shell.h" | ||
142 | #include "ephy-lib-type-builtins.h" | ||
143 | +#include "ephy-output-encoding.h" | ||
144 | #include "ephy-settings.h" | ||
145 | #include "ephy-web-view.h" | ||
146 | |||
147 | @@ -156,7 +157,9 @@ readability_js_finish_cb (GObject * | ||
148 | g_autoptr (WebKitJavascriptResult) js_result = NULL; | ||
149 | g_autoptr (GError) error = NULL; | ||
150 | g_autofree gchar *byline = NULL; | ||
151 | + g_autofree gchar *encoded_byline = NULL; | ||
152 | g_autofree gchar *content = NULL; | ||
153 | + g_autofree gchar *encoded_title = NULL; | ||
154 | g_autoptr (GString) html = NULL; | ||
155 | g_autoptr (GBytes) style_css = NULL; | ||
156 | const gchar *title; | ||
157 | @@ -173,10 +176,14 @@ readability_js_finish_cb (GObject * | ||
158 | |||
159 | byline = readability_get_property_string (js_result, "byline"); | ||
160 | content = readability_get_property_string (js_result, "content"); | ||
161 | + title = webkit_web_view_get_title (web_view); | ||
162 | + | ||
163 | + encoded_byline = byline ? ephy_encode_for_html_entity (byline) : g_strdup (""); | ||
164 | + encoded_title = ephy_encode_for_html_entity (title); | ||
165 | |||
166 | - html = g_string_new (""); | ||
167 | + html = g_string_new (NULL); | ||
168 | style_css = g_resources_lookup_data ("/org/gnome/epiphany/readability/reader.css", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); | ||
169 | - title = webkit_web_view_get_title (web_view); | ||
170 | + | ||
171 | font_style = enum_nick (EPHY_TYPE_PREFS_READER_FONT_STYLE, | ||
172 | g_settings_get_enum (EPHY_SETTINGS_READER, | ||
173 | EPHY_PREFS_READER_FONT_STYLE)); | ||
174 | @@ -186,7 +193,8 @@ readability_js_finish_cb (GObject * | ||
175 | |||
176 | g_string_append_printf (html, "<style>%s</style>" | ||
177 | "<title>%s</title>" | ||
178 | - "<meta http-equiv=\"Content-Type\" content=\"text/html;\" charset=\"UTF-8\">" \ | ||
179 | + "<meta http-equiv='Content-Type' content='text/html;' charset='UTF-8'>" \ | ||
180 | + "<meta http-equiv='Content-Security-Policy' content=\"script-src 'none'\">" \ | ||
181 | "<body class='%s %s'>" | ||
182 | "<article>" | ||
183 | "<h2>" | ||
184 | @@ -197,13 +205,27 @@ readability_js_finish_cb (GObject * | ||
185 | "</i>" | ||
186 | "<hr>", | ||
187 | (gchar *)g_bytes_get_data (style_css, NULL), | ||
188 | - title, | ||
189 | + encoded_title, | ||
190 | font_style, | ||
191 | color_scheme, | ||
192 | - title, | ||
193 | - byline != NULL ? byline : ""); | ||
194 | + encoded_title, | ||
195 | + encoded_byline); | ||
196 | + | ||
197 | + /* We cannot encode the page content because it contains HTML tags inserted by | ||
198 | + * Readability.js. Upstream recommends that we use an XSS sanitizer like | ||
199 | + * DOMPurify plus Content-Security-Policy, but I'm not keen on adding more | ||
200 | + * bundled JS dependencies, and we have an advantage over Firefox in that we | ||
201 | + * don't need scripts to work at this point. So instead the above CSP | ||
202 | + * completely blocks all scripts, which should hopefully obviate the need for | ||
203 | + * a DOM purifier. | ||
204 | + * | ||
205 | + * Note the encoding for page title and byline is still required, as they're | ||
206 | + * not supposed to contain markup, and Readability.js unescapes them before | ||
207 | + * returning them to us. | ||
208 | + */ | ||
209 | g_string_append (html, content); | ||
210 | g_string_append (html, "</article>"); | ||
211 | + g_string_append (html, "</body>"); | ||
212 | |||
213 | finish_uri_scheme_request (request, g_strdup (html->str), NULL); | ||
214 | } | ||
215 | Index: epiphany-browser/embed/ephy-view-source-handler.c | ||
216 | =================================================================== | ||
217 | --- epiphany-browser.orig/embed/ephy-view-source-handler.c | ||
218 | +++ epiphany-browser/embed/ephy-view-source-handler.c | ||
219 | @@ -23,6 +23,7 @@ | ||
220 | |||
221 | #include "ephy-embed-container.h" | ||
222 | #include "ephy-embed-shell.h" | ||
223 | +#include "ephy-output-encoding.h" | ||
224 | #include "ephy-web-view.h" | ||
225 | |||
226 | #include <gio/gio.h> | ||
227 | @@ -109,7 +110,9 @@ web_resource_data_cb (WebKitWebResource | ||
228 | EphyViewSourceRequest *request) | ||
229 | { | ||
230 | g_autofree guchar *data = NULL; | ||
231 | - g_autofree char *escaped_str = NULL; | ||
232 | + g_autofree char *data_str = NULL; | ||
233 | + g_autofree char *encoded_str = NULL; | ||
234 | + g_autofree char *encoded_uri = NULL; | ||
235 | g_autoptr (GError) error = NULL; | ||
236 | g_autofree char *html = NULL; | ||
237 | gsize length; | ||
238 | @@ -120,8 +123,13 @@ web_resource_data_cb (WebKitWebResource | ||
239 | return; | ||
240 | } | ||
241 | |||
242 | - /* Warning: data is not a string, so we pass length here because it's not NUL-terminated. */ | ||
243 | - escaped_str = g_markup_escape_text ((const char *)data, length); | ||
244 | + /* Convert data to a string */ | ||
245 | + data_str = g_malloc (length + 1); | ||
246 | + memcpy (data_str, data, length); | ||
247 | + data_str[length] = '\0'; | ||
248 | + | ||
249 | + encoded_str = ephy_encode_for_html_entity (data_str); | ||
250 | + encoded_uri = ephy_encode_for_html_entity (webkit_web_resource_get_uri (resource)); | ||
251 | |||
252 | html = g_strdup_printf ("<head>" | ||
253 | " <link rel='stylesheet' href='ephy-resource:///org/gnome/epiphany/highlightjs/nnfx.css' media='(prefers-color-scheme: no-preference), (prefers-color-scheme: light)'>" | ||
254 | @@ -136,8 +144,8 @@ web_resource_data_cb (WebKitWebResource | ||
255 | " hljs.initLineNumbersOnLoad();</script>" | ||
256 | " <pre><code class='html'>%s</code></pre>" | ||
257 | "</body>", | ||
258 | - webkit_web_resource_get_uri (resource), | ||
259 | - escaped_str); | ||
260 | + encoded_uri, | ||
261 | + encoded_str); | ||
262 | |||
263 | finish_uri_scheme_request (request, g_steal_pointer (&html), NULL); | ||
264 | } | ||
265 | Index: epiphany-browser/embed/ephy-web-view.c | ||
266 | =================================================================== | ||
267 | --- epiphany-browser.orig/embed/ephy-web-view.c | ||
268 | +++ epiphany-browser/embed/ephy-web-view.c | ||
269 | @@ -38,6 +38,7 @@ | ||
270 | #include "ephy-gsb-utils.h" | ||
271 | #include "ephy-history-service.h" | ||
272 | #include "ephy-lib-type-builtins.h" | ||
273 | +#include "ephy-output-encoding.h" | ||
274 | #include "ephy-permissions-manager.h" | ||
275 | #include "ephy-prefs.h" | ||
276 | #include "ephy-reader-handler.h" | ||
277 | @@ -1772,9 +1773,11 @@ format_network_error_page (const char * | ||
278 | const char **icon_name, | ||
279 | const char **style) | ||
280 | { | ||
281 | - char *formatted_origin; | ||
282 | - char *formatted_reason; | ||
283 | - char *first_paragraph; | ||
284 | + g_autofree char *encoded_uri = NULL; | ||
285 | + g_autofree char *encoded_origin = NULL; | ||
286 | + g_autofree char *formatted_origin = NULL; | ||
287 | + g_autofree char *formatted_reason = NULL; | ||
288 | + g_autofree char *first_paragraph = NULL; | ||
289 | const char *second_paragraph; | ||
290 | |||
291 | /* Page title when a site cannot be loaded due to a network error. */ | ||
292 | @@ -1783,7 +1786,8 @@ format_network_error_page (const char * | ||
293 | /* Message title when a site cannot be loaded due to a network error. */ | ||
294 | *message_title = g_strdup (_("Unable to display this website")); | ||
295 | |||
296 | - formatted_origin = g_strdup_printf ("<strong>%s</strong>", origin); | ||
297 | + encoded_origin = ephy_encode_for_html_entity (origin); | ||
298 | + formatted_origin = g_strdup_printf ("<strong>%s</strong>", encoded_origin); | ||
299 | /* Error details when a site cannot be loaded due to a network error. */ | ||
300 | first_paragraph = g_strdup_printf (_("The site at %s seems to be " | ||
301 | "unavailable."), | ||
302 | @@ -1805,16 +1809,13 @@ format_network_error_page (const char * | ||
303 | |||
304 | /* The button on the network error page. DO NOT ADD MNEMONICS HERE. */ | ||
305 | *button_label = g_strdup (_("Reload")); | ||
306 | - *button_action = g_strdup_printf ("window.location = '%s';", uri); | ||
307 | + encoded_uri = ephy_encode_for_javascript (uri); | ||
308 | + *button_action = g_strdup_printf ("window.location = '%s';", encoded_uri); | ||
309 | /* Mnemonic for the Reload button on browser error pages. */ | ||
310 | *button_accesskey = C_("reload-access-key", "R"); | ||
311 | |||
312 | *icon_name = "network-error-symbolic.svg"; | ||
313 | *style = "default"; | ||
314 | - | ||
315 | - g_free (formatted_origin); | ||
316 | - g_free (formatted_reason); | ||
317 | - g_free (first_paragraph); | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | @@ -1828,10 +1829,12 @@ format_crash_error_page (const char *ur | ||
322 | const char **icon_name, | ||
323 | const char **style) | ||
324 | { | ||
325 | - char *formatted_uri; | ||
326 | - char *formatted_distributor; | ||
327 | - char *first_paragraph; | ||
328 | - char *second_paragraph; | ||
329 | + g_autofree char *html_encoded_uri = NULL; | ||
330 | + g_autofree char *js_encoded_uri = NULL; | ||
331 | + g_autofree char *formatted_uri = NULL; | ||
332 | + g_autofree char *formatted_distributor = NULL; | ||
333 | + g_autofree char *first_paragraph = NULL; | ||
334 | + g_autofree char *second_paragraph = NULL; | ||
335 | |||
336 | /* Page title when a site cannot be loaded due to a page crash error. */ | ||
337 | *page_title = g_strdup_printf (_("Problem Loading Page")); | ||
338 | @@ -1839,7 +1842,8 @@ format_crash_error_page (const char *ur | ||
339 | /* Message title when a site cannot be loaded due to a page crash error. */ | ||
340 | *message_title = g_strdup (_("Oops! There may be a problem")); | ||
341 | |||
342 | - formatted_uri = g_strdup_printf ("<strong>%s</strong>", uri); | ||
343 | + html_encoded_uri = ephy_encode_for_html_entity (uri); | ||
344 | + formatted_uri = g_strdup_printf ("<strong>%s</strong>", html_encoded_uri); | ||
345 | /* Error details when a site cannot be loaded due to a page crash error. */ | ||
346 | first_paragraph = g_strdup_printf (_("The page %s may have caused Web to " | ||
347 | "close unexpectedly."), | ||
348 | @@ -1858,17 +1862,13 @@ format_crash_error_page (const char *ur | ||
349 | |||
350 | /* The button on the page crash error page. DO NOT ADD MNEMONICS HERE. */ | ||
351 | *button_label = g_strdup (_("Reload")); | ||
352 | - *button_action = g_strdup_printf ("window.location = '%s';", uri); | ||
353 | + js_encoded_uri = ephy_encode_for_javascript (uri); | ||
354 | + *button_action = g_strdup_printf ("window.location = '%s';", js_encoded_uri); | ||
355 | /* Mnemonic for the Reload button on browser error pages. */ | ||
356 | *button_accesskey = C_("reload-access-key", "R"); | ||
357 | |||
358 | *icon_name = "computer-fail-symbolic.svg"; | ||
359 | *style = "default"; | ||
360 | - | ||
361 | - g_free (formatted_uri); | ||
362 | - g_free (formatted_distributor); | ||
363 | - g_free (first_paragraph); | ||
364 | - g_free (second_paragraph); | ||
365 | } | ||
366 | |||
367 | static void | ||
368 | @@ -1882,6 +1882,7 @@ format_process_crash_error_page (const c | ||
369 | const char **icon_name, | ||
370 | const char **style) | ||
371 | { | ||
372 | + g_autofree char *encoded_uri = NULL; | ||
373 | const char *first_paragraph; | ||
374 | |||
375 | /* Page title when a site cannot be loaded due to a process crash error. */ | ||
376 | @@ -1897,7 +1898,8 @@ format_process_crash_error_page (const c | ||
377 | |||
378 | /* The button on the process crash error page. DO NOT ADD MNEMONICS HERE. */ | ||
379 | *button_label = g_strdup (_("Reload")); | ||
380 | - *button_action = g_strdup_printf ("window.location = '%s';", uri); | ||
381 | + encoded_uri = ephy_encode_for_javascript (uri); | ||
382 | + *button_action = g_strdup_printf ("window.location = '%s';", encoded_uri); | ||
383 | /* Mnemonic for the Reload button on browser error pages. */ | ||
384 | *button_accesskey = C_("reload-access-key", "R"); | ||
385 | |||
386 | @@ -1921,8 +1923,9 @@ format_tls_error_page (EphyWebView *vie | ||
387 | const char **icon_name, | ||
388 | const char **style) | ||
389 | { | ||
390 | - char *formatted_origin; | ||
391 | - char *first_paragraph; | ||
392 | + g_autofree char *encoded_origin = NULL; | ||
393 | + g_autofree char *formatted_origin = NULL; | ||
394 | + g_autofree char *first_paragraph = NULL; | ||
395 | |||
396 | /* Page title when a site is not loaded due to an invalid TLS certificate. */ | ||
397 | *page_title = g_strdup_printf (_("Security Violation")); | ||
398 | @@ -1930,7 +1933,8 @@ format_tls_error_page (EphyWebView *vie | ||
399 | /* Message title when a site is not loaded due to an invalid TLS certificate. */ | ||
400 | *message_title = g_strdup (_("This Connection is Not Secure")); | ||
401 | |||
402 | - formatted_origin = g_strdup_printf ("<strong>%s</strong>", origin); | ||
403 | + encoded_origin = ephy_encode_for_html_entity (origin); | ||
404 | + formatted_origin = g_strdup_printf ("<strong>%s</strong>", encoded_origin); | ||
405 | /* Error details when a site is not loaded due to an invalid TLS certificate. */ | ||
406 | first_paragraph = g_strdup_printf (_("This does not look like the real %s. " | ||
407 | "Attackers might be trying to steal or " | ||
408 | @@ -1956,9 +1960,6 @@ format_tls_error_page (EphyWebView *vie | ||
409 | |||
410 | *icon_name = "channel-insecure-symbolic.svg"; | ||
411 | *style = "danger"; | ||
412 | - | ||
413 | - g_free (formatted_origin); | ||
414 | - g_free (first_paragraph); | ||
415 | } | ||
416 | |||
417 | static void | ||
418 | @@ -1978,8 +1979,9 @@ format_unsafe_browsing_error_page (EphyW | ||
419 | const char **icon_name, | ||
420 | const char **style) | ||
421 | { | ||
422 | - char *formatted_origin; | ||
423 | - char *first_paragraph; | ||
424 | + g_autofree char *encoded_origin = NULL; | ||
425 | + g_autofree char *formatted_origin = NULL; | ||
426 | + g_autofree char *first_paragraph = NULL; | ||
427 | |||
428 | /* Page title when a site is flagged by Google Safe Browsing verification. */ | ||
429 | *page_title = g_strdup_printf (_("Security Warning")); | ||
430 | @@ -1987,7 +1989,8 @@ format_unsafe_browsing_error_page (EphyW | ||
431 | /* Message title on the unsafe browsing error page. */ | ||
432 | *message_title = g_strdup (_("Unsafe website detected!")); | ||
433 | |||
434 | - formatted_origin = g_strdup_printf ("<strong>%s</strong>", origin); | ||
435 | + encoded_origin = ephy_encode_for_html_entity (origin); | ||
436 | + formatted_origin = g_strdup_printf ("<strong>%s</strong>", encoded_origin); | ||
437 | /* Error details on the unsafe browsing error page. | ||
438 | * https://developers.google.com/safe-browsing/v4/usage-limits#UserWarnings | ||
439 | */ | ||
440 | @@ -2045,9 +2048,6 @@ format_unsafe_browsing_error_page (EphyW | ||
441 | |||
442 | *icon_name = "security-high-symbolic.svg"; | ||
443 | *style = "danger"; | ||
444 | - | ||
445 | - g_free (formatted_origin); | ||
446 | - g_free (first_paragraph); | ||
447 | } | ||
448 | |||
449 | static void | ||
450 | @@ -2061,7 +2061,8 @@ format_no_such_file_error_page (EphyWebV | ||
451 | const char **icon_name, | ||
452 | const char **style) | ||
453 | { | ||
454 | - g_autofree gchar *formatted_origin = NULL; | ||
455 | + g_autofree gchar *encoded_address = NULL; | ||
456 | + g_autofree gchar *formatted_address = NULL; | ||
457 | g_autofree gchar *first_paragraph = NULL; | ||
458 | g_autofree gchar *second_paragraph = NULL; | ||
459 | |||
460 | @@ -2071,10 +2072,11 @@ format_no_such_file_error_page (EphyWebV | ||
461 | /* Message title on the no such file error page. */ | ||
462 | *message_title = g_strdup (_("File not found")); | ||
463 | |||
464 | - formatted_origin = g_strdup_printf ("<strong>%s</strong>", view->address); | ||
465 | + encoded_address = ephy_encode_for_html_entity (view->address); | ||
466 | + formatted_address = g_strdup_printf ("<strong>%s</strong>", encoded_address); | ||
467 | |||
468 | first_paragraph = g_strdup_printf (_("%s could not be found."), | ||
469 | - formatted_origin); | ||
470 | + formatted_address); | ||
471 | second_paragraph = g_strdup_printf (_("Please check the file name for " | ||
472 | "capitalization or other typing errors. Also check if " | ||
473 | "it has been moved, renamed, or deleted.")); | ||
474 | @@ -2109,19 +2111,19 @@ ephy_web_view_load_error_page (EphyWebVi | ||
475 | GError *error, | ||
476 | gpointer user_data) | ||
477 | { | ||
478 | - GBytes *html_file; | ||
479 | - GString *html = g_string_new (""); | ||
480 | - char *origin = NULL; | ||
481 | - char *lang = NULL; | ||
482 | - char *page_title = NULL; | ||
483 | - char *msg_title = NULL; | ||
484 | - char *msg_body = NULL; | ||
485 | - char *msg_details = NULL; | ||
486 | - char *button_label = NULL; | ||
487 | - char *hidden_button_label = NULL; | ||
488 | - char *button_action = NULL; | ||
489 | - char *hidden_button_action = NULL; | ||
490 | - char *style_sheet = NULL; | ||
491 | + g_autoptr (GBytes) html_file = NULL; | ||
492 | + g_autoptr (GString) html = g_string_new (NULL); | ||
493 | + g_autofree char *origin = NULL; | ||
494 | + g_autofree char *lang = NULL; | ||
495 | + g_autofree char *page_title = NULL; | ||
496 | + g_autofree char *msg_title = NULL; | ||
497 | + g_autofree char *msg_body = NULL; | ||
498 | + g_autofree char *msg_details = NULL; | ||
499 | + g_autofree char *button_label = NULL; | ||
500 | + g_autofree char *hidden_button_label = NULL; | ||
501 | + g_autofree char *button_action = NULL; | ||
502 | + g_autofree char *hidden_button_action = NULL; | ||
503 | + g_autofree char *style_sheet = NULL; | ||
504 | const char *button_accesskey = NULL; | ||
505 | const char *hidden_button_accesskey = NULL; | ||
506 | const char *icon_name = NULL; | ||
507 | @@ -2261,23 +2263,9 @@ ephy_web_view_load_error_page (EphyWebVi | ||
508 | button_accesskey, button_label); | ||
509 | #pragma GCC diagnostic pop | ||
510 | |||
511 | - g_bytes_unref (html_file); | ||
512 | - g_free (origin); | ||
513 | - g_free (lang); | ||
514 | - g_free (page_title); | ||
515 | - g_free (msg_title); | ||
516 | - g_free (msg_body); | ||
517 | - g_free (msg_details); | ||
518 | - g_free (button_label); | ||
519 | - g_free (button_action); | ||
520 | - g_free (hidden_button_label); | ||
521 | - g_free (hidden_button_action); | ||
522 | - g_free (style_sheet); | ||
523 | - | ||
524 | /* Make our history backend ignore the next page load, since it will be an error page. */ | ||
525 | ephy_web_view_freeze_history (view); | ||
526 | webkit_web_view_load_alternate_html (WEBKIT_WEB_VIEW (view), html->str, uri, 0); | ||
527 | - g_string_free (html, TRUE); | ||
528 | } | ||
529 | |||
530 | static gboolean | ||
531 | Index: epiphany-browser/lib/ephy-output-encoding.c | ||
532 | =================================================================== | ||
533 | --- /dev/null | ||
534 | +++ epiphany-browser/lib/ephy-output-encoding.c | ||
535 | @@ -0,0 +1,117 @@ | ||
536 | +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
537 | +/* | ||
538 | + * Copyright © Red Hat Inc. | ||
539 | + * | ||
540 | + * This file is part of Epiphany. | ||
541 | + * | ||
542 | + * Epiphany is free software: you can redistribute it and/or modify | ||
543 | + * it under the terms of the GNU General Public License as published by | ||
544 | + * the Free Software Foundation, either version 3 of the License, or | ||
545 | + * (at your option) any later version. | ||
546 | + * | ||
547 | + * Epiphany is distributed in the hope that it will be useful, | ||
548 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
549 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
550 | + * GNU General Public License for more details. | ||
551 | + * | ||
552 | + * You should have received a copy of the GNU General Public License | ||
553 | + * along with Epiphany. If not, see <http://www.gnu.org/licenses/>. | ||
554 | + */ | ||
555 | + | ||
556 | +#include "config.h" | ||
557 | +#include "ephy-output-encoding.h" | ||
558 | + | ||
559 | +#include <glib.h> | ||
560 | + | ||
561 | +#if !GLIB_CHECK_VERSION(2, 68, 0) | ||
562 | +static guint | ||
563 | +g_string_replace (GString *string, | ||
564 | + const gchar *find, | ||
565 | + const gchar *replace, | ||
566 | + guint limit) | ||
567 | +{ | ||
568 | + gsize f_len, r_len, pos; | ||
569 | + gchar *cur, *next; | ||
570 | + guint n = 0; | ||
571 | + | ||
572 | + g_return_val_if_fail (string != NULL, 0); | ||
573 | + g_return_val_if_fail (find != NULL, 0); | ||
574 | + g_return_val_if_fail (replace != NULL, 0); | ||
575 | + | ||
576 | + f_len = strlen (find); | ||
577 | + r_len = strlen (replace); | ||
578 | + cur = string->str; | ||
579 | + | ||
580 | + while ((next = strstr (cur, find)) != NULL) | ||
581 | + { | ||
582 | + pos = next - string->str; | ||
583 | + g_string_erase (string, pos, f_len); | ||
584 | + g_string_insert (string, pos, replace); | ||
585 | + cur = string->str + pos + r_len; | ||
586 | + n++; | ||
587 | + /* Only match the empty string once at any given position, to | ||
588 | + * avoid infinite loops */ | ||
589 | + if (f_len == 0) | ||
590 | + { | ||
591 | + if (cur[0] == '\0') | ||
592 | + break; | ||
593 | + else | ||
594 | + cur++; | ||
595 | + } | ||
596 | + if (n == limit) | ||
597 | + break; | ||
598 | + } | ||
599 | + | ||
600 | + return n; | ||
601 | +} | ||
602 | +#endif | ||
603 | + | ||
604 | +char * | ||
605 | +ephy_encode_for_html_entity (const char *input) | ||
606 | +{ | ||
607 | + GString *str = g_string_new (input); | ||
608 | + | ||
609 | + g_string_replace (str, "&", "&", 0); | ||
610 | + g_string_replace (str, "<", "<", 0); | ||
611 | + g_string_replace (str, ">", ">", 0); | ||
612 | + g_string_replace (str, "\"", """, 0); | ||
613 | + g_string_replace (str, "'", "'", 0); | ||
614 | + g_string_replace (str, "/", "/", 0); | ||
615 | + | ||
616 | + return g_string_free (str, FALSE); | ||
617 | +} | ||
618 | + | ||
619 | +static char * | ||
620 | +encode_all_except_alnum (const char *input, | ||
621 | + const char *format) | ||
622 | +{ | ||
623 | + GString *str; | ||
624 | + const char *c = input; | ||
625 | + | ||
626 | + if (!g_utf8_validate (input, -1, NULL)) | ||
627 | + return g_strdup (""); | ||
628 | + | ||
629 | + str = g_string_new (NULL); | ||
630 | + do { | ||
631 | + gunichar u = g_utf8_get_char (c); | ||
632 | + if (g_unichar_isalnum (u)) | ||
633 | + g_string_append_unichar (str, u); | ||
634 | + else | ||
635 | + g_string_append_printf (str, format, u); | ||
636 | + c = g_utf8_next_char (c); | ||
637 | + } while (*c); | ||
638 | + | ||
639 | + return g_string_free (str, FALSE); | ||
640 | +} | ||
641 | + | ||
642 | +char * | ||
643 | +ephy_encode_for_html_attribute (const char *input) | ||
644 | +{ | ||
645 | + return encode_all_except_alnum (input, "&#x%02x;"); | ||
646 | +} | ||
647 | + | ||
648 | +char * | ||
649 | +ephy_encode_for_javascript (const char *input) | ||
650 | +{ | ||
651 | + return encode_all_except_alnum (input, "\\u%04u;"); | ||
652 | +} | ||
653 | Index: epiphany-browser/lib/ephy-output-encoding.h | ||
654 | =================================================================== | ||
655 | --- /dev/null | ||
656 | +++ epiphany-browser/lib/ephy-output-encoding.h | ||
657 | @@ -0,0 +1,38 @@ | ||
658 | +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
659 | +/* | ||
660 | + * Copyright © 2021 Red Hat Inc. | ||
661 | + * | ||
662 | + * This file is part of Epiphany. | ||
663 | + * | ||
664 | + * Epiphany is free software: you can redistribute it and/or modify | ||
665 | + * it under the terms of the GNU General Public License as published by | ||
666 | + * the Free Software Foundation, either version 3 of the License, or | ||
667 | + * (at your option) any later version. | ||
668 | + * | ||
669 | + * Epiphany is distributed in the hope that it will be useful, | ||
670 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
671 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
672 | + * GNU General Public License for more details. | ||
673 | + * | ||
674 | + * You should have received a copy of the GNU General Public License | ||
675 | + * along with Epiphany. If not, see <http://www.gnu.org/licenses/>. | ||
676 | + */ | ||
677 | + | ||
678 | +#pragma once | ||
679 | + | ||
680 | +#include <glib.h> | ||
681 | + | ||
682 | +G_BEGIN_DECLS | ||
683 | + | ||
684 | +/* These functions implement the OWASP XSS prevention output encoding rules: | ||
685 | + * https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#output-encoding-rules-summary | ||
686 | + * | ||
687 | + * You must *carefully* read that document to safely inject untrusted data into | ||
688 | + * web content. Here be dragons. | ||
689 | + */ | ||
690 | + | ||
691 | +char *ephy_encode_for_html_entity (const char *input); | ||
692 | +char *ephy_encode_for_html_attribute (const char *input); | ||
693 | +char *ephy_encode_for_javascript (const char *input); | ||
694 | + | ||
695 | +G_END_DECLS | ||
696 | Index: epiphany-browser/lib/meson.build | ||
697 | =================================================================== | ||
698 | --- epiphany-browser.orig/lib/meson.build | ||
699 | +++ epiphany-browser/lib/meson.build | ||
700 | @@ -21,6 +21,7 @@ libephymisc_sources = [ | ||
701 | 'ephy-langs.c', | ||
702 | 'ephy-notification.c', | ||
703 | 'ephy-notification-container.c', | ||
704 | + 'ephy-output-encoding.c', | ||
705 | 'ephy-permissions-manager.c', | ||
706 | 'ephy-profile-utils.c', | ||
707 | 'ephy-search-engine-manager.c', | ||