diff --git a/backport-CVE-2024-52531.patch b/backport-CVE-2024-52531.patch new file mode 100644 index 0000000000000000000000000000000000000000..8864fd2e39b9f1460e0ef89b586e0b04c7a9a7e9 --- /dev/null +++ b/backport-CVE-2024-52531.patch @@ -0,0 +1,285 @@ +From b1d22b0cd1fe363ccce462d1a147b65283883b75 Mon Sep 17 00:00:00 2001 +From: renwang +Date: Thu, 12 Dec 2024 11:21:48 +0800 +Subject: [PATCH] change + +--- + fuzzing/fuzz.h | 8 ++++++- + fuzzing/fuzz_header_parsing.c | 19 +++++++++++++++ + fuzzing/fuzz_header_parsing.dict | 8 +++++++ + fuzzing/meson.build | 2 ++ + libsoup/soup-headers.c | 40 ++++++++++++++++++++------------ + meson.build | 3 +++ + tests/header-parsing-test.c | 12 +++++++++- + tests/hsts-db-test.c | 3 ++- + tests/proxy-test.c | 2 +- + 9 files changed, 78 insertions(+), 19 deletions(-) + create mode 100644 fuzzing/fuzz_header_parsing.c + create mode 100644 fuzzing/fuzz_header_parsing.dict + +diff --git a/fuzzing/fuzz.h b/fuzzing/fuzz.h +index 0d38028..8ec48f3 100644 +--- a/fuzzing/fuzz.h ++++ b/fuzzing/fuzz.h +@@ -1,6 +1,7 @@ + #include "libsoup/soup.h" + + int LLVMFuzzerTestOneInput (const unsigned char *data, size_t size); ++static int set_logger = 0; + + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + static GLogWriterOutput +@@ -16,6 +17,11 @@ static void + fuzz_set_logging_func (void) + { + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +- g_log_set_writer_func (empty_logging_func, NULL, NULL); ++ if(!set_logger) ++ { ++ set_logger = 1; ++ g_log_set_writer_func (empty_logging_func, NULL, NULL); ++ ++ } + #endif + } +diff --git a/fuzzing/fuzz_header_parsing.c b/fuzzing/fuzz_header_parsing.c +new file mode 100644 +index 0000000..a8e5c1f +--- /dev/null ++++ b/fuzzing/fuzz_header_parsing.c +@@ -0,0 +1,19 @@ ++#include "fuzz.h" ++ ++int ++LLVMFuzzerTestOneInput (const unsigned char *data, size_t size) ++{ ++ GHashTable *elements; ++ ++ // We only accept NUL terminated strings ++ if (!size || data[size - 1] != '\0') ++ return 0; ++ ++ fuzz_set_logging_func (); ++ ++ elements = soup_header_parse_param_list((char*)data); ++ ++ g_hash_table_unref(elements); ++ ++ return 0; ++} +\ No newline at end of file +diff --git a/fuzzing/fuzz_header_parsing.dict b/fuzzing/fuzz_header_parsing.dict +new file mode 100644 +index 0000000..1562ca3 +--- /dev/null ++++ b/fuzzing/fuzz_header_parsing.dict +@@ -0,0 +1,8 @@ ++"*=UTF-8''" ++"*=iso-8859-1''" ++"'" ++"''" ++"=" ++"*=" ++""" ++";" +\ No newline at end of file +diff --git a/fuzzing/meson.build b/fuzzing/meson.build +index b14cbb5..5dd0f41 100644 +--- a/fuzzing/meson.build ++++ b/fuzzing/meson.build +@@ -5,6 +5,7 @@ fuzz_targets = [ + 'fuzz_cookie_parse', + 'fuzz_content_sniffer', + 'fuzz_date_time', ++ 'fuzz_header_parsing', + ] + + fuzzing_args = '-fsanitize=fuzzer,address,undefined' +@@ -34,6 +35,7 @@ if have_fuzzing and (fuzzing_feature.enabled() or fuzzing_feature.auto()) + '-runs=200000', + '-artifact_prefix=meson-logs/' + target + '-', + '-print_final_stats=1', ++ '-max_len=4096', + ] + extra_args, + env: [ + 'ASAN_OPTIONS=fast_unwind_on_malloc=0', +diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c +index f30ee46..79320e3 100644 +--- a/libsoup/soup-headers.c ++++ b/libsoup/soup-headers.c +@@ -646,8 +646,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; +@@ -661,10 +662,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) +@@ -703,7 +705,7 @@ decode_rfc5987 (char *encoded_string) + * 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; + } +@@ -713,15 +715,18 @@ parse_param_list (const char *header, char delim, gboolean strict) + { + GHashTable *params; + GSList *list, *iter; +- char *item, *eq, *name_end, *value; +- gboolean override, duplicated; ++ + + 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; + +@@ -736,19 +741,19 @@ parse_param_list (const char *header, char delim, gboolean strict) + + *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; ++ } else if (parsed_value->str[0] == '"') ++ decode_quoted_string_inplace (parsed_value); ++ } + + duplicated = g_hash_table_lookup_extended (params, item, NULL, NULL); + +@@ -756,11 +761,16 @@ parse_param_list (const char *header, char delim, gboolean strict) + soup_header_free_param_list (params); + params = NULL; + g_slist_foreach (iter, (GFunc)g_free, NULL); ++ if (parsed_value) ++ g_string_free (parsed_value, TRUE); + break; +- } else if (override || !duplicated) +- g_hash_table_replace (params, item, value); +- else ++ } else if (override || !duplicated) { ++ 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); +diff --git a/meson.build b/meson.build +index 73a9fa0..3a5d354 100644 +--- a/meson.build ++++ b/meson.build +@@ -112,6 +112,9 @@ glib_deps = [glib_dep, gmodule_dep, gobject_dep, gio_dep] + + cdata = configuration_data() + ++cdata.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_70') ++cdata.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_70') ++ + libnghttp2_dep = dependency('libnghttp2') + if (libnghttp2_dep.version() == 'unknown' and (libnghttp2_dep.type_name() == 'internal' or cc.has_function('nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation', prefix : '#include ', dependencies : libnghttp2_dep))) or libnghttp2_dep.version().version_compare('>=1.50') + cdata.set('HAVE_NGHTTP2_OPTION_SET_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION', '1') +diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c +index 715c2c6..9d85705 100644 +--- a/tests/header-parsing-test.c ++++ b/tests/header-parsing-test.c +@@ -818,13 +818,23 @@ static struct ParamListTest { + { "filename", "filename.jpg" }, + }, + }, +- + { FALSE, + "attachment; filename*=UTF-8''t%C3%A9st.txt; filename=\"test.txt\"", + { { "attachment", NULL }, + { "filename", "t\xC3\xA9st.txt" }, + }, + }, ++ ++ /* This tests invalid UTF-8 data which *should* never be passed here but it was designed to be robust against it. */ ++ { TRUE, ++ "invalid*=\x69\x27\x27\x93\x93\x93\x93\xff\x61\x61\x61\x61\x61\x61\x61\x62\x63\x64\x65\x0a; filename*=iso-8859-1''\x69\x27\x27\x93\x93\x93\x93\xff\x61\x61\x61\x61\x61\x61\x61\x62\x63\x64\x65\x0a; foo", ++ { ++ { "filename", "i''\302\223\302\223\302\223\302\223\303\277aaaaaaabcde" }, ++ { "invalid", "\302\223\302\223\302\223\302\223\303\277aaaaaaabcde" }, ++ { "foo", NULL }, ++ ++ }, ++ } + }; + static const int num_paramlisttests = G_N_ELEMENTS (paramlisttests); + +diff --git a/tests/hsts-db-test.c b/tests/hsts-db-test.c +index 1149a04..04d7c4f 100644 +--- a/tests/hsts-db-test.c ++++ b/tests/hsts-db-test.c +@@ -1,8 +1,9 @@ ++#include "test-utils.h" ++ + #include + #include + + #include +-#include "test-utils.h" + #include "soup-uri-utils-private.h" + + #define DB_FILE "hsts-db.sqlite" +diff --git a/tests/proxy-test.c b/tests/proxy-test.c +index ec03936..1125dad 100644 +--- a/tests/proxy-test.c ++++ b/tests/proxy-test.c +@@ -1,8 +1,8 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ + +-#include + #include "test-utils.h" + ++#include + typedef struct { + const char *explanation; + const char *url; +-- +2.20.1 + diff --git a/libsoup3.spec b/libsoup3.spec index cedf1d501f3bef9ad104ee2c032593cea4495e88..15249607cfaa577202df2ed76ebbbd9032bac2e2 100644 --- a/libsoup3.spec +++ b/libsoup3.spec @@ -4,7 +4,7 @@ Name: libsoup3 Version: 3.4.4 -Release: 4 +Release: 5 Summary: Soup, an HTTP library implementation License: LGPL-2.0-or-later URL: https://wiki.gnome.org/Projects/libsoup @@ -12,6 +12,7 @@ Source0: https://download.gnome.org/sources/libsoup/3.4/libsoup-%{version} Patch0001: 0001-websocket-process-the-frame-as-soon-as-we-read-data.patch Patch0002: backport-CVE-2024-52530.patch +Patch0003: backport-CVE-2024-52531.patch BuildRequires: gcc gettext vala krb5-devel samba-winbind-clients BuildRequires: meson >= 0.54 @@ -87,6 +88,12 @@ install -m 644 -D tests/libsoup.supp %{buildroot}%{_datadir}/libsoup-3.0/libsoup %{_datadir}/doc %changelog +* Fri Dec 20 2024 renwang - 3.4.4-5 +- Type:CVE +- ID:CVE-2024-52531 +- SUG:NA +- DESC: fix CVE-2024-52531 + * Fri Nov 22 2024 Han Jinpeng - 3.4.4-4 - Type:CVE - ID:CVE-2024-52530