|
| 1 | +From 65ebc5f7d91a98b96bb7730433722b4b235cc74b Mon Sep 17 00:00:00 2001 |
| 2 | +From: Philip Withnall < [email protected]> |
| 3 | +Date: Thu, 13 Nov 2025 18:27:22 +0000 |
| 4 | +Subject: [PATCH] gconvert: Error out if g_escape_uri_string() would overflow |
| 5 | +MIME-Version: 1.0 |
| 6 | +Content-Type: text/plain; charset=UTF-8 |
| 7 | +Content-Transfer-Encoding: 8bit |
| 8 | + |
| 9 | +If the string to escape contains a very large number of unacceptable |
| 10 | +characters (which would need escaping), the calculation of the length of |
| 11 | +the escaped string could overflow, leading to a potential write off the |
| 12 | +end of the newly allocated string. |
| 13 | + |
| 14 | +In addition to that, the number of unacceptable characters was counted |
| 15 | +in a signed integer, which would overflow to become negative, making it |
| 16 | +easier for an attacker to craft an input string which would cause an |
| 17 | +out-of-bounds write. |
| 18 | + |
| 19 | +Fix that by validating the allocation length, and using an unsigned |
| 20 | +integer to count the number of unacceptable characters. |
| 21 | + |
| 22 | +Spotted by treeplus. Thanks to the Sovereign Tech Resilience programme |
| 23 | +from the Sovereign Tech Agency. ID: #YWH-PGM9867-134 |
| 24 | + |
| 25 | +Signed-off-by: Philip Withnall < [email protected]> |
| 26 | + |
| 27 | +Fixes: #3827 |
| 28 | + |
| 29 | +Backport 2.86: Changed the translatable error message to re-use an |
| 30 | +existing translatable string, to avoid adding new translatable strings |
| 31 | +to a stable branch. The re-used string doesn’t perfectly match the |
| 32 | +error, but it’s good enough given that no users will ever see it. |
| 33 | + |
| 34 | +Signed-off-by: Azure Linux Security Servicing Account < [email protected]> |
| 35 | +Upstream-reference: https://gitlab.gnome.org/GNOME/glib/-/commit/9bcd65ba5fa1b92ff0fb8380faea335ccef56253.patch |
| 36 | +--- |
| 37 | + glib/gconvert.c | 36 +++++++++++++++++++++++++----------- |
| 38 | + 1 file changed, 25 insertions(+), 11 deletions(-) |
| 39 | + |
| 40 | +diff --git a/glib/gconvert.c b/glib/gconvert.c |
| 41 | +index 69bcc2f..d43631c 100644 |
| 42 | +--- a/glib/gconvert.c |
| 43 | ++++ b/glib/gconvert.c |
| 44 | +@@ -1428,8 +1428,9 @@ static const gchar hex[] = "0123456789ABCDEF"; |
| 45 | + /* Note: This escape function works on file: URIs, but if you want to |
| 46 | + * escape something else, please read RFC-2396 */ |
| 47 | + static gchar * |
| 48 | +-g_escape_uri_string (const gchar *string, |
| 49 | +- UnsafeCharacterSet mask) |
| 50 | ++g_escape_uri_string (const gchar *string, |
| 51 | ++ UnsafeCharacterSet mask, |
| 52 | ++ GError **error) |
| 53 | + { |
| 54 | + #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) |
| 55 | + |
| 56 | +@@ -1437,7 +1438,7 @@ g_escape_uri_string (const gchar *string, |
| 57 | + gchar *q; |
| 58 | + gchar *result; |
| 59 | + int c; |
| 60 | +- gint unacceptable; |
| 61 | ++ size_t unacceptable; |
| 62 | + UnsafeCharacterSet use_mask; |
| 63 | + |
| 64 | + g_return_val_if_fail (mask == UNSAFE_ALL |
| 65 | +@@ -1454,7 +1455,14 @@ g_escape_uri_string (const gchar *string, |
| 66 | + if (!ACCEPTABLE (c)) |
| 67 | + unacceptable++; |
| 68 | + } |
| 69 | +- |
| 70 | ++ |
| 71 | ++ if (unacceptable >= (G_MAXSIZE - (p - string)) / 2) |
| 72 | ++ { |
| 73 | ++ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI, |
| 74 | ++ _("Invalid hostname")); |
| 75 | ++ return NULL; |
| 76 | ++ } |
| 77 | ++ |
| 78 | + result = g_malloc (p - string + unacceptable * 2 + 1); |
| 79 | + |
| 80 | + use_mask = mask; |
| 81 | +@@ -1479,12 +1487,13 @@ g_escape_uri_string (const gchar *string, |
| 82 | + |
| 83 | + |
| 84 | + static gchar * |
| 85 | +-g_escape_file_uri (const gchar *hostname, |
| 86 | +- const gchar *pathname) |
| 87 | ++g_escape_file_uri (const gchar *hostname, |
| 88 | ++ const gchar *pathname, |
| 89 | ++ GError **error) |
| 90 | + { |
| 91 | + char *escaped_hostname = NULL; |
| 92 | +- char *escaped_path; |
| 93 | +- char *res; |
| 94 | ++ char *escaped_path = NULL; |
| 95 | ++ char *res = NULL; |
| 96 | + |
| 97 | + #ifdef G_OS_WIN32 |
| 98 | + char *p, *backslash; |
| 99 | +@@ -1505,10 +1514,14 @@ g_escape_file_uri (const gchar *hostname, |
| 100 | + |
| 101 | + if (hostname && *hostname != '\0') |
| 102 | + { |
| 103 | +- escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST); |
| 104 | ++ escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST, error); |
| 105 | ++ if (escaped_hostname == NULL) |
| 106 | ++ goto out; |
| 107 | + } |
| 108 | + |
| 109 | +- escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH); |
| 110 | ++ escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH, error); |
| 111 | ++ if (escaped_path == NULL) |
| 112 | ++ goto out; |
| 113 | + |
| 114 | + res = g_strconcat ("file://", |
| 115 | + (escaped_hostname) ? escaped_hostname : "", |
| 116 | +@@ -1516,6 +1529,7 @@ g_escape_file_uri (const gchar *hostname, |
| 117 | + escaped_path, |
| 118 | + NULL); |
| 119 | + |
| 120 | ++out: |
| 121 | + #ifdef G_OS_WIN32 |
| 122 | + g_free ((char *) pathname); |
| 123 | + #endif |
| 124 | +@@ -1849,7 +1863,7 @@ g_filename_to_uri (const gchar *filename, |
| 125 | + hostname = NULL; |
| 126 | + #endif |
| 127 | + |
| 128 | +- escaped_uri = g_escape_file_uri (hostname, filename); |
| 129 | ++ escaped_uri = g_escape_file_uri (hostname, filename, error); |
| 130 | + |
| 131 | + return escaped_uri; |
| 132 | + } |
| 133 | +-- |
| 134 | +2.45.4 |
| 135 | + |
0 commit comments