File libsoup-CVE-2026-1467.patch of Package libsoup.42965
Index: libsoup-3.4.4/libsoup/auth/soup-auth.c
===================================================================
--- libsoup-3.4.4.orig/libsoup/auth/soup-auth.c
+++ libsoup-3.4.4/libsoup/auth/soup-auth.c
@@ -647,7 +647,7 @@ GSList *
soup_auth_get_protection_space (SoupAuth *auth, GUri *source_uri)
{
g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
- g_return_val_if_fail (SOUP_URI_IS_VALID (source_uri), NULL);
+ g_return_val_if_fail (soup_uri_is_valid (source_uri), NULL);
GUri *source_uri_normalized = soup_uri_copy_with_normalized_flags (source_uri);
GSList *ret = SOUP_AUTH_GET_CLASS (auth)->get_protection_space (auth, source_uri_normalized);
Index: libsoup-3.4.4/libsoup/soup-message.c
===================================================================
--- libsoup-3.4.4.orig/libsoup/soup-message.c
+++ libsoup-3.4.4/libsoup/soup-message.c
@@ -976,7 +976,8 @@ soup_message_new (const char *method, co
uri = g_uri_parse (uri_string, SOUP_HTTP_URI_FLAGS, NULL);
if (!uri)
return NULL;
- if (!SOUP_URI_IS_VALID (uri)) {
+
+ if (!soup_uri_is_valid (uri)) {
g_uri_unref (uri);
return NULL;
}
@@ -999,7 +1000,7 @@ SoupMessage *
soup_message_new_from_uri (const char *method, GUri *uri)
{
g_return_val_if_fail (method != NULL, NULL);
- g_return_val_if_fail (SOUP_URI_IS_VALID (uri), NULL);
+ g_return_val_if_fail (soup_uri_is_valid (uri), NULL);
return g_object_new (SOUP_TYPE_MESSAGE,
"method", method,
@@ -1019,7 +1020,7 @@ soup_message_new_from_uri (const char *m
SoupMessage *
soup_message_new_options_ping (GUri *base_uri)
{
- g_return_val_if_fail (SOUP_URI_IS_VALID (base_uri), NULL);
+ g_return_val_if_fail (soup_uri_is_valid (base_uri), NULL);
return g_object_new (SOUP_TYPE_MESSAGE,
"method", SOUP_METHOD_OPTIONS,
@@ -2133,7 +2134,7 @@ soup_message_set_uri (SoupMessage *msg,
GUri *normalized_uri;
g_return_if_fail (SOUP_IS_MESSAGE (msg));
- g_return_if_fail (SOUP_URI_IS_VALID (uri));
+ g_return_if_fail (soup_uri_is_valid (uri));
priv = soup_message_get_instance_private (msg);
Index: libsoup-3.4.4/libsoup/soup-uri-utils-private.h
===================================================================
--- libsoup-3.4.4.orig/libsoup/soup-uri-utils-private.h
+++ libsoup-3.4.4/libsoup/soup-uri-utils-private.h
@@ -10,6 +10,8 @@
G_BEGIN_DECLS
+gboolean soup_uri_is_valid (GUri *uri);
+
gboolean soup_uri_is_http (GUri *uri);
gboolean soup_uri_is_https (GUri *uri);
@@ -28,6 +30,4 @@ GUri *soup_uri_copy_with_normaliz
char *soup_uri_get_host_for_headers (GUri *uri);
-#define SOUP_URI_IS_VALID(x) (x && g_uri_get_host(x) && g_uri_get_host(x)[0])
-
G_END_DECLS
Index: libsoup-3.4.4/libsoup/soup-uri-utils.c
===================================================================
--- libsoup-3.4.4.orig/libsoup/soup-uri-utils.c
+++ libsoup-3.4.4/libsoup/soup-uri-utils.c
@@ -236,6 +236,68 @@ soup_uri_host_equal (gconstpointer v1, g
return g_ascii_strcasecmp (one_host, two_host) == 0;
}
+static gboolean
+is_valid_character_for_host (char c)
+{
+ static const char forbidden_chars[] = { '\t', '\n', '\r', ' ', '#', '/', ':', '<', '>', '?', '@', '[', '\\', ']', '^', '|' };
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (forbidden_chars); ++i) {
+ if (c == forbidden_chars[i])
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+is_host_valid (const char* host)
+{
+ int i;
+ gboolean is_valid;
+ char *ascii_host = NULL;
+
+ if (!host || !host[0])
+ return FALSE;
+
+ if (g_hostname_is_non_ascii (host)) {
+
+
+ ascii_host = g_hostname_to_ascii (host);
+ if (!ascii_host)
+ return FALSE;
+
+ host = ascii_host;
+ }
+
+ if ((g_ascii_isdigit (host[0]) || strchr (host, ':')) && g_hostname_is_ip_address (host)) {
+ g_free (ascii_host);
+ return TRUE;
+ }
+
+ is_valid = TRUE;
+ for (i = 0; host[i] && is_valid; i++)
+ is_valid = is_valid_character_for_host (host[i]);
+
+ g_free (ascii_host);
+
+ return is_valid;
+}
+
+gboolean
+soup_uri_is_valid (GUri *uri)
+{
+ if (!uri)
+ return FALSE;
+
+ if (!is_host_valid (g_uri_get_host (uri)))
+ return FALSE;
+
+ /* FIXME: validate other URI components? */
+
+ return TRUE;
+}
+
gboolean
soup_uri_is_https (GUri *uri)
{
Index: libsoup-3.4.4/tests/uri-parsing-test.c
===================================================================
--- libsoup-3.4.4.orig/tests/uri-parsing-test.c
+++ libsoup-3.4.4/tests/uri-parsing-test.c
@@ -126,6 +126,51 @@ do_copy_tests (void)
g_uri_unref (uri2);
}
+static struct {
+ const char *scheme;
+ const char *host;
+ const char *as_string;
+ gboolean valid;
+} valid_tests[] = {
+ { "http", "example.com", "http://example.com/", TRUE },
+ { "http", "localhost", "http://localhost/", TRUE },
+ { "http", "127.0.0.1", "http://127.0.0.1/", TRUE },
+ { "http", "::1", "http://[::1]/", TRUE },
+ { "http", "::192.168.0.10", "http://[::192.168.0.10]/", TRUE },
+ { "http", "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/", TRUE },
+ { "http", "\xe4\xbe\x8b\xe5\xad\x90.\xe6\xb5\x8b\xe8\xaf\x95", "http://\xe4\xbe\x8b\xe5\xad\x90.\xe6\xb5\x8b\xe8\xaf\x95/", TRUE },
+ { "http", "012x:4567:89AB:cdef:3210:7654:ba98:FeDc", "http://012x:4567:89AB:cdef:3210:7654:ba98:FeDc/", FALSE },
+ { "http", "\texample.com", "http://\texample.com/", FALSE },
+ { "http", "example.com\n", "http://example.com\n/", FALSE },
+ { "http", "\r\nexample.com", "http://\r\nexample.com/", FALSE },
+ { "http", "example .com", "http://example .com/", FALSE },
+ { "http", "example:com", "http://example:com/", FALSE },
+ { "http", "exampl<e>.com", "http://exampl<e>.com/", FALSE },
+ { "http", "exampl[e].com", "http://exampl[e].com/", FALSE },
+ { "http", "exampl^e.com", "http://exampl^e.com/", FALSE },
+ { "http", "examp|e.com", "http://examp|e.com/", FALSE },
+};
+
+static void
+do_valid_tests (void)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (valid_tests); ++i) {
+ GUri *uri;
+ char *uri_str;
+
+ uri = g_uri_build (SOUP_HTTP_URI_FLAGS | G_URI_FLAGS_ENCODED, valid_tests[i].scheme, NULL, valid_tests[i].host, -1, "", NULL, NULL);
+ uri_str = g_uri_to_string (uri);
+
+ g_assert_cmpstr (uri_str, ==, valid_tests[i].as_string);
+ g_assert_true (soup_uri_is_valid (uri) == valid_tests[i].valid);
+
+ g_free (uri_str);
+ g_uri_unref (uri);
+ }
+}
+
#define CONTENT_TYPE_DEFAULT "text/plain;charset=US-ASCII"
static struct {
@@ -204,6 +249,7 @@ main (int argc, char **argv)
g_test_add_func ("/uri/equality", do_equality_tests);
g_test_add_func ("/uri/copy", do_copy_tests);
+ g_test_add_func ("/uri/valid", do_valid_tests);
g_test_add_func ("/data", do_data_uri_tests);
g_test_add_func ("/path_and_query", do_path_and_query_tests);