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