From b1d22b0cd1fe363ccce462d1a147b65283883b75 Mon Sep 17 00:00:00 2001
From: renwang <renwang@uniontech.com>
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 <nghttp2/nghttp2.h>', 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 <glib.h>
 #include <glib/gstdio.h>
 
 #include <stdio.h>
-#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 <gio/gio.h>
 #include "test-utils.h"
 
+#include <gio/gio.h>
 typedef struct {
 	const char *explanation;
 	const char *url;
-- 
2.20.1

