Update to 3.6.6
Also, add fixes for CVE-2026-4271 and CVE-2026-5119. Resolves: RHEL-151634 Resolves: RHEL-159788 Resolves: RHEL-167775
This commit is contained in:
parent
2eb78ac576
commit
0080cb6c4b
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,3 +19,4 @@
|
||||
/libsoup-3.6.1.tar.xz
|
||||
/libsoup-3.6.3.tar.xz
|
||||
/libsoup-3.6.5.tar.xz
|
||||
/libsoup-3.6.6.tar.xz
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From 9ba1243a24e442fa5ec44684617a4480027da960 Mon Sep 17 00:00:00 2001
|
||||
From: Eugene Mutavchi <Ievgen_Mutavchi@comcast.com>
|
||||
Date: Fri, 10 Oct 2025 16:24:27 +0000
|
||||
Subject: [PATCH] fix 'heap-use-after-free' caused by 'finishing' queue item
|
||||
twice
|
||||
|
||||
---
|
||||
libsoup/soup-session.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
|
||||
index c5694d2c..4e6b478b 100644
|
||||
--- a/libsoup/soup-session.c
|
||||
+++ b/libsoup/soup-session.c
|
||||
@@ -2894,8 +2894,10 @@ run_until_read_done (SoupMessage *msg,
|
||||
if (soup_message_io_in_progress (msg))
|
||||
soup_message_io_finished (msg);
|
||||
item->paused = FALSE;
|
||||
- item->state = SOUP_MESSAGE_FINISHING;
|
||||
- soup_session_process_queue_item (item->session, item, FALSE);
|
||||
+ if (item->state != SOUP_MESSAGE_FINISHED) {
|
||||
+ item->state = SOUP_MESSAGE_FINISHING;
|
||||
+ soup_session_process_queue_item (item->session, item, FALSE);
|
||||
+ }
|
||||
}
|
||||
async_send_request_return_result (item, NULL, error);
|
||||
soup_message_queue_item_unref (item);
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,695 +0,0 @@
|
||||
From 3c975f8d53df061538f865edfe35f9dd4b3e2f80 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||
Date: Wed, 7 Jan 2026 14:50:33 -0600
|
||||
Subject: [PATCH] Reject duplicate Host headers
|
||||
|
||||
RFC 9112 section 3.2 says:
|
||||
|
||||
A server MUST respond with a 400 (Bad Request) status code to any
|
||||
HTTP/1.1 request message that lacks a Host header field and to any
|
||||
request message that contains more than one Host header field line or a
|
||||
Host header field with an invalid field value.
|
||||
|
||||
In addition to rejecting a duplicate header when parsing headers, also
|
||||
reject attempts to add the duplicate header using the
|
||||
soup_message_headers_append() API, and add tests for both cases.
|
||||
|
||||
These checks will also apply to HTTP/2. I'm not sure whether this is
|
||||
actually desired or not, but the header processing code is not aware of
|
||||
which HTTP version is in use.
|
||||
|
||||
(Note that while SoupMessageHeaders does not require the Host header to
|
||||
be present in an HTTP/1.1 request, SoupServer itself does. So we can't
|
||||
test the case of missing Host header via the header parsing test, but it
|
||||
really is enforced.)
|
||||
|
||||
Fixes #472
|
||||
---
|
||||
libsoup/soup-headers.c | 3 +-
|
||||
libsoup/soup-message-headers-private.h | 4 +-
|
||||
libsoup/soup-message-headers.c | 78 +++++++++------
|
||||
tests/header-parsing-test.c | 133 ++++++++++++++++---------
|
||||
4 files changed, 137 insertions(+), 81 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
|
||||
index 52ef2ece..9dcffbf2 100644
|
||||
--- a/libsoup/soup-headers.c
|
||||
+++ b/libsoup/soup-headers.c
|
||||
@@ -139,7 +139,8 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest)
|
||||
for (p = strchr (value, '\r'); p; p = strchr (p, '\r'))
|
||||
*p = ' ';
|
||||
|
||||
- soup_message_headers_append_untrusted_data (dest, name, value);
|
||||
+ if (!soup_message_headers_append_untrusted_data (dest, name, value))
|
||||
+ goto done;
|
||||
}
|
||||
success = TRUE;
|
||||
|
||||
diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h
|
||||
index 98154645..770f3ef1 100644
|
||||
--- a/libsoup/soup-message-headers-private.h
|
||||
+++ b/libsoup/soup-message-headers-private.h
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
-void soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs,
|
||||
+gboolean soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs,
|
||||
const char *name,
|
||||
const char *value);
|
||||
-void soup_message_headers_append_common (SoupMessageHeaders *hdrs,
|
||||
+gboolean soup_message_headers_append_common (SoupMessageHeaders *hdrs,
|
||||
SoupHeaderName name,
|
||||
const char *value);
|
||||
const char *soup_message_headers_get_one_common (SoupMessageHeaders *hdrs,
|
||||
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
|
||||
index f101d4b4..b0d5828f 100644
|
||||
--- a/libsoup/soup-message-headers.c
|
||||
+++ b/libsoup/soup-message-headers.c
|
||||
@@ -273,12 +273,16 @@ soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs)
|
||||
soup_header_free_list (tokens);
|
||||
}
|
||||
|
||||
-void
|
||||
+gboolean
|
||||
soup_message_headers_append_common (SoupMessageHeaders *hdrs,
|
||||
SoupHeaderName name,
|
||||
const char *value)
|
||||
{
|
||||
SoupCommonHeader header;
|
||||
+ if (name == SOUP_HEADER_HOST && soup_message_headers_get_one (hdrs, "Host")) {
|
||||
+ g_warning ("Attempted to add duplicate Host header to a SoupMessageHeaders that already contains a Host header");
|
||||
+ return FALSE;
|
||||
+ }
|
||||
|
||||
if (!hdrs->common_headers)
|
||||
hdrs->common_headers = g_array_sized_new (FALSE, FALSE, sizeof (SoupCommonHeader), 6);
|
||||
@@ -290,33 +294,19 @@ soup_message_headers_append_common (SoupMessageHeaders *hdrs,
|
||||
g_hash_table_remove (hdrs->common_concat, GUINT_TO_POINTER (header.name));
|
||||
|
||||
soup_message_headers_set (hdrs, name, value);
|
||||
+ return TRUE;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * soup_message_headers_append:
|
||||
- * @hdrs: a #SoupMessageHeaders
|
||||
- * @name: the header name to add
|
||||
- * @value: the new value of @name
|
||||
- *
|
||||
- * Appends a new header with name @name and value @value to @hdrs.
|
||||
- *
|
||||
- * (If there is an existing header with name @name, then this creates a second
|
||||
- * one, which is only allowed for list-valued headers; see also
|
||||
- * [method@MessageHeaders.replace].)
|
||||
- *
|
||||
- * The caller is expected to make sure that @name and @value are
|
||||
- * syntactically correct.
|
||||
- **/
|
||||
-void
|
||||
-soup_message_headers_append (SoupMessageHeaders *hdrs,
|
||||
- const char *name, const char *value)
|
||||
+static gboolean
|
||||
+soup_message_headers_append_internal (SoupMessageHeaders *hdrs,
|
||||
+ const char *name, const char *value)
|
||||
{
|
||||
SoupUncommonHeader header;
|
||||
SoupHeaderName header_name;
|
||||
|
||||
- g_return_if_fail (hdrs);
|
||||
- g_return_if_fail (name != NULL);
|
||||
- g_return_if_fail (value != NULL);
|
||||
+ g_return_val_if_fail (hdrs, FALSE);
|
||||
+ g_return_val_if_fail (name != NULL, FALSE);
|
||||
+ g_return_val_if_fail (value != NULL, FALSE);
|
||||
|
||||
/* Setting a syntactically invalid header name or value is
|
||||
* considered to be a programming error. However, it can also
|
||||
@@ -324,23 +314,22 @@ soup_message_headers_append (SoupMessageHeaders *hdrs,
|
||||
* compiled with G_DISABLE_CHECKS.
|
||||
*/
|
||||
#ifndef G_DISABLE_CHECKS
|
||||
- g_return_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL);
|
||||
- g_return_if_fail (strpbrk (value, "\r\n") == NULL);
|
||||
+ g_return_val_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL, FALSE);
|
||||
+ g_return_val_if_fail (strpbrk (value, "\r\n") == NULL, FALSE);
|
||||
#else
|
||||
if (*name && strpbrk (name, " \t\r\n:")) {
|
||||
g_warning ("soup_message_headers_append: Ignoring bad name '%s'", name);
|
||||
- return;
|
||||
+ return FALSE;
|
||||
}
|
||||
if (strpbrk (value, "\r\n")) {
|
||||
g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value);
|
||||
- return;
|
||||
+ return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
header_name = soup_header_name_from_string (name);
|
||||
if (header_name != SOUP_HEADER_UNKNOWN) {
|
||||
- soup_message_headers_append_common (hdrs, header_name, value);
|
||||
- return;
|
||||
+ return soup_message_headers_append_common (hdrs, header_name, value);
|
||||
}
|
||||
|
||||
if (!hdrs->uncommon_headers)
|
||||
@@ -351,21 +340,48 @@ soup_message_headers_append (SoupMessageHeaders *hdrs,
|
||||
g_array_append_val (hdrs->uncommon_headers, header);
|
||||
if (hdrs->uncommon_concat)
|
||||
g_hash_table_remove (hdrs->uncommon_concat, header.name);
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * soup_message_headers_append:
|
||||
+ * @hdrs: a #SoupMessageHeaders
|
||||
+ * @name: the header name to add
|
||||
+ * @value: the new value of @name
|
||||
+ *
|
||||
+ * Appends a new header with name @name and value @value to @hdrs.
|
||||
+ *
|
||||
+ * (If there is an existing header with name @name, then this creates a second
|
||||
+ * one, which is only allowed for list-valued headers; see also
|
||||
+ * [method@MessageHeaders.replace].)
|
||||
+ *
|
||||
+ * The caller is expected to make sure that @name and @value are
|
||||
+ * syntactically correct.
|
||||
+ **/
|
||||
+void
|
||||
+soup_message_headers_append (SoupMessageHeaders *hdrs,
|
||||
+ const char *name, const char *value)
|
||||
+{
|
||||
+ soup_message_headers_append_internal (hdrs, name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
- * Appends a header value ensuring that it is valid UTF8.
|
||||
+ * Appends a header value ensuring that it is valid UTF-8, and also checking the
|
||||
+ * return value of soup_message_headers_append_internal() to report whether the
|
||||
+ * headers are invalid for various other reasons.
|
||||
*/
|
||||
-void
|
||||
+gboolean
|
||||
soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs,
|
||||
const char *name,
|
||||
const char *value)
|
||||
{
|
||||
char *safe_value = g_utf8_make_valid (value, -1);
|
||||
char *safe_name = g_utf8_make_valid (name, -1);
|
||||
- soup_message_headers_append (hdrs, safe_name, safe_value);
|
||||
+ gboolean result = soup_message_headers_append_internal (hdrs, safe_name, safe_value);
|
||||
+
|
||||
g_free (safe_value);
|
||||
g_free (safe_name);
|
||||
+ return result;
|
||||
}
|
||||
|
||||
void
|
||||
diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c
|
||||
index 4faafbd6..ea42d5e6 100644
|
||||
--- a/tests/header-parsing-test.c
|
||||
+++ b/tests/header-parsing-test.c
|
||||
@@ -24,6 +24,7 @@ static struct RequestTest {
|
||||
const char *method, *path;
|
||||
SoupHTTPVersion version;
|
||||
Header headers[10];
|
||||
+ GLogLevelFlags log_flags;
|
||||
} reqtests[] = {
|
||||
/**********************/
|
||||
/*** VALID REQUESTS ***/
|
||||
@@ -33,7 +34,7 @@ static struct RequestTest {
|
||||
"GET / HTTP/1.0\r\n", -1,
|
||||
SOUP_STATUS_OK,
|
||||
"GET", "/", SOUP_HTTP_1_0,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 1 header", NULL,
|
||||
@@ -42,7 +43,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "example.com" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 1 header, no leading whitespace", NULL,
|
||||
@@ -51,7 +52,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "example.com" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 1 header including trailing whitespace", NULL,
|
||||
@@ -60,7 +61,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "example.com" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 1 header, wrapped", NULL,
|
||||
@@ -69,7 +70,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Foo", "bar baz" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 1 header, wrapped with additional whitespace", NULL,
|
||||
@@ -78,7 +79,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Foo", "bar baz" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 1 header, wrapped with tab", NULL,
|
||||
@@ -87,7 +88,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Foo", "bar baz" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 1 header, wrapped before value", NULL,
|
||||
@@ -96,7 +97,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Foo", "bar baz" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 1 header with empty value", NULL,
|
||||
@@ -105,7 +106,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 2 headers", NULL,
|
||||
@@ -115,7 +116,7 @@ static struct RequestTest {
|
||||
{ { "Host", "example.com" },
|
||||
{ "Connection", "close" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 3 headers", NULL,
|
||||
@@ -126,7 +127,7 @@ static struct RequestTest {
|
||||
{ "Connection", "close" },
|
||||
{ "Blah", "blah" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 3 headers, 1st wrapped", NULL,
|
||||
@@ -137,7 +138,7 @@ static struct RequestTest {
|
||||
{ "Foo", "bar baz" },
|
||||
{ "Blah", "blah" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 3 headers, 2nd wrapped", NULL,
|
||||
@@ -148,7 +149,7 @@ static struct RequestTest {
|
||||
{ "Blah", "blah" },
|
||||
{ "Foo", "bar baz" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ 3 headers, 3rd wrapped", NULL,
|
||||
@@ -159,7 +160,7 @@ static struct RequestTest {
|
||||
{ "Blah", "blah" },
|
||||
{ "Foo", "bar baz" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ same header multiple times", NULL,
|
||||
@@ -168,7 +169,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Foo", "bar, baz, quux" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Connection header on HTTP/1.0 message", NULL,
|
||||
@@ -178,21 +179,21 @@ static struct RequestTest {
|
||||
{ { "Connection", "Bar, Quux" },
|
||||
{ "Foo", "bar" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "GET with full URI", "667637",
|
||||
"GET http://example.com HTTP/1.1\r\n", -1,
|
||||
SOUP_STATUS_OK,
|
||||
"GET", "http://example.com", SOUP_HTTP_1_1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "GET with full URI in upper-case", "667637",
|
||||
"GET HTTP://example.com HTTP/1.1\r\n", -1,
|
||||
SOUP_STATUS_OK,
|
||||
"GET", "HTTP://example.com", SOUP_HTTP_1_1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
/* It's better for this to be passed through: this means a SoupServer
|
||||
@@ -202,7 +203,7 @@ static struct RequestTest {
|
||||
"GET AbOuT: HTTP/1.1\r\n", -1,
|
||||
SOUP_STATUS_OK,
|
||||
"GET", "AbOuT:", SOUP_HTTP_1_1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
/****************************/
|
||||
@@ -217,7 +218,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "example.com" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
/* RFC 2616 section 3.1 says we MUST accept this */
|
||||
@@ -228,7 +229,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "example.com" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
/* RFC 2616 section 19.3 says we SHOULD accept these */
|
||||
@@ -240,7 +241,7 @@ static struct RequestTest {
|
||||
{ { "Host", "example.com" },
|
||||
{ "Connection", "close" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "LF instead of CRLF after Request-Line", NULL,
|
||||
@@ -249,7 +250,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "example.com" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Mixed CRLF/LF", "666316",
|
||||
@@ -261,7 +262,7 @@ static struct RequestTest {
|
||||
{ "e", "f" },
|
||||
{ "g", "h" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ incorrect whitespace in Request-Line", NULL,
|
||||
@@ -270,7 +271,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "example.com" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Req w/ incorrect whitespace after Request-Line", "475169",
|
||||
@@ -279,7 +280,7 @@ static struct RequestTest {
|
||||
"GET", "/", SOUP_HTTP_1_1,
|
||||
{ { "Host", "example.com" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
/* If the request/status line is parseable, then we
|
||||
@@ -293,7 +294,7 @@ static struct RequestTest {
|
||||
{ { "Host", "example.com" },
|
||||
{ "Bar", "two" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "First header line is continuation", "666316",
|
||||
@@ -303,7 +304,7 @@ static struct RequestTest {
|
||||
{ { "Host", "example.com" },
|
||||
{ "c", "d" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Zero-length header name", "666316",
|
||||
@@ -313,7 +314,7 @@ static struct RequestTest {
|
||||
{ { "a", "b" },
|
||||
{ "c", "d" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "CR in header name", "666316",
|
||||
@@ -323,7 +324,7 @@ static struct RequestTest {
|
||||
{ { "a", "b" },
|
||||
{ "c", "d" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "CR in header value", "666316",
|
||||
@@ -336,7 +337,7 @@ static struct RequestTest {
|
||||
{ "s", "t" }, /* CR at end is ignored */
|
||||
{ "c", "d" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Tab in header name", "666316",
|
||||
@@ -351,7 +352,7 @@ static struct RequestTest {
|
||||
{ "p", "q z: w" },
|
||||
{ "c", "d" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
{ "Tab in header value", "666316",
|
||||
@@ -364,7 +365,7 @@ static struct RequestTest {
|
||||
{ "z", "w" }, /* trailing tab ignored */
|
||||
{ "c", "d" },
|
||||
{ NULL }
|
||||
- }
|
||||
+ }, 0
|
||||
},
|
||||
|
||||
/************************/
|
||||
@@ -375,77 +376,77 @@ static struct RequestTest {
|
||||
"GET /\r\n", -1,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "HTTP 1.2 request (no such thing)", NULL,
|
||||
"GET / HTTP/1.2\r\n", -1,
|
||||
SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "HTTP 2000 request (no such thing)", NULL,
|
||||
"GET / HTTP/2000.0\r\n", -1,
|
||||
SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "Long HTTP version terminating at missing minor version", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/404",
|
||||
unterminated_http_version, sizeof (unterminated_http_version),
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "Non-HTTP request", NULL,
|
||||
"GET / SOUP/1.1\r\nHost: example.com\r\n", -1,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "Junk after Request-Line", NULL,
|
||||
"GET / HTTP/1.1 blah\r\nHost: example.com\r\n", -1,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "NUL in Method", NULL,
|
||||
"G\x00T / HTTP/1.1\r\nHost: example.com\r\n", 37,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "NUL at beginning of Method", "666316",
|
||||
"\x00 / HTTP/1.1\r\nHost: example.com\r\n", 35,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "NUL in Path", NULL,
|
||||
"GET /\x00 HTTP/1.1\r\nHost: example.com\r\n", 38,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "No terminating CRLF", NULL,
|
||||
"GET / HTTP/1.1\r\nHost: example.com", -1,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "Unrecognized expectation", NULL,
|
||||
"GET / HTTP/1.1\r\nHost: example.com\r\nExpect: the-impossible\r\n", -1,
|
||||
SOUP_STATUS_EXPECTATION_FAILED,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
// https://gitlab.gnome.org/GNOME/libsoup/-/issues/377
|
||||
@@ -453,21 +454,31 @@ static struct RequestTest {
|
||||
"GET / HTTP/1.1\r\nHost\x00: example.com\r\n", 36,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "NUL in header value", NULL,
|
||||
"HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28,
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
},
|
||||
|
||||
{ "Only newlines", NULL,
|
||||
only_newlines, sizeof (only_newlines),
|
||||
SOUP_STATUS_BAD_REQUEST,
|
||||
NULL, NULL, -1,
|
||||
- { { NULL } }
|
||||
+ { { NULL } }, 0
|
||||
+ },
|
||||
+
|
||||
+ { "Duplicate Host headers",
|
||||
+ "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472",
|
||||
+ "GET / HTTP/1.1\r\nHost: example.com\r\nHost: example.org\r\n",
|
||||
+ -1,
|
||||
+ SOUP_STATUS_BAD_REQUEST,
|
||||
+ NULL, NULL, -1,
|
||||
+ { { NULL } },
|
||||
+ G_LOG_LEVEL_WARNING
|
||||
}
|
||||
};
|
||||
static const int num_reqtests = G_N_ELEMENTS (reqtests);
|
||||
@@ -915,10 +926,17 @@ do_request_tests (void)
|
||||
len = strlen (reqtests[i].request);
|
||||
else
|
||||
len = reqtests[i].length;
|
||||
+
|
||||
+ if (reqtests[i].log_flags)
|
||||
+ g_test_expect_message ("libsoup", reqtests[i].log_flags, "*");
|
||||
+
|
||||
status = soup_headers_parse_request (reqtests[i].request, len,
|
||||
headers, &method, &path,
|
||||
&version);
|
||||
g_assert_cmpint (status, ==, reqtests[i].status);
|
||||
+ if (reqtests[i].log_flags)
|
||||
+ g_test_assert_expected_messages ();
|
||||
+
|
||||
if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
|
||||
g_assert_cmpstr (method, ==, reqtests[i].method);
|
||||
g_assert_cmpstr (path, ==, reqtests[i].path);
|
||||
@@ -1314,6 +1332,25 @@ do_bad_header_tests (void)
|
||||
soup_message_headers_unref (hdrs);
|
||||
}
|
||||
|
||||
+static void
|
||||
+do_append_duplicate_host_test (void)
|
||||
+{
|
||||
+ SoupMessageHeaders *hdrs;
|
||||
+ const char *list_value;
|
||||
+
|
||||
+ hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
|
||||
+ soup_message_headers_append (hdrs, "Host", "a");
|
||||
+ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
|
||||
+ "Attempted to add duplicate Host header to a SoupMessageHeaders that already contains a Host header");
|
||||
+ soup_message_headers_append (hdrs, "Host", "b");
|
||||
+ g_test_assert_expected_messages ();
|
||||
+
|
||||
+ list_value = soup_message_headers_get_list (hdrs, "Host");
|
||||
+ g_assert_cmpstr (list_value, ==, "a");
|
||||
+
|
||||
+ soup_message_headers_unref (hdrs);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -1330,6 +1367,8 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/header-parsing/append-param", do_append_param_tests);
|
||||
g_test_add_func ("/header-parsing/bad", do_bad_header_tests);
|
||||
|
||||
+ g_test_add_func ("/header-parsing/append-duplicate-host", do_append_duplicate_host_test);
|
||||
+
|
||||
ret = g_test_run ();
|
||||
|
||||
test_cleanup ();
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From 84e601252a9ae5eafaba9cb9cb5e4bd77ca41bdb Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Tue, 15 Apr 2025 12:17:39 +0200
|
||||
Subject: [PATCH] soup-message-headers: Correct merge of ranges
|
||||
|
||||
It had been skipping every second range, which generated an array
|
||||
of a lot of insane ranges, causing large memory usage by the server.
|
||||
|
||||
Closes #428
|
||||
---
|
||||
libsoup/soup-message-headers.c | 1 +
|
||||
tests/meson.build | 1 +
|
||||
tests/server-mem-limit-test.c | 144 +++++++++++++++++++++++++++++++++
|
||||
3 files changed, 146 insertions(+)
|
||||
create mode 100644 tests/server-mem-limit-test.c
|
||||
|
||||
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
|
||||
index 64847e30..f612bff1 100644
|
||||
--- a/libsoup/soup-message-headers.c
|
||||
+++ b/libsoup/soup-message-headers.c
|
||||
@@ -1024,6 +1024,7 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
|
||||
if (cur->start <= prev->end) {
|
||||
prev->end = MAX (prev->end, cur->end);
|
||||
g_array_remove_index (array, i);
|
||||
+ i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
--
|
||||
2.49.0
|
||||
@ -1,130 +0,0 @@
|
||||
From a792b23ab87cacbf4dd9462bf7b675fa678efbae Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Tue, 15 Apr 2025 09:59:05 +0200
|
||||
Subject: [PATCH] soup-server-http2: Check validity of the constructed
|
||||
connection URI
|
||||
|
||||
The HTTP/2 pseudo-headers can contain invalid values, which the GUri rejects
|
||||
and returns NULL, but the soup-server did not check the validity and could
|
||||
abort the server itself later in the code.
|
||||
|
||||
Closes #429
|
||||
---
|
||||
.../http2/soup-server-message-io-http2.c | 4 +++
|
||||
tests/http2-test.c | 28 +++++++++++++++++++
|
||||
2 files changed, 32 insertions(+)
|
||||
|
||||
diff --git a/libsoup/server/http2/soup-server-message-io-http2.c b/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
index 943ecfd3..f1fe2d5c 100644
|
||||
--- a/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
+++ b/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
@@ -771,9 +771,13 @@ on_frame_recv_callback (nghttp2_session *session,
|
||||
char *uri_string;
|
||||
GUri *uri;
|
||||
|
||||
+ if (msg_io->scheme == NULL || msg_io->authority == NULL || msg_io->path == NULL)
|
||||
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
uri_string = g_strdup_printf ("%s://%s%s", msg_io->scheme, msg_io->authority, msg_io->path);
|
||||
uri = g_uri_parse (uri_string, SOUP_HTTP_URI_FLAGS, NULL);
|
||||
g_free (uri_string);
|
||||
+ if (uri == NULL)
|
||||
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
soup_server_message_set_uri (msg_io->msg, uri);
|
||||
g_uri_unref (uri);
|
||||
|
||||
diff --git a/tests/http2-test.c b/tests/http2-test.c
|
||||
index 5b6da5e4..ec7972fe 100644
|
||||
--- a/tests/http2-test.c
|
||||
+++ b/tests/http2-test.c
|
||||
@@ -1341,6 +1341,30 @@ do_connection_closed_test (Test *test, gconstpointer data)
|
||||
g_uri_unref (uri);
|
||||
}
|
||||
|
||||
+static void
|
||||
+do_broken_pseudo_header_test (Test *test, gconstpointer data)
|
||||
+{
|
||||
+ char *path;
|
||||
+ SoupMessage *msg;
|
||||
+ GUri *uri;
|
||||
+ GBytes *body = NULL;
|
||||
+ GError *error = NULL;
|
||||
+
|
||||
+ uri = g_uri_parse_relative (base_uri, "/ag", SOUP_HTTP_URI_FLAGS, NULL);
|
||||
+
|
||||
+ /* an ugly cheat to construct a broken URI, which can be sent from other libs */
|
||||
+ path = (char *) g_uri_get_path (uri);
|
||||
+ path[1] = '%';
|
||||
+
|
||||
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
|
||||
+ body = soup_test_session_async_send (test->session, msg, NULL, &error);
|
||||
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
|
||||
+ g_assert_null (body);
|
||||
+ g_clear_error (&error);
|
||||
+ g_object_unref (msg);
|
||||
+ g_uri_unref (uri);
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
unpause_message (SoupServerMessage *msg)
|
||||
{
|
||||
@@ -1662,6 +1686,10 @@ main (int argc, char **argv)
|
||||
setup_session,
|
||||
do_connection_closed_test,
|
||||
teardown_session);
|
||||
+ g_test_add ("/http2/broken-pseudo-header", Test, NULL,
|
||||
+ setup_session,
|
||||
+ do_broken_pseudo_header_test,
|
||||
+ teardown_session);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
From 527428a033df573ef4558ce1106e080fd9ec5c71 Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Mon, 28 Apr 2025 10:55:42 +0200
|
||||
Subject: [PATCH] soup-server-http2: Correct check of the validity of the
|
||||
constructed connection URI
|
||||
|
||||
RFC 5740: the CONNECT has unset the "scheme" and "path", thus allow them unset.
|
||||
|
||||
The commit a792b23ab87cacbf4dd9462bf7b675fa678efbae also missed to decrement
|
||||
the `io->in_callback` in the early returns.
|
||||
|
||||
Related to #429
|
||||
---
|
||||
.../server/http2/soup-server-message-io-http2.c | 15 ++++++++++-----
|
||||
1 file changed, 10 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libsoup/server/http2/soup-server-message-io-http2.c b/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
index f1fe2d5c..913afb46 100644
|
||||
--- a/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
+++ b/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
@@ -771,13 +771,18 @@ on_frame_recv_callback (nghttp2_session *session,
|
||||
char *uri_string;
|
||||
GUri *uri;
|
||||
|
||||
- if (msg_io->scheme == NULL || msg_io->authority == NULL || msg_io->path == NULL)
|
||||
- return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
- uri_string = g_strdup_printf ("%s://%s%s", msg_io->scheme, msg_io->authority, msg_io->path);
|
||||
+ if (msg_io->authority == NULL) {
|
||||
+ io->in_callback--;
|
||||
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
+ }
|
||||
+ /* RFC 5740: the CONNECT has unset the "scheme" and "path", but the GUri requires the scheme, thus let it be "(null)" */
|
||||
+ uri_string = g_strdup_printf ("%s://%s%s", msg_io->scheme, msg_io->authority, msg_io->path == NULL ? "" : msg_io->path);
|
||||
uri = g_uri_parse (uri_string, SOUP_HTTP_URI_FLAGS, NULL);
|
||||
g_free (uri_string);
|
||||
- if (uri == NULL)
|
||||
- return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
+ if (uri == NULL) {
|
||||
+ io->in_callback--;
|
||||
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
+ }
|
||||
soup_server_message_set_uri (msg_io->msg, uri);
|
||||
g_uri_unref (uri);
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,107 +0,0 @@
|
||||
From 5bfcf8157597f2d327050114fb37ff600004dbcf Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Tue, 15 Apr 2025 09:03:00 +0200
|
||||
Subject: [PATCH] multipart: Fix read out of buffer bounds under
|
||||
soup_multipart_new_from_message()
|
||||
|
||||
This is CVE-2025-32914, special crafted input can cause read out of buffer bounds
|
||||
of the body argument.
|
||||
|
||||
Closes #436
|
||||
---
|
||||
libsoup/soup-multipart.c | 2 +-
|
||||
tests/multipart-test.c | 58 ++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 59 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-multipart.c b/libsoup/soup-multipart.c
|
||||
index 2421c91f8..102ce3722 100644
|
||||
--- a/libsoup/soup-multipart.c
|
||||
+++ b/libsoup/soup-multipart.c
|
||||
@@ -173,7 +173,7 @@ soup_multipart_new_from_message (SoupMessageHeaders *headers,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- split = strstr (start, "\r\n\r\n");
|
||||
+ split = g_strstr_len (start, body_end - start, "\r\n\r\n");
|
||||
if (!split || split > end) {
|
||||
soup_multipart_free (multipart);
|
||||
return NULL;
|
||||
diff --git a/tests/multipart-test.c b/tests/multipart-test.c
|
||||
index 2c0e7e969..f5b986889 100644
|
||||
--- a/tests/multipart-test.c
|
||||
+++ b/tests/multipart-test.c
|
||||
@@ -471,6 +471,62 @@ test_multipart (gconstpointer data)
|
||||
loop = NULL;
|
||||
}
|
||||
|
||||
+static void
|
||||
+test_multipart_bounds_good (void)
|
||||
+{
|
||||
+ #define TEXT "line1\r\nline2"
|
||||
+ SoupMultipart *multipart;
|
||||
+ SoupMessageHeaders *headers, *set_headers = NULL;
|
||||
+ GBytes *bytes, *set_bytes = NULL;
|
||||
+ const char *raw_data = "--123\r\nContent-Type: text/plain;\r\n\r\n" TEXT "\r\n--123--\r\n";
|
||||
+ gboolean success;
|
||||
+
|
||||
+ headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
|
||||
+ soup_message_headers_append (headers, "Content-Type", "multipart/mixed; boundary=\"123\"");
|
||||
+
|
||||
+ bytes = g_bytes_new (raw_data, strlen (raw_data));
|
||||
+
|
||||
+ multipart = soup_multipart_new_from_message (headers, bytes);
|
||||
+
|
||||
+ g_assert_nonnull (multipart);
|
||||
+ g_assert_cmpint (soup_multipart_get_length (multipart), ==, 1);
|
||||
+ success = soup_multipart_get_part (multipart, 0, &set_headers, &set_bytes);
|
||||
+ g_assert_true (success);
|
||||
+ g_assert_nonnull (set_headers);
|
||||
+ g_assert_nonnull (set_bytes);
|
||||
+ g_assert_cmpint (strlen (TEXT), ==, g_bytes_get_size (set_bytes));
|
||||
+ g_assert_cmpstr ("text/plain", ==, soup_message_headers_get_content_type (set_headers, NULL));
|
||||
+ g_assert_cmpmem (TEXT, strlen (TEXT), g_bytes_get_data (set_bytes, NULL), g_bytes_get_size (set_bytes));
|
||||
+
|
||||
+ soup_message_headers_unref (headers);
|
||||
+ g_bytes_unref (bytes);
|
||||
+
|
||||
+ soup_multipart_free (multipart);
|
||||
+
|
||||
+ #undef TEXT
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_multipart_bounds_bad (void)
|
||||
+{
|
||||
+ SoupMultipart *multipart;
|
||||
+ SoupMessageHeaders *headers;
|
||||
+ GBytes *bytes;
|
||||
+ const char *raw_data = "--123\r\nContent-Type: text/plain;\r\nline1\r\nline2\r\n--123--\r\n";
|
||||
+
|
||||
+ headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
|
||||
+ soup_message_headers_append (headers, "Content-Type", "multipart/mixed; boundary=\"123\"");
|
||||
+
|
||||
+ bytes = g_bytes_new (raw_data, strlen (raw_data));
|
||||
+
|
||||
+ /* it did read out of raw_data/bytes bounds */
|
||||
+ multipart = soup_multipart_new_from_message (headers, bytes);
|
||||
+ g_assert_null (multipart);
|
||||
+
|
||||
+ soup_message_headers_unref (headers);
|
||||
+ g_bytes_unref (bytes);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -498,6 +554,8 @@ main (int argc, char **argv)
|
||||
g_test_add_data_func ("/multipart/sync", GINT_TO_POINTER (SYNC_MULTIPART), test_multipart);
|
||||
g_test_add_data_func ("/multipart/async", GINT_TO_POINTER (ASYNC_MULTIPART), test_multipart);
|
||||
g_test_add_data_func ("/multipart/async-small-reads", GINT_TO_POINTER (ASYNC_MULTIPART_SMALL_READS), test_multipart);
|
||||
+ g_test_add_func ("/multipart/bounds-good", test_multipart_bounds_good);
|
||||
+ g_test_add_func ("/multipart/bounds-bad", test_multipart_bounds_bad);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
From 845e198402377f8644e9ae5200f1715df1ddfc08 Mon Sep 17 00:00:00 2001
|
||||
From 3b0a3a4a9c751e2874d8cfb7b61349881ba2114a Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Thu, 27 Mar 2025 14:43:26 -0500
|
||||
Subject: [PATCH 1/3] cookie: Always normalize domain value
|
||||
Subject: [PATCH] cookie: Always normalize domain value
|
||||
|
||||
In order for libpsl to give accurate results the domain must be lowercased.
|
||||
|
||||
@ -16,7 +16,7 @@ To make it easiest we normalize it at construction time of the cookie.
|
||||
6 files changed, 76 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libsoup/cookies/soup-cookie-jar.c b/libsoup/cookies/soup-cookie-jar.c
|
||||
index fac53a5f9..7f92ace1f 100644
|
||||
index 20805c20..51c51d3c 100644
|
||||
--- a/libsoup/cookies/soup-cookie-jar.c
|
||||
+++ b/libsoup/cookies/soup-cookie-jar.c
|
||||
@@ -519,6 +519,7 @@ incoming_cookie_is_third_party (SoupCookieJar *jar,
|
||||
@ -48,7 +48,7 @@ index fac53a5f9..7f92ace1f 100644
|
||||
if (policy == SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY)
|
||||
return TRUE;
|
||||
diff --git a/libsoup/cookies/soup-cookie.c b/libsoup/cookies/soup-cookie.c
|
||||
index cc80d001f..b6d771646 100644
|
||||
index d4a9f4c0..e0dbbdda 100644
|
||||
--- a/libsoup/cookies/soup-cookie.c
|
||||
+++ b/libsoup/cookies/soup-cookie.c
|
||||
@@ -168,6 +168,16 @@ parse_date (const char **val_p)
|
||||
@ -109,7 +109,7 @@ index cc80d001f..b6d771646 100644
|
||||
|
||||
/**
|
||||
diff --git a/libsoup/soup-tld.c b/libsoup/soup-tld.c
|
||||
index 2d8151662..71fac5749 100644
|
||||
index 02e54059..ee98c459 100644
|
||||
--- a/libsoup/soup-tld.c
|
||||
+++ b/libsoup/soup-tld.c
|
||||
@@ -15,6 +15,7 @@
|
||||
@ -152,23 +152,21 @@ index 2d8151662..71fac5749 100644
|
||||
|
||||
/**
|
||||
diff --git a/libsoup/soup-uri-utils-private.h b/libsoup/soup-uri-utils-private.h
|
||||
index 0119f0814..c2f984f86 100644
|
||||
index a73e8821..83c4fb36 100644
|
||||
--- a/libsoup/soup-uri-utils-private.h
|
||||
+++ b/libsoup/soup-uri-utils-private.h
|
||||
@@ -28,6 +28,8 @@ GUri *soup_uri_copy_with_normalized_flags (GUri *uri);
|
||||
@@ -30,4 +30,6 @@ GUri *soup_uri_copy_with_normalized_flags (GUri *uri);
|
||||
|
||||
char *soup_uri_get_host_for_headers (GUri *uri);
|
||||
|
||||
+char *soup_uri_normalize_domain (const char *domain);
|
||||
+
|
||||
#define SOUP_URI_IS_VALID(x) ((x) && g_uri_get_host(x) && g_uri_get_host(x)[0])
|
||||
|
||||
G_END_DECLS
|
||||
diff --git a/libsoup/soup-uri-utils.c b/libsoup/soup-uri-utils.c
|
||||
index 0963a1143..1f65faede 100644
|
||||
index 44cc59b1..63262018 100644
|
||||
--- a/libsoup/soup-uri-utils.c
|
||||
+++ b/libsoup/soup-uri-utils.c
|
||||
@@ -506,3 +506,21 @@ soup_uri_get_host_for_headers (GUri *uri)
|
||||
@@ -566,3 +566,21 @@ soup_uri_get_host_for_headers (GUri *uri)
|
||||
|
||||
return g_strdup (host);
|
||||
}
|
||||
@ -191,10 +189,10 @@ index 0963a1143..1f65faede 100644
|
||||
+ return normalized;
|
||||
+}
|
||||
diff --git a/tests/cookies-test.c b/tests/cookies-test.c
|
||||
index 1d2d45630..7007aaf59 100644
|
||||
index 27cf6d9b..f3dfd6df 100644
|
||||
--- a/tests/cookies-test.c
|
||||
+++ b/tests/cookies-test.c
|
||||
@@ -695,6 +695,24 @@ do_cookies_threads_test (void)
|
||||
@@ -715,6 +715,24 @@ do_cookies_threads_test (void)
|
||||
soup_test_session_abort_unref (session);
|
||||
}
|
||||
|
||||
@ -219,7 +217,7 @@ index 1d2d45630..7007aaf59 100644
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -726,6 +744,7 @@ main (int argc, char **argv)
|
||||
@@ -748,6 +766,7 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/cookies/secure-cookies", do_cookies_strict_secure_test);
|
||||
g_test_add_func ("/cookies/prefix", do_cookies_prefix_test);
|
||||
g_test_add_func ("/cookies/threads", do_cookies_threads_test);
|
||||
@ -228,4 +226,5 @@ index 1d2d45630..7007aaf59 100644
|
||||
ret = g_test_run ();
|
||||
|
||||
--
|
||||
GitLab
|
||||
2.54.0
|
||||
|
||||
|
||||
@ -1,245 +0,0 @@
|
||||
From 8988379984e33dcc7d3aa58551db13e48755959f Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Thu, 15 May 2025 07:59:14 +0200
|
||||
Subject: [PATCH 1/2] soup-date-utils: Add value checks for date/time parsing
|
||||
|
||||
Reject date/time when it does not represent a valid value.
|
||||
|
||||
Closes https://gitlab.gnome.org/GNOME/libsoup/-/issues/448
|
||||
---
|
||||
libsoup/soup-date-utils.c | 23 +++++++++++++++--------
|
||||
tests/cookies-test.c | 10 ++++++++++
|
||||
2 files changed, 25 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-date-utils.c b/libsoup/soup-date-utils.c
|
||||
index fd785f509..34ca99503 100644
|
||||
--- a/libsoup/soup-date-utils.c
|
||||
+++ b/libsoup/soup-date-utils.c
|
||||
@@ -129,7 +129,7 @@ parse_day (int *day, const char **date_string)
|
||||
while (*end == ' ' || *end == '-')
|
||||
end++;
|
||||
*date_string = end;
|
||||
- return TRUE;
|
||||
+ return *day >= 1 && *day <= 31;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -169,7 +169,7 @@ parse_year (int *year, const char **date_string)
|
||||
while (*end == ' ' || *end == '-')
|
||||
end++;
|
||||
*date_string = end;
|
||||
- return TRUE;
|
||||
+ return *year > 0 && *year < 9999;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -193,7 +193,7 @@ parse_time (int *hour, int *minute, int *second, const char **date_string)
|
||||
while (*p == ' ')
|
||||
p++;
|
||||
*date_string = p;
|
||||
- return TRUE;
|
||||
+ return *hour >= 0 && *hour < 24 && *minute >= 0 && *minute < 60 && *second >= 0 && *second < 60;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -209,9 +209,14 @@ parse_timezone (GTimeZone **timezone, const char **date_string)
|
||||
gulong val;
|
||||
int sign = (**date_string == '+') ? 1 : -1;
|
||||
val = strtoul (*date_string + 1, (char **)date_string, 10);
|
||||
- if (**date_string == ':')
|
||||
- val = 60 * val + strtoul (*date_string + 1, (char **)date_string, 10);
|
||||
- else
|
||||
+ if (val > 9999)
|
||||
+ return FALSE;
|
||||
+ if (**date_string == ':') {
|
||||
+ gulong val2 = strtoul (*date_string + 1, (char **)date_string, 10);
|
||||
+ if (val > 99 || val2 > 99)
|
||||
+ return FALSE;
|
||||
+ val = 60 * val + val2;
|
||||
+ } else
|
||||
val = 60 * (val / 100) + (val % 100);
|
||||
offset_minutes = sign * val;
|
||||
utc = (sign == -1) && !val;
|
||||
@@ -264,7 +269,8 @@ parse_textual_date (const char *date_string)
|
||||
if (!parse_month (&month, &date_string) ||
|
||||
!parse_day (&day, &date_string) ||
|
||||
!parse_time (&hour, &minute, &second, &date_string) ||
|
||||
- !parse_year (&year, &date_string))
|
||||
+ !parse_year (&year, &date_string) ||
|
||||
+ !g_date_valid_dmy (day, month, year))
|
||||
return NULL;
|
||||
|
||||
/* There shouldn't be a timezone, but check anyway */
|
||||
@@ -276,7 +282,8 @@ parse_textual_date (const char *date_string)
|
||||
if (!parse_day (&day, &date_string) ||
|
||||
!parse_month (&month, &date_string) ||
|
||||
!parse_year (&year, &date_string) ||
|
||||
- !parse_time (&hour, &minute, &second, &date_string))
|
||||
+ !parse_time (&hour, &minute, &second, &date_string) ||
|
||||
+ !g_date_valid_dmy (day, month, year))
|
||||
return NULL;
|
||||
|
||||
/* This time there *should* be a timezone, but we
|
||||
diff --git a/tests/cookies-test.c b/tests/cookies-test.c
|
||||
index 1d2d45630..ff809a400 100644
|
||||
--- a/tests/cookies-test.c
|
||||
+++ b/tests/cookies-test.c
|
||||
@@ -460,6 +460,15 @@ do_cookies_parsing_max_age_long_overflow (void)
|
||||
soup_cookie_free (cookie);
|
||||
}
|
||||
|
||||
+static void
|
||||
+do_cookies_parsing_int32_overflow (void)
|
||||
+{
|
||||
+ SoupCookie *cookie = soup_cookie_parse ("Age=1;expires=3Mar9 999:9:9+ 999999999-age=main=gne=", NULL);
|
||||
+ g_assert_nonnull (cookie);
|
||||
+ g_assert_null (soup_cookie_get_expires (cookie));
|
||||
+ soup_cookie_free (cookie);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
do_cookies_equal_nullpath (void)
|
||||
{
|
||||
@@ -718,6 +727,7 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/cookies/parsing/no-path-null-origin", do_cookies_parsing_nopath_nullorigin);
|
||||
g_test_add_func ("/cookies/parsing/max-age-int32-overflow", do_cookies_parsing_max_age_int32_overflow);
|
||||
g_test_add_func ("/cookies/parsing/max-age-long-overflow", do_cookies_parsing_max_age_long_overflow);
|
||||
+ g_test_add_func ("/cookies/parsing/int32-overflow", do_cookies_parsing_int32_overflow);
|
||||
g_test_add_func ("/cookies/parsing/equal-nullpath", do_cookies_equal_nullpath);
|
||||
g_test_add_func ("/cookies/parsing/control-characters", do_cookies_parsing_control_characters);
|
||||
g_test_add_func ("/cookies/parsing/name-value-max-size", do_cookies_parsing_name_value_max_size);
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
||||
From 0d6bfa52da7313de848fb13fcfdbc561c04afef8 Mon Sep 17 00:00:00 2001
|
||||
From: Brian Yurko <155515-byurko@users.noreply.gitlab.gnome.org>
|
||||
Date: Wed, 11 Jun 2025 11:00:56 -0400
|
||||
Subject: [PATCH 2/2] tests: Add tests for date-time including timezone
|
||||
validation work
|
||||
|
||||
These tests are built on top of earlier work in a related pull request.
|
||||
|
||||
Closes #448
|
||||
---
|
||||
libsoup/soup-date-utils.c | 8 ++++----
|
||||
tests/cookies-test.c | 1 +
|
||||
tests/date-test.c | 37 ++++++++++++++++++++++++++++++-------
|
||||
3 files changed, 35 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-date-utils.c b/libsoup/soup-date-utils.c
|
||||
index 34ca99503..73f80ab60 100644
|
||||
--- a/libsoup/soup-date-utils.c
|
||||
+++ b/libsoup/soup-date-utils.c
|
||||
@@ -40,7 +40,7 @@ soup_date_time_is_past (GDateTime *date)
|
||||
g_return_val_if_fail (date != NULL, TRUE);
|
||||
|
||||
/* optimization */
|
||||
- if (g_date_time_get_year (date) < 2020)
|
||||
+ if (g_date_time_get_year (date) < 2025)
|
||||
return TRUE;
|
||||
|
||||
return g_date_time_to_unix (date) < time (NULL);
|
||||
@@ -219,15 +219,15 @@ parse_timezone (GTimeZone **timezone, const char **date_string)
|
||||
} else
|
||||
val = 60 * (val / 100) + (val % 100);
|
||||
offset_minutes = sign * val;
|
||||
- utc = (sign == -1) && !val;
|
||||
+ utc = (sign == -1) && !val;
|
||||
} else if (**date_string == 'Z') {
|
||||
offset_minutes = 0;
|
||||
- utc = TRUE;
|
||||
+ utc = TRUE;
|
||||
(*date_string)++;
|
||||
} else if (!strcmp (*date_string, "GMT") ||
|
||||
!strcmp (*date_string, "UTC")) {
|
||||
offset_minutes = 0;
|
||||
- utc = TRUE;
|
||||
+ utc = TRUE;
|
||||
(*date_string) += 3;
|
||||
} else if (strchr ("ECMP", **date_string) &&
|
||||
((*date_string)[1] == 'D' || (*date_string)[1] == 'S') &&
|
||||
diff --git a/tests/cookies-test.c b/tests/cookies-test.c
|
||||
index ff809a400..18c9b60d8 100644
|
||||
--- a/tests/cookies-test.c
|
||||
+++ b/tests/cookies-test.c
|
||||
@@ -464,6 +464,7 @@ static void
|
||||
do_cookies_parsing_int32_overflow (void)
|
||||
{
|
||||
SoupCookie *cookie = soup_cookie_parse ("Age=1;expires=3Mar9 999:9:9+ 999999999-age=main=gne=", NULL);
|
||||
+ g_test_bug ("https://gitlab.gnome.org/GNOME/libsoup/-/issues/448");
|
||||
g_assert_nonnull (cookie);
|
||||
g_assert_null (soup_cookie_get_expires (cookie));
|
||||
soup_cookie_free (cookie);
|
||||
diff --git a/tests/date-test.c b/tests/date-test.c
|
||||
index 7eefd7c00..abf89ddd1 100644
|
||||
--- a/tests/date-test.c
|
||||
+++ b/tests/date-test.c
|
||||
@@ -92,6 +92,11 @@ static const OkDate ok_dates[] = {
|
||||
{ "Sat, 06 Nov 2004 08:09:07", NULL },
|
||||
{ "06 Nov 2004 08:09:07 GMT", NULL },
|
||||
{ "SAT, 06 NOV 2004 08:09:07 +1000", "644048" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 -10000", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 +01:30", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 +0:180", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 +100:100", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 Z", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
|
||||
/* rfc850-date, and broken variants */
|
||||
{ "Saturday, 06-Nov-04 08:09:07 GMT", NULL },
|
||||
@@ -109,6 +114,8 @@ static const OkDate ok_dates[] = {
|
||||
{ "Sat Nov 06 08:09:07 2004", NULL },
|
||||
{ "Sat Nov 6 08:09:07 2004", NULL },
|
||||
{ "Sat Nov 6 08:09:07 2004 GMT", NULL },
|
||||
+ { "Sat Nov 6 08:09:07 2004 NoZone", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat Nov 6 08:09:07 2004 UTC", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
|
||||
/* Netscape cookie spec date, and broken variants */
|
||||
{ "Sat, 06-Nov-2004 08:09:07 GMT", NULL },
|
||||
@@ -182,7 +189,23 @@ static const BadDate bad_dates[] = {
|
||||
{ "Sat Nov 6 08::07 2004", NULL },
|
||||
{ "Sat Nov 6 08:09: 2004", NULL },
|
||||
{ "Sat Nov 6 08:09:07", NULL },
|
||||
- { "Sat Nov 6 08:09:07 GMT 2004", NULL }
|
||||
+ { "Sat Nov 6 08:09:07 GMT 2004", NULL },
|
||||
+
|
||||
+ /* range constraints added "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" */
|
||||
+ { "Sat, 00-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 32-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-0 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-9999 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 0-1:09:07 GMT", NULL },
|
||||
+ { "(Sat), Nov 6 -1:09:07 2004", NULL },
|
||||
+ { "Sat, 06-Nov-2004 24:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:-1:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:60:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:09:-10 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:09:60 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-71 08:09:99 UTC", NULL },
|
||||
+ { "Sat, 31-Feb-2004 08:09:07 UTC", NULL },
|
||||
+ { "2004-11-06T08:09:07Z", NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -198,12 +221,12 @@ check_bad (gconstpointer data)
|
||||
soup_test_assert (date == NULL,
|
||||
"date parsing succeeded for '%s': %d %d %d - %d %d %d",
|
||||
bad->date,
|
||||
- g_date_time_get_year (date),
|
||||
- g_date_time_get_month (date),
|
||||
- g_date_time_get_day_of_month (date),
|
||||
- g_date_time_get_hour (date),
|
||||
- g_date_time_get_minute (date),
|
||||
- g_date_time_get_second (date));
|
||||
+ g_date_time_get_year (date),
|
||||
+ g_date_time_get_month (date),
|
||||
+ g_date_time_get_day_of_month (date),
|
||||
+ g_date_time_get_hour (date),
|
||||
+ g_date_time_get_minute (date),
|
||||
+ g_date_time_get_second (date));
|
||||
g_clear_pointer (&date, g_date_time_unref);
|
||||
}
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,89 +0,0 @@
|
||||
From 66521f00e9f87f709d8ad9138f19052db933cf06 Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Thu, 15 May 2025 17:49:11 +0200
|
||||
Subject: [PATCH] soup-multipart: Verify boundary limits for multipart body
|
||||
|
||||
It could happen that the boundary started at a place which resulted into
|
||||
a negative number, which in an unsigned integer is a very large value.
|
||||
Check the body size is not a negative value before setting it.
|
||||
|
||||
Closes https://gitlab.gnome.org/GNOME/libsoup/-/issues/449
|
||||
---
|
||||
libsoup/soup-multipart.c | 2 +-
|
||||
tests/multipart-test.c | 40 ++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 41 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-multipart.c b/libsoup/soup-multipart.c
|
||||
index 102ce372..a587fe7c 100644
|
||||
--- a/libsoup/soup-multipart.c
|
||||
+++ b/libsoup/soup-multipart.c
|
||||
@@ -204,7 +204,7 @@ soup_multipart_new_from_message (SoupMessageHeaders *headers,
|
||||
*/
|
||||
part_body = g_bytes_new_from_bytes (body, // FIXME
|
||||
split - body_data,
|
||||
- end - 2 - split);
|
||||
+ end - 2 >= split ? end - 2 - split : 0);
|
||||
g_ptr_array_add (multipart->bodies, part_body);
|
||||
|
||||
start = end;
|
||||
diff --git a/tests/multipart-test.c b/tests/multipart-test.c
|
||||
index f5b98688..92b673eb 100644
|
||||
--- a/tests/multipart-test.c
|
||||
+++ b/tests/multipart-test.c
|
||||
@@ -527,6 +527,45 @@ test_multipart_bounds_bad (void)
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
|
||||
+static void
|
||||
+test_multipart_too_large (void)
|
||||
+{
|
||||
+ const char *raw_body =
|
||||
+ "-------------------\r\n"
|
||||
+ "-\n"
|
||||
+ "Cont\"\r\n"
|
||||
+ "Content-Tynt----e:n\x8erQK\r\n"
|
||||
+ "Content-Disposition: name= form-; name=\"file\"; filename=\"ype:i/ -d; ----\xae\r\n"
|
||||
+ "Content-Typimag\x01/png--\\\n"
|
||||
+ "\r\n"
|
||||
+ "---:\n\r\n"
|
||||
+ "\r\n"
|
||||
+ "-------------------------------------\r\n"
|
||||
+ "---------\r\n"
|
||||
+ "----------------------";
|
||||
+ GBytes *body;
|
||||
+ GHashTable *params;
|
||||
+ SoupMessageHeaders *headers;
|
||||
+ SoupMultipart *multipart;
|
||||
+
|
||||
+ params = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
+ g_hash_table_insert (params, (gpointer) "boundary", (gpointer) "-----------------");
|
||||
+ headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
|
||||
+ soup_message_headers_set_content_type (headers, "multipart/form-data", params);
|
||||
+ g_hash_table_unref (params);
|
||||
+
|
||||
+ body = g_bytes_new_static (raw_body, strlen (raw_body));
|
||||
+ multipart = soup_multipart_new_from_message (headers, body);
|
||||
+ soup_message_headers_unref (headers);
|
||||
+ g_bytes_unref (body);
|
||||
+
|
||||
+ g_assert_nonnull (multipart);
|
||||
+ g_assert_cmpint (soup_multipart_get_length (multipart), ==, 1);
|
||||
+ g_assert_true (soup_multipart_get_part (multipart, 0, &headers, &body));
|
||||
+ g_assert_cmpint (g_bytes_get_size (body), ==, 0);
|
||||
+ soup_multipart_free (multipart);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -556,6 +595,7 @@ main (int argc, char **argv)
|
||||
g_test_add_data_func ("/multipart/async-small-reads", GINT_TO_POINTER (ASYNC_MULTIPART_SMALL_READS), test_multipart);
|
||||
g_test_add_func ("/multipart/bounds-good", test_multipart_bounds_good);
|
||||
g_test_add_func ("/multipart/bounds-bad", test_multipart_bounds_bad);
|
||||
+ g_test_add_func ("/multipart/too-large", test_multipart_too_large);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,185 +0,0 @@
|
||||
From 427a5ed7048dda4d22f13c164a3a439e68604406 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Gorse <mgorse@suse.com>
|
||||
Date: Thu, 8 Jan 2026 16:19:37 -0600
|
||||
Subject: [PATCH] soup-auth-ntlm: Reject excessively long passwords
|
||||
|
||||
According to
|
||||
https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/ntlm-user-authentication,
|
||||
the practical limit for a NTLM password is 128 Unicode characters, so it
|
||||
should be safe to reject passwords longer than 256 bytes. Previously,
|
||||
md4sum could overflow and cause an out-of-bounds memory access if an
|
||||
extremely long password was provided. Also update md4sum to use unsigned
|
||||
variables for size-related calculations, as a precaution.
|
||||
|
||||
This is CVE-2026-0719.
|
||||
|
||||
Closes #477.
|
||||
---
|
||||
libsoup/auth/soup-auth-ntlm.c | 27 +++++++++++----
|
||||
tests/ntlm-test.c | 64 +++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 84 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libsoup/auth/soup-auth-ntlm.c b/libsoup/auth/soup-auth-ntlm.c
|
||||
index dc440ad1..a338389b 100644
|
||||
--- a/libsoup/auth/soup-auth-ntlm.c
|
||||
+++ b/libsoup/auth/soup-auth-ntlm.c
|
||||
@@ -355,6 +355,14 @@ soup_auth_ntlm_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+ if (priv->password_state == SOUP_NTLM_PASSWORD_PROVIDED && !priv->nt_hash[0]) {
|
||||
+ /* This can happen if an excessively long password was
|
||||
+ * provided, in which case we don't try to hash */
|
||||
+ conn->state = SOUP_NTLM_FAILED;
|
||||
+ priv->password_state = SOUP_NTLM_PASSWORD_REJECTED;
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
if (!soup_ntlm_parse_challenge (auth_header + 5, &conn->nonce,
|
||||
priv->domain ? NULL : &priv->domain,
|
||||
&conn->ntlmv2_session, &conn->negotiate_target,
|
||||
@@ -449,8 +457,10 @@ soup_auth_ntlm_authenticate (SoupAuth *auth, const char *username,
|
||||
priv->username = g_strdup (username);
|
||||
}
|
||||
|
||||
- soup_ntlm_nt_hash (password, priv->nt_hash);
|
||||
- soup_ntlm_lanmanager_hash (password, priv->lm_hash);
|
||||
+ if (strlen (password) < 256) {
|
||||
+ soup_ntlm_nt_hash (password, priv->nt_hash);
|
||||
+ soup_ntlm_lanmanager_hash (password, priv->lm_hash);
|
||||
+ }
|
||||
|
||||
priv->password_state = SOUP_NTLM_PASSWORD_PROVIDED;
|
||||
}
|
||||
@@ -616,7 +626,7 @@ soup_auth_ntlm_class_init (SoupAuthNTLMClass *auth_ntlm_class)
|
||||
}
|
||||
|
||||
static void md4sum (const unsigned char *in,
|
||||
- int nbytes,
|
||||
+ size_t nbytes,
|
||||
unsigned char digest[16]);
|
||||
|
||||
typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
|
||||
@@ -662,7 +672,7 @@ soup_ntlm_nt_hash (const char *password, guchar hash[21])
|
||||
{
|
||||
unsigned char *buf, *p;
|
||||
|
||||
- p = buf = g_malloc (strlen (password) * 2);
|
||||
+ p = buf = g_malloc_n (strlen (password), 2);
|
||||
|
||||
while (*password) {
|
||||
*p++ = *password++;
|
||||
@@ -1104,15 +1114,16 @@ calc_response (const guchar *key, const guchar *plaintext, guchar *results)
|
||||
#define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
|
||||
|
||||
static void
|
||||
-md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
|
||||
+md4sum (const unsigned char *in, size_t nbytes, unsigned char digest[16])
|
||||
{
|
||||
unsigned char *M;
|
||||
guint32 A, B, C, D, AA, BB, CC, DD, X[16];
|
||||
- int pbytes, nbits = nbytes * 8, i, j;
|
||||
+ size_t pbytes, nbits = nbytes * 8;
|
||||
+ int i, j;
|
||||
|
||||
/* There is *always* padding of at least one bit. */
|
||||
pbytes = ((119 - (nbytes % 64)) % 64) + 1;
|
||||
- M = alloca (nbytes + pbytes + 8);
|
||||
+ M = g_malloc (nbytes + pbytes + 8);
|
||||
memcpy (M, in, nbytes);
|
||||
memset (M + nbytes, 0, pbytes + 8);
|
||||
M[nbytes] = 0x80;
|
||||
@@ -1212,6 +1223,8 @@ md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
|
||||
digest[13] = (D >> 8) & 0xFF;
|
||||
digest[14] = (D >> 16) & 0xFF;
|
||||
digest[15] = (D >> 24) & 0xFF;
|
||||
+
|
||||
+ g_free (M);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/tests/ntlm-test.c b/tests/ntlm-test.c
|
||||
index e19f5663..c95fcd50 100644
|
||||
--- a/tests/ntlm-test.c
|
||||
+++ b/tests/ntlm-test.c
|
||||
@@ -740,6 +740,67 @@ do_retrying_test (TestServer *ts,
|
||||
soup_test_session_abort_unref (session);
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+long_password_test_authenticate (SoupMessage *msg,
|
||||
+ SoupAuth *auth,
|
||||
+ gboolean retrying,
|
||||
+ gpointer user)
|
||||
+{
|
||||
+ size_t l = 65536;
|
||||
+ char *password;
|
||||
+ char tmp[10000];
|
||||
+ size_t i;
|
||||
+
|
||||
+ password = (char *)g_malloc (l);
|
||||
+
|
||||
+ for (i = 0; i < 10000; i++) {
|
||||
+ tmp[i] = 'A';
|
||||
+ }
|
||||
+ for (i = 0; i < l/10000; i++) {
|
||||
+ memcpy (password + i * 10000, tmp, 10000);
|
||||
+ }
|
||||
+ memcpy (password + l - 1 - 10000, tmp, 10000);
|
||||
+
|
||||
+ soup_auth_authenticate (auth, "alice", password);
|
||||
+
|
||||
+ g_free (password);
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+do_long_password_test (TestServer *ts,
|
||||
+ gconstpointer data)
|
||||
+{
|
||||
+ SoupSession *session;
|
||||
+ SoupMessage *msg;
|
||||
+ GUri *uri;
|
||||
+ GBytes *body;
|
||||
+
|
||||
+ if (!can_do_ntlm_test ()) {
|
||||
+ g_test_skip ("NTLM authentication not available (likely due to FIPS mode)");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ session = soup_test_session_new (NULL);
|
||||
+ soup_session_add_feature_by_type (session, SOUP_TYPE_AUTH_NTLM);
|
||||
+ soup_session_set_proxy_resolver(session, NULL);
|
||||
+
|
||||
+ uri = g_uri_parse_relative (ts->uri, "/alice", SOUP_HTTP_URI_FLAGS, NULL);
|
||||
+ msg = soup_message_new_from_uri ("GET", uri);
|
||||
+ g_signal_connect (msg, "authenticate",
|
||||
+ G_CALLBACK (long_password_test_authenticate), NULL);
|
||||
+ g_uri_unref (uri);
|
||||
+
|
||||
+ body = soup_session_send_and_read (session, msg, NULL, NULL);
|
||||
+
|
||||
+ soup_test_assert_message_status (msg, SOUP_STATUS_UNAUTHORIZED);
|
||||
+
|
||||
+ g_bytes_unref (body);
|
||||
+ g_object_unref (msg);
|
||||
+
|
||||
+ soup_test_session_abort_unref (session);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -763,6 +824,9 @@ main (int argc, char **argv)
|
||||
g_test_add ("/ntlm/retry", TestServer, NULL,
|
||||
setup_server, do_retrying_test, teardown_server);
|
||||
|
||||
+ g_test_add ("/ntlm/long-password", TestServer, NULL,
|
||||
+ setup_server, do_long_password_test, teardown_server);
|
||||
+
|
||||
ret = g_test_run ();
|
||||
|
||||
test_cleanup ();
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,97 +0,0 @@
|
||||
From 0a55f5ebde48cc3e488bff70215b22f103cc6077 Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
||||
Date: Mon, 19 Jan 2026 15:14:58 +0100
|
||||
Subject: [PATCH] multipart: check length of bytes read
|
||||
soup_filter_input_stream_read_until()
|
||||
|
||||
We do make sure the read length is smaller than the buffer length when
|
||||
the boundary is not found, but we should do the same when the boundary
|
||||
is found.
|
||||
|
||||
Spotted in #YWH-PGM9867-149
|
||||
Closes #493
|
||||
---
|
||||
libsoup/soup-filter-input-stream.c | 3 +-
|
||||
tests/multipart-test.c | 46 ++++++++++++++++++++++++++++++
|
||||
2 files changed, 48 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-filter-input-stream.c b/libsoup/soup-filter-input-stream.c
|
||||
index b1e616c7..22541aa0 100644
|
||||
--- a/libsoup/soup-filter-input-stream.c
|
||||
+++ b/libsoup/soup-filter-input-stream.c
|
||||
@@ -337,6 +337,7 @@ soup_filter_input_stream_read_until (SoupFilterInputStream *fstream,
|
||||
if (eof && !*got_boundary)
|
||||
read_length = MIN (priv->buf->len, length);
|
||||
else
|
||||
- read_length = p - buf;
|
||||
+ read_length = MIN ((gsize)(p - buf), length);
|
||||
+
|
||||
return read_from_buf (fstream, buffer, read_length);
|
||||
}
|
||||
diff --git a/tests/multipart-test.c b/tests/multipart-test.c
|
||||
index 92b673eb..0496a4c6 100644
|
||||
--- a/tests/multipart-test.c
|
||||
+++ b/tests/multipart-test.c
|
||||
@@ -527,6 +527,51 @@ test_multipart_bounds_bad (void)
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
|
||||
+static void
|
||||
+test_multipart_bounds_bad_3 (void)
|
||||
+{
|
||||
+ SoupMessage *msg;
|
||||
+ SoupMessageHeaders *headers;
|
||||
+ GInputStream *in;
|
||||
+ SoupMultipartInputStream *multipart;
|
||||
+ GError *error = NULL;
|
||||
+ const char raw_data[] = "\0$--A\r\nContent-Disposition: form-data; name=\"f\"\r\n\r\nXXXXXXXXX\r\n--A--\r\n";
|
||||
+
|
||||
+ msg = soup_message_new(SOUP_METHOD_POST, "http://foo/upload");
|
||||
+ headers = soup_message_get_response_headers (msg);
|
||||
+ soup_message_headers_replace (headers, "Content-Type", "multipart/form-data; boundary=\"A\"");
|
||||
+
|
||||
+ in = g_memory_input_stream_new_from_data (raw_data + 2, sizeof(raw_data) - 2, NULL);
|
||||
+ multipart = soup_multipart_input_stream_new (msg, in);
|
||||
+ g_object_unref (in);
|
||||
+
|
||||
+ while (TRUE) {
|
||||
+ in = soup_multipart_input_stream_next_part (multipart, NULL, &error);
|
||||
+ g_assert_no_error (error);
|
||||
+ if (!in) {
|
||||
+ g_clear_error (&error);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ char buffer[10];
|
||||
+ while (TRUE) {
|
||||
+ gssize bytes_read;
|
||||
+
|
||||
+ bytes_read = g_input_stream_read (in, buffer, sizeof(buffer), NULL, &error);
|
||||
+ g_assert_no_error (error);
|
||||
+ if (bytes_read <= 0) {
|
||||
+ g_clear_error (&error);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ g_object_unref (in);
|
||||
+ }
|
||||
+
|
||||
+ g_object_unref (multipart);
|
||||
+ g_object_unref (msg);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
test_multipart_too_large (void)
|
||||
{
|
||||
@@ -595,6 +640,7 @@ main (int argc, char **argv)
|
||||
g_test_add_data_func ("/multipart/async-small-reads", GINT_TO_POINTER (ASYNC_MULTIPART_SMALL_READS), test_multipart);
|
||||
g_test_add_func ("/multipart/bounds-good", test_multipart_bounds_good);
|
||||
g_test_add_func ("/multipart/bounds-bad", test_multipart_bounds_bad);
|
||||
+ g_test_add_func ("/multipart/bounds-bad-3", test_multipart_bounds_bad_3);
|
||||
g_test_add_func ("/multipart/too-large", test_multipart_too_large);
|
||||
|
||||
ret = g_test_run ();
|
||||
--
|
||||
2.52.0
|
||||
|
||||
361
CVE-2026-4271.patch
Normal file
361
CVE-2026-4271.patch
Normal file
@ -0,0 +1,361 @@
|
||||
From f99a814cadc4c19c5b70a42476f05e62ac2d5bab Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
||||
Date: Mon, 16 Feb 2026 12:09:08 +0100
|
||||
Subject: [PATCH] server: protect message io while reading and writing
|
||||
|
||||
Ensure the nghttp2 session is not destroyed while being used.
|
||||
|
||||
Closes #496
|
||||
---
|
||||
.../http2/soup-server-message-io-http2.c | 117 +++++++++++++-----
|
||||
tests/http2-test.c | 54 ++++++++
|
||||
2 files changed, 141 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/libsoup/server/http2/soup-server-message-io-http2.c b/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
index 913afb46..6f8d1bb6 100644
|
||||
--- a/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
+++ b/libsoup/server/http2/soup-server-message-io-http2.c
|
||||
@@ -69,6 +69,8 @@ typedef struct {
|
||||
GHashTable *messages;
|
||||
|
||||
guint in_callback;
|
||||
+ guint protected;
|
||||
+ gboolean destroyed;
|
||||
} SoupServerMessageIOHTTP2;
|
||||
|
||||
static void soup_server_message_io_http2_send_response (SoupServerMessageIOHTTP2 *io,
|
||||
@@ -146,6 +148,8 @@ soup_server_message_io_http2_destroy (SoupServerMessageIO *iface)
|
||||
{
|
||||
SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)iface;
|
||||
|
||||
+ io->destroyed = TRUE;
|
||||
+
|
||||
if (io->read_source) {
|
||||
g_source_destroy (io->read_source);
|
||||
g_source_unref (io->read_source);
|
||||
@@ -160,10 +164,14 @@ soup_server_message_io_http2_destroy (SoupServerMessageIO *iface)
|
||||
}
|
||||
|
||||
g_clear_object (&io->iostream);
|
||||
- g_clear_pointer (&io->session, nghttp2_session_del);
|
||||
- g_clear_pointer (&io->messages, g_hash_table_unref);
|
||||
+ io->istream = NULL;
|
||||
+ io->ostream = NULL;
|
||||
|
||||
- g_free (io);
|
||||
+ if (io->protected == 0) {
|
||||
+ g_clear_pointer (&io->session, nghttp2_session_del);
|
||||
+ g_clear_pointer (&io->messages, g_hash_table_unref);
|
||||
+ g_free (io);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -321,7 +329,33 @@ static const SoupServerMessageIOFuncs io_funcs = {
|
||||
soup_server_message_io_http2_is_paused
|
||||
};
|
||||
|
||||
+static void
|
||||
+soup_server_message_io_http2_protect (SoupServerMessageIOHTTP2 *io)
|
||||
+{
|
||||
+ io->protected++;
|
||||
+ g_object_ref (io->conn);
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
+soup_server_message_io_http2_unprotect (SoupServerMessageIOHTTP2 *io)
|
||||
+{
|
||||
+ g_object_unref (io->conn);
|
||||
+
|
||||
+ if (--io->protected > 0)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (io->destroyed) {
|
||||
+ g_clear_pointer (&io->session, nghttp2_session_del);
|
||||
+ g_clear_pointer (&io->messages, g_hash_table_unref);
|
||||
+ g_free (io);
|
||||
+
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
io_write (SoupServerMessageIOHTTP2 *io,
|
||||
GError **error)
|
||||
{
|
||||
@@ -336,51 +370,57 @@ io_write (SoupServerMessageIOHTTP2 *io,
|
||||
if (io->write_buffer_size == 0) {
|
||||
/* Done */
|
||||
io->write_buffer = NULL;
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
}
|
||||
|
||||
+ if (!io->ostream)
|
||||
+ return;
|
||||
+
|
||||
gssize ret = g_pollable_stream_write (io->ostream,
|
||||
io->write_buffer + io->written_bytes,
|
||||
io->write_buffer_size - io->written_bytes,
|
||||
FALSE, NULL, error);
|
||||
- if (ret < 0)
|
||||
- return FALSE;
|
||||
-
|
||||
- io->written_bytes += ret;
|
||||
- return TRUE;
|
||||
+ if (ret > 0)
|
||||
+ io->written_bytes += ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
io_write_ready (GObject *stream,
|
||||
SoupServerMessageIOHTTP2 *io)
|
||||
{
|
||||
- SoupServerConnection *conn = io->conn;
|
||||
GError *error = NULL;
|
||||
|
||||
- g_object_ref (conn);
|
||||
+ soup_server_message_io_http2_protect (io);
|
||||
+
|
||||
+ while (!error) {
|
||||
+ if (io->destroyed)
|
||||
+ break;
|
||||
+
|
||||
+ if (!nghttp2_session_want_write (io->session))
|
||||
+ break;
|
||||
|
||||
- while (!error && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && nghttp2_session_want_write (io->session))
|
||||
io_write (io, &error);
|
||||
+ }
|
||||
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
||||
g_error_free (error);
|
||||
- g_object_unref (conn);
|
||||
+ soup_server_message_io_http2_unprotect (io);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
- if (soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io) {
|
||||
+ if (!io->destroyed) {
|
||||
if (error)
|
||||
h2_debug (io, NULL, "[SESSION] IO error: %s", error->message);
|
||||
|
||||
g_clear_pointer (&io->write_source, g_source_unref);
|
||||
|
||||
if (error || (!nghttp2_session_want_read (io->session) && !nghttp2_session_want_write (io->session)))
|
||||
- soup_server_connection_disconnect (conn);
|
||||
+ soup_server_connection_disconnect (io->conn);
|
||||
}
|
||||
|
||||
g_clear_error (&error);
|
||||
- g_object_unref (conn);
|
||||
+ soup_server_message_io_http2_unprotect (io);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
@@ -390,13 +430,12 @@ static gboolean io_write_idle_cb (SoupServerMessageIOHTTP2* io);
|
||||
static void
|
||||
io_try_write (SoupServerMessageIOHTTP2 *io)
|
||||
{
|
||||
- SoupServerConnection *conn = io->conn;
|
||||
GError *error = NULL;
|
||||
|
||||
if (io->write_source)
|
||||
return;
|
||||
|
||||
- if (io->in_callback && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io) {
|
||||
+ if (io->in_callback && !io->destroyed) {
|
||||
if (!nghttp2_session_want_write (io->session))
|
||||
return;
|
||||
|
||||
@@ -416,12 +455,19 @@ io_try_write (SoupServerMessageIOHTTP2 *io)
|
||||
g_clear_pointer (&io->write_idle_source, g_source_unref);
|
||||
}
|
||||
|
||||
- g_object_ref (conn);
|
||||
+ soup_server_message_io_http2_protect (io);
|
||||
+
|
||||
+ while (!error) {
|
||||
+ if (io->destroyed)
|
||||
+ break;
|
||||
+
|
||||
+ if (!nghttp2_session_want_write (io->session))
|
||||
+ break;
|
||||
|
||||
- while (!error && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && !io->in_callback && nghttp2_session_want_write (io->session))
|
||||
io_write (io, &error);
|
||||
+ }
|
||||
|
||||
- if (soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io) {
|
||||
+ if (!io->destroyed) {
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
||||
g_clear_error (&error);
|
||||
io->write_source = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (io->ostream), NULL);
|
||||
@@ -434,11 +480,11 @@ io_try_write (SoupServerMessageIOHTTP2 *io)
|
||||
h2_debug (io, NULL, "[SESSION] IO error: %s", error->message);
|
||||
|
||||
if (error || (!nghttp2_session_want_read (io->session) && !nghttp2_session_want_write (io->session)))
|
||||
- soup_server_connection_disconnect (conn);
|
||||
+ soup_server_connection_disconnect (io->conn);
|
||||
}
|
||||
|
||||
g_clear_error (&error);
|
||||
- g_object_unref (conn);
|
||||
+ soup_server_message_io_http2_unprotect (io);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -481,31 +527,37 @@ static gboolean
|
||||
io_read_ready (GObject *stream,
|
||||
SoupServerMessageIOHTTP2 *io)
|
||||
{
|
||||
- SoupServerConnection *conn = io->conn;
|
||||
gboolean progress = TRUE;
|
||||
GError *error = NULL;
|
||||
|
||||
- g_object_ref (conn);
|
||||
+ soup_server_message_io_http2_protect (io);
|
||||
+
|
||||
+ while (progress) {
|
||||
+ if (io->destroyed)
|
||||
+ break;
|
||||
+
|
||||
+ if (!nghttp2_session_want_read (io->session))
|
||||
+ break;
|
||||
|
||||
- while (progress && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && nghttp2_session_want_read (io->session))
|
||||
progress = io_read (io, &error);
|
||||
+ }
|
||||
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
||||
g_error_free (error);
|
||||
- g_object_unref (conn);
|
||||
+ soup_server_message_io_http2_unprotect (io);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
- if (soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io) {
|
||||
+ if (!io->destroyed) {
|
||||
if (error)
|
||||
h2_debug (io, NULL, "[SESSION] IO error: %s", error->message);
|
||||
|
||||
if (error || (!nghttp2_session_want_read (io->session) && !nghttp2_session_want_write (io->session)))
|
||||
- soup_server_connection_disconnect (conn);
|
||||
+ soup_server_connection_disconnect (io->conn);
|
||||
}
|
||||
|
||||
g_clear_error (&error);
|
||||
- g_object_unref (conn);
|
||||
+ soup_server_message_io_http2_unprotect (io);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
@@ -931,5 +983,10 @@ soup_server_message_io_http2_new (SoupServerConnection *conn,
|
||||
nghttp2_submit_settings (io->session, NGHTTP2_FLAG_NONE, settings, G_N_ELEMENTS (settings));
|
||||
io_try_write (io);
|
||||
|
||||
+#ifdef __clang_analyzer__
|
||||
+ // Suppress false positive about io being destroyed here, since at this point we have only
|
||||
+ // send the initial settings and not callback is called.
|
||||
+ [[clang::suppress]]
|
||||
+#endif
|
||||
return (SoupServerMessageIO *)io;
|
||||
}
|
||||
diff --git a/tests/http2-test.c b/tests/http2-test.c
|
||||
index dafcb95a..ee15e072 100644
|
||||
--- a/tests/http2-test.c
|
||||
+++ b/tests/http2-test.c
|
||||
@@ -1368,6 +1368,40 @@ do_broken_pseudo_header_test (Test *test, gconstpointer data)
|
||||
g_uri_unref (uri);
|
||||
}
|
||||
|
||||
+static void
|
||||
+disconnect_on_got_headers (SoupServerMessage *msg, gpointer user_data)
|
||||
+{
|
||||
+ GUri *uri;
|
||||
+ SoupServerConnection *conn;
|
||||
+
|
||||
+ uri = soup_server_message_get_uri (msg);
|
||||
+ if (!g_str_equal (g_uri_get_path (uri), "/close-on-got-headers"))
|
||||
+ return;
|
||||
+
|
||||
+ conn = soup_server_message_get_connection (msg);
|
||||
+ soup_server_connection_disconnect (conn);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+do_server_disconnect_on_got_headers_test (Test *test, gconstpointer data)
|
||||
+{
|
||||
+ SoupMessage *msg;
|
||||
+ GUri *uri;
|
||||
+ GBytes *response;
|
||||
+ GError *error = NULL;
|
||||
+
|
||||
+ uri = g_uri_parse_relative (base_uri, "/close-on-got-headers", SOUP_HTTP_URI_FLAGS, NULL);
|
||||
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
|
||||
+
|
||||
+ response = soup_test_session_async_send (test->session, msg, NULL, &error);
|
||||
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
|
||||
+
|
||||
+ g_clear_error (&error);
|
||||
+ g_bytes_unref (response);
|
||||
+ g_object_unref (msg);
|
||||
+ g_uri_unref (uri);
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
unpause_message (SoupServerMessage *msg)
|
||||
{
|
||||
@@ -1505,12 +1539,26 @@ server_handler (SoupServer *server,
|
||||
shutdown (fd, SHUT_WR);
|
||||
#endif
|
||||
|
||||
+ soup_server_message_set_response (msg, "text/plain",
|
||||
+ SOUP_MEMORY_STATIC,
|
||||
+ "Success!", 8);
|
||||
+ } else if (strcmp (path, "/close-on-got-headers") == 0) {
|
||||
soup_server_message_set_response (msg, "text/plain",
|
||||
SOUP_MEMORY_STATIC,
|
||||
"Success!", 8);
|
||||
}
|
||||
}
|
||||
|
||||
+static void
|
||||
+server_request_started (SoupServer *server,
|
||||
+ SoupServerMessage *msg,
|
||||
+ SoupServerConnection *conn,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ g_signal_connect (msg, "got-headers",
|
||||
+ G_CALLBACK (disconnect_on_got_headers), NULL);
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
server_basic_auth_callback (SoupAuthDomain *auth_domain,
|
||||
SoupServerMessage *msg,
|
||||
@@ -1537,6 +1585,8 @@ main (int argc, char **argv)
|
||||
return 0;
|
||||
|
||||
server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD | SOUP_TEST_SERVER_HTTP2);
|
||||
+ g_signal_connect (server, "request-started",
|
||||
+ G_CALLBACK (server_request_started), NULL);
|
||||
auth = soup_auth_domain_basic_new ("realm", "http2-test",
|
||||
"auth-callback", server_basic_auth_callback,
|
||||
NULL);
|
||||
@@ -1697,6 +1747,10 @@ main (int argc, char **argv)
|
||||
setup_session,
|
||||
do_broken_pseudo_header_test,
|
||||
teardown_session);
|
||||
+ g_test_add ("/http2/server-disconnect-on-got-headers", Test, NULL,
|
||||
+ setup_session,
|
||||
+ do_server_disconnect_on_got_headers_test,
|
||||
+ teardown_session);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
120
CVE-2026-5119.patch
Normal file
120
CVE-2026-5119.patch
Normal file
@ -0,0 +1,120 @@
|
||||
From 1922f08e4cbae4d13430421b1377aad21ad54025 Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
||||
Date: Fri, 27 Feb 2026 12:03:25 +0100
|
||||
Subject: [PATCH] cookies: do not send cookies to a HTTP proxy for a HTTPS
|
||||
request
|
||||
|
||||
Closes #502
|
||||
---
|
||||
libsoup/cookies/soup-cookie-jar.c | 24 +++++++++++-----
|
||||
tests/proxy-test.c | 47 +++++++++++++++++++++++++++++++
|
||||
2 files changed, 64 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libsoup/cookies/soup-cookie-jar.c b/libsoup/cookies/soup-cookie-jar.c
|
||||
index 51c51d3c..1be56d89 100644
|
||||
--- a/libsoup/cookies/soup-cookie-jar.c
|
||||
+++ b/libsoup/cookies/soup-cookie-jar.c
|
||||
@@ -890,18 +890,28 @@ process_set_cookie_header (SoupMessage *msg, gpointer user_data)
|
||||
g_slist_free (new_cookies);
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+allow_cookies_for_request (SoupMessage *msg)
|
||||
+{
|
||||
+ /* Do not send cookies to a HTTP proxy for a HTTPS request */
|
||||
+ return soup_message_get_method (msg) != SOUP_METHOD_CONNECT || !soup_connection_is_tunnelled (soup_message_get_connection (msg));
|
||||
+}
|
||||
+
|
||||
static void
|
||||
msg_starting_cb (SoupMessage *msg, gpointer feature)
|
||||
{
|
||||
SoupCookieJar *jar = SOUP_COOKIE_JAR (feature);
|
||||
- GSList *cookies;
|
||||
+ GSList *cookies = NULL;
|
||||
+
|
||||
+ if (allow_cookies_for_request (msg)) {
|
||||
+ cookies = soup_cookie_jar_get_cookie_list_with_same_site_info (jar, soup_message_get_uri (msg),
|
||||
+ soup_message_get_first_party (msg),
|
||||
+ soup_message_get_site_for_cookies (msg),
|
||||
+ TRUE,
|
||||
+ SOUP_METHOD_IS_SAFE (soup_message_get_method (msg)),
|
||||
+ soup_message_get_is_top_level_navigation (msg));
|
||||
+ }
|
||||
|
||||
- cookies = soup_cookie_jar_get_cookie_list_with_same_site_info (jar, soup_message_get_uri (msg),
|
||||
- soup_message_get_first_party (msg),
|
||||
- soup_message_get_site_for_cookies (msg),
|
||||
- TRUE,
|
||||
- SOUP_METHOD_IS_SAFE (soup_message_get_method (msg)),
|
||||
- soup_message_get_is_top_level_navigation (msg));
|
||||
if (cookies != NULL) {
|
||||
char *cookie_header = soup_cookies_to_cookie_header (cookies);
|
||||
soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_COOKIE, cookie_header, SOUP_HEADER_VALUE_TRUSTED);
|
||||
diff --git a/tests/proxy-test.c b/tests/proxy-test.c
|
||||
index d730c8a7..7d90c053 100644
|
||||
--- a/tests/proxy-test.c
|
||||
+++ b/tests/proxy-test.c
|
||||
@@ -373,6 +373,52 @@ do_proxy_connect_error_test (gconstpointer data)
|
||||
soup_test_session_abort_unref (session);
|
||||
}
|
||||
|
||||
+static void
|
||||
+connect_message_wrote_headers_cb (SoupMessage *msg, guint *counter)
|
||||
+{
|
||||
+ SoupMessageHeaders *hdrs;
|
||||
+
|
||||
+ *counter += 1;
|
||||
+
|
||||
+ hdrs = soup_message_get_request_headers (msg);
|
||||
+ if (soup_message_get_method (msg) == SOUP_METHOD_CONNECT)
|
||||
+ g_assert_null (soup_message_headers_get_one (hdrs, "Cookie"));
|
||||
+ else
|
||||
+ g_assert_nonnull (soup_message_headers_get_one (hdrs, "Cookie"));
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+request_queued_cb (SoupSession *session, SoupMessage *msg, guint *counter)
|
||||
+{
|
||||
+ g_signal_connect (msg, "wrote-headers", G_CALLBACK (connect_message_wrote_headers_cb), counter);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+do_proxy_secure_cookies_test (void)
|
||||
+{
|
||||
+ SoupSession *session;
|
||||
+ SoupMessage *msg;
|
||||
+ SoupCookieJar *jar;
|
||||
+ guint counter = 0;
|
||||
+
|
||||
+ SOUP_TEST_SKIP_IF_NO_APACHE;
|
||||
+ SOUP_TEST_SKIP_IF_NO_TLS;
|
||||
+
|
||||
+ session = soup_test_session_new ("proxy-resolver", proxy_resolvers[SIMPLE_PROXY], NULL);
|
||||
+ g_signal_connect (session, "request-queued", G_CALLBACK (request_queued_cb), &counter);
|
||||
+
|
||||
+ soup_session_add_feature_by_type (session, SOUP_TYPE_COOKIE_JAR);
|
||||
+ jar = SOUP_COOKIE_JAR (soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR));
|
||||
+
|
||||
+ msg = soup_message_new (SOUP_METHOD_GET, HTTPS_SERVER);
|
||||
+ soup_cookie_jar_set_cookie (jar, soup_message_get_uri (msg), "user=password; secure");
|
||||
+ soup_test_session_send_message (session, msg);
|
||||
+ soup_test_assert_message_status (msg, SOUP_STATUS_OK);
|
||||
+ g_assert_cmpuint (counter, ==, 2);
|
||||
+
|
||||
+ soup_test_session_abort_unref (session);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -404,6 +450,7 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/proxy/redirect", do_proxy_redirect_test);
|
||||
g_test_add_func ("/proxy/auth-cache", do_proxy_auth_cache_test);
|
||||
g_test_add_data_func ("/proxy/connect-error", base_https_uri, do_proxy_connect_error_test);
|
||||
+ g_test_add_func ("/proxy/secure-cookies", do_proxy_secure_cookies_test);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From a2eaa4aab2b62976118a4a62f5041eead5c90a02 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||
Date: Thu, 1 May 2025 08:57:46 -0500
|
||||
Subject: [PATCH] Reduce runtime of http2-body-size test
|
||||
|
||||
This test is *really* slow and I think it would be excessive to increase
|
||||
the test timeout any further, so let's test less data.
|
||||
|
||||
Fixes #444
|
||||
Obsoletes: !309
|
||||
---
|
||||
tests/http2-body-stream-test.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/http2-body-stream-test.c b/tests/http2-body-stream-test.c
|
||||
index 540beb3b..c53f22bc 100644
|
||||
--- a/tests/http2-body-stream-test.c
|
||||
+++ b/tests/http2-body-stream-test.c
|
||||
@@ -24,7 +24,7 @@ static void
|
||||
do_large_data_test (void)
|
||||
{
|
||||
#define CHUNK_SIZE ((gsize)1024 * 1024 * 512) // 512 MiB
|
||||
-#define TEST_SIZE (CHUNK_SIZE * 20) // 10 GiB
|
||||
+#define TEST_SIZE (CHUNK_SIZE * 4) // 2 GiB
|
||||
|
||||
GInputStream *stream = soup_body_input_stream_http2_new ();
|
||||
SoupBodyInputStreamHttp2 *mem_stream = SOUP_BODY_INPUT_STREAM_HTTP2 (stream);
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
%global glib2_version 2.69.1
|
||||
|
||||
Name: libsoup3
|
||||
Version: 3.6.5
|
||||
Release: 3%{?dist}.%{autorelease -n}
|
||||
Version: 3.6.6
|
||||
Release: %autorelease
|
||||
Summary: Soup, an HTTP library implementation
|
||||
|
||||
License: LGPL-2.0-or-later
|
||||
@ -12,35 +12,14 @@ Source0: https://download.gnome.org/sources/libsoup/3.6/libsoup-%{version}.tar.x
|
||||
# Downstream patch, needed due to glib2 gnutls-hmac.patch
|
||||
Patch: no-ntlm-in-fips-mode.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/426
|
||||
Patch: test-timeouts.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/454
|
||||
Patch: server-test-timeout.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/455
|
||||
Patch: http2-body-size-test-timeout.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/450
|
||||
Patch: CVE-2025-32914.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/451
|
||||
Patch: CVE-2025-32908.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/448 (simplified and corrected)
|
||||
Patch: CVE-2025-4035.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/463
|
||||
Patch: CVE-2025-4948.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/408 (simplified)
|
||||
Patch: CVE-2025-32049.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/452
|
||||
Patch: CVE-2025-32907.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/473
|
||||
Patch: CVE-2025-4945-CVE-2025-11021.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/481
|
||||
Patch: CVE-2025-12105.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/491
|
||||
Patch: CVE-2025-14523.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/494
|
||||
Patch: CVE-2026-0719.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/496
|
||||
Patch: CVE-2026-1761.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/516
|
||||
Patch: CVE-2026-5119.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/511
|
||||
Patch: CVE-2026-4271.patch
|
||||
|
||||
BuildRequires: ca-certificates
|
||||
BuildRequires: gcc
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
From 9ff306aa714efd06ceeafacee03298a3665055b1 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||
Date: Wed, 30 Apr 2025 14:13:41 -0500
|
||||
Subject: [PATCH] test-utils: fix deadlock in add_listener_in_thread()
|
||||
|
||||
The mutex is locked in the wrong place here.
|
||||
|
||||
Hopefully fixes #379
|
||||
---
|
||||
tests/test-utils.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tests/test-utils.c b/tests/test-utils.c
|
||||
index df4cee44..5c1e316c 100644
|
||||
--- a/tests/test-utils.c
|
||||
+++ b/tests/test-utils.c
|
||||
@@ -607,9 +607,11 @@ static gboolean
|
||||
add_listener_in_thread (gpointer user_data)
|
||||
{
|
||||
AddListenerData *data = user_data;
|
||||
+ GUri *uri;
|
||||
|
||||
- data->uri = add_listener (data->server, data->scheme, data->host);
|
||||
+ uri = add_listener (data->server, data->scheme, data->host);
|
||||
g_mutex_lock (&data->mutex);
|
||||
+ data->uri = uri;
|
||||
g_cond_signal (&data->cond);
|
||||
g_mutex_unlock (&data->mutex);
|
||||
|
||||
@@ -641,9 +643,9 @@ soup_test_server_get_uri (SoupServer *server,
|
||||
data.host = host;
|
||||
data.uri = NULL;
|
||||
|
||||
- g_mutex_lock (&data.mutex);
|
||||
soup_add_completion (context, add_listener_in_thread, &data);
|
||||
|
||||
+ g_mutex_lock (&data.mutex);
|
||||
while (!data.uri)
|
||||
g_cond_wait (&data.cond, &data.mutex);
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
2
sources
2
sources
@ -1 +1 @@
|
||||
SHA512 (libsoup-3.6.5.tar.xz) = cb44d93b16048d31ae04a8c2416bbe233e0e9bdaf2d9bfe2879260fd3da27e90a0bb05cddbd82cdf81a4a778bd451ad172a14dd31e2fd113c3bbbe13c0029b03
|
||||
SHA512 (libsoup-3.6.6.tar.xz) = 4018dc6f9823fd82cde0fecbb50cd1b5dd0ff4963f92f7ea465e67faf81e71580709eec59914ddbdff317963a88e4a8024e60e44087041175bc21e04022857d2
|
||||
|
||||
@ -1,103 +0,0 @@
|
||||
From e308ed1a277c6b9c35c3f5c0e8e9deb06b2bcf89 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||
Date: Mon, 13 Jan 2025 11:50:35 -0600
|
||||
Subject: [PATCH] Mark several tests as slow
|
||||
|
||||
Let's allow 30 seconds to run most tests, or 5 minutes for tests marked
|
||||
slow. Most of them are fast on my computer:
|
||||
|
||||
1/34 cache-test OK 0.08s 7 subtests passed
|
||||
2/34 chunk-io-test OK 0.08s 1 subtests passed
|
||||
3/34 coding-test OK 0.08s 11 subtests passed
|
||||
4/34 continue-test OK 0.08s 12 subtests passed
|
||||
5/34 cookies-test OK 0.07s 13 subtests passed
|
||||
6/34 date-test OK 0.07s 66 subtests passed
|
||||
7/34 header-parsing-test OK 0.07s 8 subtests passed
|
||||
8/34 logger-test OK 0.05s 6 subtests passed
|
||||
9/34 multipart-test OK 0.05s 4 subtests passed
|
||||
10/34 multithread-test OK 0.05s 8 subtests passed
|
||||
11/34 no-ssl-test OK 0.04s 1 subtests passed
|
||||
12/34 redirect-test OK 0.04s 29 subtests passed
|
||||
13/34 request-body-test OK 0.04s 18 subtests passed
|
||||
14/34 samesite-test OK 0.04s 16 subtests passed
|
||||
15/34 streaming-test OK 0.02s 4 subtests passed
|
||||
16/34 tld-test OK 0.02s 2 subtests passed
|
||||
17/34 uri-parsing-test OK 0.02s 4 subtests passed
|
||||
18/34 sniffing-test OK 0.03s 37 subtests passed
|
||||
19/34 brotli-decompressor-test OK 0.01s 3 subtests passed
|
||||
20/34 unix-socket-test OK 0.01s 1 subtests passed
|
||||
21/34 hsts-db-test OK 0.08s 3 subtests passed
|
||||
22/34 forms-test OK 0.11s 5 subtests passed
|
||||
23/34 server-test OK 0.08s 18 subtests passed
|
||||
24/34 ntlm-test OK 0.10s 21 subtests passed
|
||||
25/34 ssl-test OK 0.12s 7 subtests passed
|
||||
26/34 session-test OK 0.16s 6 subtests passed
|
||||
27/34 misc-test OK 0.22s 18 subtests passed
|
||||
28/34 context-test OK 0.41s 1 subtests passed
|
||||
29/34 server-auth-test OK 0.37s 12 subtests passed
|
||||
30/34 http2-test OK 2.73s 35 subtests passed
|
||||
31/34 websocket-test OK 3.97s 55 subtests passed
|
||||
32/34 timeout-test OK 4.08s 4 subtests passed
|
||||
33/34 http2-body-stream-test OK 8.05s 3 subtests passed
|
||||
34/34 hsts-test OK 12.12s 25 subtests passed
|
||||
|
||||
A 2 minute timeout is not good enough, so let's use 5 minutes.
|
||||
|
||||
I'm not marking hsts-test as slow because it is fast with the exception
|
||||
of some hardcoded 2-3 second timeouts that should never cause the total
|
||||
time to exceed 30s.
|
||||
---
|
||||
.gitlab-ci.yml | 4 ++--
|
||||
tests/meson.build | 14 +++++++-------
|
||||
2 files changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/tests/meson.build b/tests/meson.build
|
||||
index ee118a01..b4dc8064 100644
|
||||
--- a/tests/meson.build
|
||||
+++ b/tests/meson.build
|
||||
@@ -87,8 +87,8 @@ tests = [
|
||||
{'name': 'date'},
|
||||
{'name': 'forms'},
|
||||
{'name': 'header-parsing'},
|
||||
- {'name': 'http2'},
|
||||
- {'name': 'http2-body-stream'},
|
||||
+ {'name': 'http2', 'slow': true},
|
||||
+ {'name': 'http2-body-stream', 'slow': true},
|
||||
{'name': 'hsts'},
|
||||
{'name': 'hsts-db'},
|
||||
{'name': 'logger'},
|
||||
@@ -115,11 +115,12 @@ tests = [
|
||||
]
|
||||
},
|
||||
{'name': 'streaming'},
|
||||
- {'name': 'timeout'},
|
||||
+ {'name': 'timeout', 'slow': true},
|
||||
{'name': 'tld'},
|
||||
{'name': 'uri-parsing'},
|
||||
{'name': 'websocket',
|
||||
- 'dependencies': [libz_dep]},
|
||||
+ 'dependencies': [libz_dep],
|
||||
+ 'slow': true},
|
||||
]
|
||||
|
||||
if brotlidec_dep.found()
|
||||
@@ -219,14 +220,13 @@ foreach test: tests
|
||||
install_dir : installed_tests_execdir,
|
||||
install_rpath : abs_installed_tests_execdir,
|
||||
)
|
||||
- # Increase the timeout as on some architectures the tests could be slower
|
||||
- # than the default 30 seconds.
|
||||
+
|
||||
test(test_name, test_target,
|
||||
args : ['--debug'],
|
||||
env : env,
|
||||
is_parallel : test.get('parallel', true),
|
||||
depends : test.get('depends', []),
|
||||
- timeout : 60,
|
||||
+ timeout : test.get('slow', false) ? 300 : 30,
|
||||
protocol : 'tap',
|
||||
)
|
||||
endforeach
|
||||
--
|
||||
2.49.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user