From f28340ee62c655487972ad3c632d231ee098fb7f Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 13 Nov 2025 18:27:22 +0000 Subject: [PATCH] gconvert: Error out if g_escape_uri_string() would overflow If the string to escape contains a very large number of unacceptable characters (which would need escaping), the calculation of the length of the escaped string could overflow, leading to a potential write off the end of the newly allocated string. In addition to that, the number of unacceptable characters was counted in a signed integer, which would overflow to become negative, making it easier for an attacker to craft an input string which would cause an out-of-bounds write. Fix that by validating the allocation length, and using an unsigned integer to count the number of unacceptable characters. Spotted by treeplus. Thanks to the Sovereign Tech Resilience programme from the Sovereign Tech Agency. ID: #YWH-PGM9867-134 Signed-off-by: Philip Withnall Fixes: #3827 --- glib/gconvert.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/glib/gconvert.c b/glib/gconvert.c index b066dd5a8..a02d2ea73 100644 --- a/glib/gconvert.c +++ b/glib/gconvert.c @@ -1336,8 +1336,9 @@ static const gchar hex[] = "0123456789ABCDEF"; /* Note: This escape function works on file: URIs, but if you want to * escape something else, please read RFC-2396 */ static gchar * -g_escape_uri_string (const gchar *string, - UnsafeCharacterSet mask) +g_escape_uri_string (const gchar *string, + UnsafeCharacterSet mask, + GError **error) { #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) @@ -1345,7 +1346,7 @@ g_escape_uri_string (const gchar *string, gchar *q; gchar *result; int c; - gint unacceptable; + size_t unacceptable; UnsafeCharacterSet use_mask; g_return_val_if_fail (mask == UNSAFE_ALL @@ -1362,7 +1363,14 @@ g_escape_uri_string (const gchar *string, if (!ACCEPTABLE (c)) unacceptable++; } - + + if (unacceptable >= (G_MAXSIZE - (p - string)) / 2) + { + g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI, + _("The URI is too long")); + return NULL; + } + result = g_malloc (p - string + unacceptable * 2 + 1); use_mask = mask; @@ -1387,12 +1395,13 @@ g_escape_uri_string (const gchar *string, static gchar * -g_escape_file_uri (const gchar *hostname, - const gchar *pathname) +g_escape_file_uri (const gchar *hostname, + const gchar *pathname, + GError **error) { char *escaped_hostname = NULL; - char *escaped_path; - char *res; + char *escaped_path = NULL; + char *res = NULL; #ifdef G_OS_WIN32 char *p, *backslash; @@ -1413,10 +1422,14 @@ g_escape_file_uri (const gchar *hostname, if (hostname && *hostname != '\0') { - escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST); + escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST, error); + if (escaped_hostname == NULL) + goto out; } - escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH); + escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH, error); + if (escaped_path == NULL) + goto out; res = g_strconcat ("file://", (escaped_hostname) ? escaped_hostname : "", @@ -1424,6 +1437,7 @@ g_escape_file_uri (const gchar *hostname, escaped_path, NULL); +out: #ifdef G_OS_WIN32 g_free ((char *) pathname); #endif @@ -1753,7 +1767,7 @@ g_filename_to_uri (const gchar *filename, hostname = NULL; #endif - escaped_uri = g_escape_file_uri (hostname, filename); + escaped_uri = g_escape_file_uri (hostname, filename, error); return escaped_uri; }