From bbeb7d59f98d0073291ca4a7ee9ce1a946842734 Mon Sep 17 00:00:00 2001 From: Patrick Griffis Date: Tue, 27 Aug 2024 13:53:26 -0500 Subject: [PATCH] headers: Be more robust against invalid input when parsing params If you pass invalid input to a function such as soup_header_parse_param_list_strict() it can cause an overflow if it decodes the input to UTF-8. This should never happen with valid UTF-8 input which libsoup's client API ensures, however it's server API does not currently. --- libsoup/soup-headers.c | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c index 271d2a63..8657483f 100644 --- a/libsoup/soup-headers.c +++ b/libsoup/soup-headers.c @@ -650,8 +650,9 @@ soup_header_contains (const char *header, const char *token) } static void -decode_quoted_string (char *quoted_string) +decode_quoted_string_inplace (GString *quoted_gstring) { + char *quoted_string = quoted_gstring->str; char *src, *dst; src = quoted_string + 1; @@ -665,10 +666,11 @@ decode_quoted_string (char *quoted_string) } static gboolean -decode_rfc5987 (char *encoded_string) +decode_rfc5987_inplace (GString *encoded_gstring) { char *q, *decoded; gboolean iso_8859_1 = FALSE; + const char *encoded_string = encoded_gstring->str; q = strchr (encoded_string, '\''); if (!q) @@ -697,14 +699,7 @@ decode_rfc5987 (char *encoded_string) decoded = utf8; } - /* If encoded_string was UTF-8, then each 3-character %-escape - * will be converted to a single byte, and so decoded is - * shorter than encoded_string. If encoded_string was - * iso-8859-1, then each 3-character %-escape will be - * converted into at most 2 bytes in UTF-8, and so it's still - * shorter. - */ - strcpy (encoded_string, decoded); + g_string_assign (encoded_gstring, decoded); g_free (decoded); return TRUE; } @@ -714,15 +709,17 @@ parse_param_list (const char *header, char delim) { GHashTable *params; GSList *list, *iter; - char *item, *eq, *name_end, *value; - gboolean override; params = g_hash_table_new_full (soup_str_case_hash, soup_str_case_equal, - g_free, NULL); + g_free, g_free); list = parse_list (header, delim); for (iter = list; iter; iter = iter->next) { + char *item, *eq, *name_end; + gboolean override, duplicated; + GString *parsed_value = NULL; + item = iter->data; override = FALSE; @@ -737,24 +734,27 @@ parse_param_list (const char *header, char delim) *name_end = '\0'; - value = (char *)skip_lws (eq + 1); + parsed_value = g_string_new ((char *)skip_lws (eq + 1)); if (name_end[-1] == '*' && name_end > item + 1) { name_end[-1] = '\0'; - if (!decode_rfc5987 (value)) { + if (!decode_rfc5987_inplace (parsed_value)) { + g_string_free (parsed_value, TRUE); g_free (item); continue; } override = TRUE; - } else if (*value == '"') - decode_quoted_string (value); - } else - value = NULL; - - if (override || !g_hash_table_lookup (params, item)) - g_hash_table_replace (params, item, value); - else + } else if (parsed_value->str[0] == '"') + decode_quoted_string_inplace (parsed_value); + } + + if (override || !g_hash_table_lookup (params, item)) { + g_hash_table_replace (params, item, parsed_value ? g_string_free (parsed_value, FALSE) : NULL); + } else { + if (parsed_value) + g_string_free (parsed_value, TRUE); g_free (item); + } } g_slist_free (list); -- 2.48.1