- Add libsoup-CVE-2026-1536.patch: Always validate the headers value when coming from untrusted source (bsc#1257440, CVE-2026-1536, glgo#GNOME/libsoup/commit/5c1a2e9c). - Add libsoup-CVE-2026-1761.patch: multipart: check length of bytes read soup_filter_input_stream_read_until() (bsc#1257598, CVE-2026-1761, glgo#GNOME/libsoup!496). OBS-URL: https://build.opensuse.org/request/show/1330655 OBS-URL: https://build.opensuse.org/package/show/GNOME:Factory/libsoup?expand=0&rev=325
695 lines
35 KiB
Diff
695 lines
35 KiB
Diff
From 7481c8ffc4d3a66ed827c6ca3314b8916a641638 Mon Sep 17 00:00:00 2001
|
|
From: Jonathan Kang <jonathankang@gnome.org>
|
|
Date: Fri, 30 Jan 2026 15:02:29 +0800
|
|
Subject: [PATCH] Always validate the headers value when coming from untrusted
|
|
source
|
|
|
|
Add trusted_value parameter to soup_message_headers_append_common() and
|
|
soup_message_headers_replace_common() and check that the value is valid
|
|
when FALSE is passed.
|
|
|
|
Closes #486
|
|
---
|
|
libsoup/auth/soup-auth-manager.c | 2 +-
|
|
libsoup/auth/soup-auth-ntlm.c | 2 +-
|
|
libsoup/cache/soup-cache.c | 4 +-
|
|
.../content-decoder/soup-content-decoder.c | 2 +-
|
|
libsoup/cookies/soup-cookie-jar.c | 2 +-
|
|
libsoup/cookies/soup-cookie.c | 4 +-
|
|
libsoup/http1/soup-client-message-io-http1.c | 2 +-
|
|
.../http1/soup-server-message-io-http1.c | 4 +-
|
|
libsoup/server/soup-auth-domain.c | 2 +-
|
|
libsoup/server/soup-server-message.c | 4 +-
|
|
libsoup/server/soup-server.c | 4 +-
|
|
libsoup/soup-message-headers-private.h | 6 +-
|
|
libsoup/soup-message-headers.c | 58 ++++++----
|
|
libsoup/soup-message.c | 8 +-
|
|
libsoup/soup-multipart.c | 4 +-
|
|
libsoup/soup-session.c | 4 +-
|
|
libsoup/websocket/soup-websocket.c | 28 ++---
|
|
tests/header-parsing-test.c | 108 ++++++++++++++----
|
|
tests/http2-test.c | 4 +-
|
|
19 files changed, 165 insertions(+), 87 deletions(-)
|
|
|
|
Index: libsoup-3.6.5/libsoup/auth/soup-auth-manager.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/auth/soup-auth-manager.c
|
|
+++ libsoup-3.6.5/libsoup/auth/soup-auth-manager.c
|
|
@@ -441,7 +441,7 @@ update_authorization_header (SoupMessage
|
|
if (!token)
|
|
return;
|
|
|
|
- soup_message_headers_replace_common (soup_message_get_request_headers (msg), authorization_header, token);
|
|
+ soup_message_headers_replace_common (soup_message_get_request_headers (msg), authorization_header, token, TRUE);
|
|
g_free (token);
|
|
}
|
|
|
|
Index: libsoup-3.6.5/libsoup/auth/soup-auth-ntlm.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/auth/soup-auth-ntlm.c
|
|
+++ libsoup-3.6.5/libsoup/auth/soup-auth-ntlm.c
|
|
@@ -328,7 +328,7 @@ soup_auth_ntlm_update_connection (SoupCo
|
|
conn->state = SOUP_NTLM_FAILED;
|
|
if (soup_message_is_keepalive (msg)) {
|
|
soup_message_headers_append_common (soup_message_get_response_headers (msg),
|
|
- SOUP_HEADER_CONNECTION, "close");
|
|
+ SOUP_HEADER_CONNECTION, "close", TRUE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
Index: libsoup-3.6.5/libsoup/cache/soup-cache.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/cache/soup-cache.c
|
|
+++ libsoup-3.6.5/libsoup/cache/soup-cache.c
|
|
@@ -1471,11 +1471,11 @@ soup_cache_generate_conditional_request
|
|
if (last_modified)
|
|
soup_message_headers_append_common (soup_message_get_request_headers (msg),
|
|
SOUP_HEADER_IF_MODIFIED_SINCE,
|
|
- last_modified);
|
|
+ last_modified, TRUE);
|
|
if (etag)
|
|
soup_message_headers_append_common (soup_message_get_request_headers (msg),
|
|
SOUP_HEADER_IF_NONE_MATCH,
|
|
- etag);
|
|
+ etag, TRUE);
|
|
|
|
return msg;
|
|
}
|
|
Index: libsoup-3.6.5/libsoup/content-decoder/soup-content-decoder.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/content-decoder/soup-content-decoder.c
|
|
+++ libsoup-3.6.5/libsoup/content-decoder/soup-content-decoder.c
|
|
@@ -249,7 +249,7 @@ soup_content_decoder_request_queued (Sou
|
|
#endif
|
|
|
|
soup_message_headers_append_common (soup_message_get_request_headers (msg),
|
|
- SOUP_HEADER_ACCEPT_ENCODING, header);
|
|
+ SOUP_HEADER_ACCEPT_ENCODING, header, TRUE);
|
|
}
|
|
}
|
|
|
|
Index: libsoup-3.6.5/libsoup/cookies/soup-cookie-jar.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/cookies/soup-cookie-jar.c
|
|
+++ libsoup-3.6.5/libsoup/cookies/soup-cookie-jar.c
|
|
@@ -899,7 +899,7 @@ msg_starting_cb (SoupMessage *msg, gpoin
|
|
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_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_COOKIE, cookie_header, TRUE);
|
|
g_free (cookie_header);
|
|
g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
|
|
} else {
|
|
Index: libsoup-3.6.5/libsoup/cookies/soup-cookie.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/cookies/soup-cookie.c
|
|
+++ libsoup-3.6.5/libsoup/cookies/soup-cookie.c
|
|
@@ -988,7 +988,7 @@ soup_cookies_to_response (GSList *cookie
|
|
while (cookies) {
|
|
serialize_cookie (cookies->data, header, TRUE);
|
|
soup_message_headers_append_common (soup_message_get_response_headers (msg),
|
|
- SOUP_HEADER_SET_COOKIE, header->str);
|
|
+ SOUP_HEADER_SET_COOKIE, header->str, TRUE);
|
|
g_string_truncate (header, 0);
|
|
cookies = cookies->next;
|
|
}
|
|
@@ -1019,7 +1019,7 @@ soup_cookies_to_request (GSList *cookies
|
|
cookies = cookies->next;
|
|
}
|
|
soup_message_headers_replace_common (soup_message_get_request_headers (msg),
|
|
- SOUP_HEADER_COOKIE, header->str);
|
|
+ SOUP_HEADER_COOKIE, header->str, TRUE);
|
|
g_string_free (header, TRUE);
|
|
}
|
|
|
|
Index: libsoup-3.6.5/libsoup/http1/soup-client-message-io-http1.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/http1/soup-client-message-io-http1.c
|
|
+++ libsoup-3.6.5/libsoup/http1/soup-client-message-io-http1.c
|
|
@@ -568,7 +568,7 @@ io_read (SoupClientMessageIOHTTP1 *clien
|
|
* closed when we're done.
|
|
*/
|
|
soup_message_headers_append_common (soup_message_get_request_headers (msg),
|
|
- SOUP_HEADER_CONNECTION, "close");
|
|
+ SOUP_HEADER_CONNECTION, "close", TRUE);
|
|
soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_RESPONSE_END);
|
|
io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
|
|
break;
|
|
Index: libsoup-3.6.5/libsoup/server/http1/soup-server-message-io-http1.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/server/http1/soup-server-message-io-http1.c
|
|
+++ libsoup-3.6.5/libsoup/server/http1/soup-server-message-io-http1.c
|
|
@@ -305,7 +305,7 @@ handle_partial_get (SoupServerMessage *m
|
|
if (content_type) {
|
|
soup_message_headers_append_common (part_headers,
|
|
SOUP_HEADER_CONTENT_TYPE,
|
|
- content_type);
|
|
+ content_type, TRUE);
|
|
}
|
|
soup_message_headers_set_content_range (part_headers,
|
|
ranges[i].start,
|
|
@@ -763,7 +763,7 @@ io_read (SoupServerMessageIOHTTP1 *serve
|
|
* closed when we're done.
|
|
*/
|
|
soup_server_message_set_status (msg, status, NULL);
|
|
- soup_message_headers_append_common (request_headers, SOUP_HEADER_CONNECTION, "close");
|
|
+ soup_message_headers_append_common (request_headers, SOUP_HEADER_CONNECTION, "close", TRUE);
|
|
io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
|
|
break;
|
|
}
|
|
Index: libsoup-3.6.5/libsoup/server/soup-auth-domain.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/server/soup-auth-domain.c
|
|
+++ libsoup-3.6.5/libsoup/server/soup-auth-domain.c
|
|
@@ -581,6 +581,6 @@ soup_auth_domain_challenge (SoupAuthDoma
|
|
priv->proxy ?
|
|
SOUP_HEADER_PROXY_AUTHENTICATE :
|
|
SOUP_HEADER_WWW_AUTHENTICATE,
|
|
- challenge);
|
|
+ challenge, FALSE);
|
|
g_free (challenge);
|
|
}
|
|
Index: libsoup-3.6.5/libsoup/server/soup-server-message.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/server/soup-server-message.c
|
|
+++ libsoup-3.6.5/libsoup/server/soup-server-message.c
|
|
@@ -939,7 +939,7 @@ soup_server_message_set_response (SoupSe
|
|
|
|
soup_message_headers_replace_common (msg->response_headers,
|
|
SOUP_HEADER_CONTENT_TYPE,
|
|
- content_type);
|
|
+ content_type, FALSE);
|
|
soup_message_body_append (msg->response_body, resp_use,
|
|
resp_body, resp_length);
|
|
} else {
|
|
@@ -980,7 +980,7 @@ soup_server_message_set_redirect (SoupSe
|
|
soup_server_message_set_status (msg, status_code, NULL);
|
|
location_str = g_uri_to_string (location);
|
|
soup_message_headers_replace_common (msg->response_headers, SOUP_HEADER_LOCATION,
|
|
- location_str);
|
|
+ location_str, FALSE);
|
|
g_free (location_str);
|
|
g_uri_unref (location);
|
|
}
|
|
Index: libsoup-3.6.5/libsoup/server/soup-server.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/server/soup-server.c
|
|
+++ libsoup-3.6.5/libsoup/server/soup-server.c
|
|
@@ -857,7 +857,7 @@ got_headers (SoupServer *server,
|
|
return;
|
|
}
|
|
|
|
- soup_message_headers_replace_common (headers, SOUP_HEADER_DATE, date_string);
|
|
+ soup_message_headers_replace_common (headers, SOUP_HEADER_DATE, date_string, TRUE);
|
|
g_free (date_string);
|
|
g_date_time_unref (date);
|
|
|
|
@@ -1041,7 +1041,7 @@ request_started_cb (SoupServer
|
|
|
|
headers = soup_server_message_get_response_headers (msg);
|
|
soup_message_headers_append_common (headers, SOUP_HEADER_SERVER,
|
|
- priv->server_header);
|
|
+ priv->server_header, FALSE);
|
|
}
|
|
|
|
g_signal_emit (server, signals[REQUEST_STARTED], 0, msg);
|
|
Index: libsoup-3.6.5/libsoup/soup-message-headers-private.h
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/soup-message-headers-private.h
|
|
+++ libsoup-3.6.5/libsoup/soup-message-headers-private.h
|
|
@@ -15,7 +15,8 @@ gboolean soup_message_headers_append_
|
|
const char *value);
|
|
gboolean soup_message_headers_append_common (SoupMessageHeaders *hdrs,
|
|
SoupHeaderName name,
|
|
- const char *value);
|
|
+ const char *value,
|
|
+ gboolean trusted_value);
|
|
const char *soup_message_headers_get_one_common (SoupMessageHeaders *hdrs,
|
|
SoupHeaderName name);
|
|
const char *soup_message_headers_get_list_common (SoupMessageHeaders *hdrs,
|
|
@@ -24,7 +25,8 @@ void soup_message_headers_remove_
|
|
SoupHeaderName name);
|
|
void soup_message_headers_replace_common (SoupMessageHeaders *hdrs,
|
|
SoupHeaderName name,
|
|
- const char *value);
|
|
+ const char *value,
|
|
+ gboolean trusted_value);
|
|
gboolean soup_message_headers_header_contains_common (SoupMessageHeaders *hdrs,
|
|
SoupHeaderName name,
|
|
const char *token);
|
|
Index: libsoup-3.6.5/libsoup/soup-message-headers.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/soup-message-headers.c
|
|
+++ libsoup-3.6.5/libsoup/soup-message-headers.c
|
|
@@ -273,10 +273,21 @@ soup_message_headers_clean_connection_he
|
|
soup_header_free_list (tokens);
|
|
}
|
|
|
|
+static inline gboolean is_valid_header_name (const char *name)
|
|
+{
|
|
+ return name && *name && strpbrk (name, " \t\r\n:") == NULL;
|
|
+}
|
|
+
|
|
+static inline gboolean is_valid_header_value (const char *value)
|
|
+{
|
|
+ return value && strpbrk (value, "\r\n") == NULL;
|
|
+}
|
|
+
|
|
gboolean
|
|
soup_message_headers_append_common (SoupMessageHeaders *hdrs,
|
|
SoupHeaderName name,
|
|
- const char *value)
|
|
+ const char *value,
|
|
+ gboolean trusted_value)
|
|
{
|
|
SoupCommonHeader header;
|
|
if (name == SOUP_HEADER_HOST && soup_message_headers_get_one (hdrs, "Host")) {
|
|
@@ -284,6 +295,11 @@ soup_message_headers_append_common (Soup
|
|
return FALSE;
|
|
}
|
|
|
|
+ if (!trusted_value && !is_valid_header_value (value)) {
|
|
+ g_warning ("soup_message_headers_append: Rejecting bad value '%s'", value);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
if (!hdrs->common_headers)
|
|
hdrs->common_headers = g_array_sized_new (FALSE, FALSE, sizeof (SoupCommonHeader), 6);
|
|
|
|
@@ -308,28 +324,19 @@ soup_message_headers_append_internal (So
|
|
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
|
|
- * be a security hole, so we want to fail here even if
|
|
- * compiled with G_DISABLE_CHECKS.
|
|
- */
|
|
-#ifndef G_DISABLE_CHECKS
|
|
- 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 FALSE;
|
|
- }
|
|
- if (strpbrk (value, "\r\n")) {
|
|
- g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value);
|
|
+ if (!is_valid_header_name (name)) {
|
|
+ g_warning ("soup_message_headers_append: Rejecting bad name '%s'", name);
|
|
return FALSE;
|
|
}
|
|
-#endif
|
|
|
|
header_name = soup_header_name_from_string (name);
|
|
if (header_name != SOUP_HEADER_UNKNOWN) {
|
|
- return soup_message_headers_append_common (hdrs, header_name, value);
|
|
+ return soup_message_headers_append_common (hdrs, header_name, value, FALSE);
|
|
+ }
|
|
+
|
|
+ if (!is_valid_header_value (value)) {
|
|
+ g_warning ("soup_message_headers_append: Rejecting bad value '%s'", value);
|
|
+ return FALSE;
|
|
}
|
|
|
|
if (!hdrs->uncommon_headers)
|
|
@@ -387,10 +394,11 @@ soup_message_headers_append_untrusted_da
|
|
void
|
|
soup_message_headers_replace_common (SoupMessageHeaders *hdrs,
|
|
SoupHeaderName name,
|
|
- const char *value)
|
|
+ const char *value,
|
|
+ gboolean trusted_value)
|
|
{
|
|
soup_message_headers_remove_common (hdrs, name);
|
|
- soup_message_headers_append_common (hdrs, name, value);
|
|
+ soup_message_headers_append_common (hdrs, name, value, trusted_value);
|
|
}
|
|
|
|
/**
|
|
@@ -1024,7 +1032,7 @@ soup_message_headers_set_encoding (SoupM
|
|
|
|
case SOUP_ENCODING_CHUNKED:
|
|
soup_message_headers_remove_common (hdrs, SOUP_HEADER_CONTENT_LENGTH);
|
|
- soup_message_headers_replace_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING, "chunked");
|
|
+ soup_message_headers_replace_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING, "chunked", TRUE);
|
|
break;
|
|
|
|
default:
|
|
@@ -1087,7 +1095,7 @@ soup_message_headers_set_content_length
|
|
g_snprintf (length, sizeof (length), "%" G_GUINT64_FORMAT,
|
|
content_length);
|
|
soup_message_headers_remove_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING);
|
|
- soup_message_headers_replace_common (hdrs, SOUP_HEADER_CONTENT_LENGTH, length);
|
|
+ soup_message_headers_replace_common (hdrs, SOUP_HEADER_CONTENT_LENGTH, length, TRUE);
|
|
}
|
|
|
|
/**
|
|
@@ -1140,7 +1148,7 @@ soup_message_headers_set_expectations (S
|
|
g_return_if_fail ((expectations & ~SOUP_EXPECTATION_CONTINUE) == 0);
|
|
|
|
if (expectations & SOUP_EXPECTATION_CONTINUE)
|
|
- soup_message_headers_replace_common (hdrs, SOUP_HEADER_EXPECT, "100-continue");
|
|
+ soup_message_headers_replace_common (hdrs, SOUP_HEADER_EXPECT, "100-continue", TRUE);
|
|
else
|
|
soup_message_headers_remove_common (hdrs, SOUP_HEADER_EXPECT);
|
|
}
|
|
@@ -1378,7 +1386,7 @@ soup_message_headers_set_ranges (SoupMes
|
|
}
|
|
}
|
|
|
|
- soup_message_headers_replace_common (hdrs, SOUP_HEADER_RANGE, header->str);
|
|
+ soup_message_headers_replace_common (hdrs, SOUP_HEADER_RANGE, header->str, TRUE);
|
|
g_string_free (header, TRUE);
|
|
}
|
|
|
|
@@ -1499,7 +1507,7 @@ soup_message_headers_set_content_range (
|
|
header = g_strdup_printf ("bytes %" G_GINT64_FORMAT "-%"
|
|
G_GINT64_FORMAT "/*", start, end);
|
|
}
|
|
- soup_message_headers_replace_common (hdrs, SOUP_HEADER_CONTENT_RANGE, header);
|
|
+ soup_message_headers_replace_common (hdrs, SOUP_HEADER_CONTENT_RANGE, header, TRUE);
|
|
g_free (header);
|
|
}
|
|
|
|
@@ -1574,7 +1582,7 @@ set_content_foo (SoupMessageHeaders *hdr
|
|
}
|
|
}
|
|
|
|
- soup_message_headers_replace_common (hdrs, header_name, str->str);
|
|
+ soup_message_headers_replace_common (hdrs, header_name, str->str, FALSE);
|
|
g_string_free (str, TRUE);
|
|
}
|
|
|
|
Index: libsoup-3.6.5/libsoup/soup-message.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/soup-message.c
|
|
+++ libsoup-3.6.5/libsoup/soup-message.c
|
|
@@ -1158,7 +1158,7 @@ soup_message_set_request_body (SoupMessa
|
|
g_warn_if_fail (strchr (content_type, '/') != NULL);
|
|
|
|
if (soup_message_headers_get_content_type (priv->request_headers, NULL) != content_type)
|
|
- soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_CONTENT_TYPE, content_type);
|
|
+ soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_CONTENT_TYPE, content_type, FALSE);
|
|
}
|
|
|
|
if (content_length == -1)
|
|
@@ -3235,12 +3235,12 @@ soup_message_set_request_host_from_uri (
|
|
|
|
host = soup_uri_get_host_for_headers (uri);
|
|
if (soup_uri_uses_default_port (uri))
|
|
- soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, host);
|
|
+ soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, host, FALSE);
|
|
else {
|
|
char *value;
|
|
|
|
value = g_strdup_printf ("%s:%d", host, g_uri_get_port (uri));
|
|
- soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, value);
|
|
+ soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, value, FALSE);
|
|
g_free (value);
|
|
}
|
|
g_free (host);
|
|
@@ -3280,7 +3280,7 @@ soup_message_force_keep_alive_if_needed
|
|
if (!soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Keep-Alive") &&
|
|
!soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "close") &&
|
|
!soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Upgrade")) {
|
|
- soup_message_headers_append_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Keep-Alive");
|
|
+ soup_message_headers_append_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Keep-Alive", TRUE);
|
|
}
|
|
}
|
|
|
|
Index: libsoup-3.6.5/libsoup/soup-multipart.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/soup-multipart.c
|
|
+++ libsoup-3.6.5/libsoup/soup-multipart.c
|
|
@@ -354,12 +354,12 @@ soup_multipart_append_form_file (SoupMul
|
|
soup_header_g_string_append_param_quoted (disposition, "filename", filename);
|
|
}
|
|
soup_message_headers_append_common (headers, SOUP_HEADER_CONTENT_DISPOSITION,
|
|
- disposition->str);
|
|
+ disposition->str, FALSE);
|
|
g_string_free (disposition, TRUE);
|
|
|
|
if (content_type) {
|
|
soup_message_headers_append_common (headers, SOUP_HEADER_CONTENT_TYPE,
|
|
- content_type);
|
|
+ content_type, FALSE);
|
|
}
|
|
|
|
g_ptr_array_add (multipart->headers, headers);
|
|
Index: libsoup-3.6.5/libsoup/soup-session.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/soup-session.c
|
|
+++ libsoup-3.6.5/libsoup/soup-session.c
|
|
@@ -1437,10 +1437,10 @@ soup_session_send_queue_item (SoupSessio
|
|
|
|
request_headers = soup_message_get_request_headers (item->msg);
|
|
if (priv->user_agent)
|
|
- soup_message_headers_replace_common (request_headers, SOUP_HEADER_USER_AGENT, priv->user_agent);
|
|
+ soup_message_headers_replace_common (request_headers, SOUP_HEADER_USER_AGENT, priv->user_agent, FALSE);
|
|
|
|
if (priv->accept_language && !soup_message_headers_get_list_common (request_headers, SOUP_HEADER_ACCEPT_LANGUAGE))
|
|
- soup_message_headers_append_common (request_headers, SOUP_HEADER_ACCEPT_LANGUAGE, priv->accept_language);
|
|
+ soup_message_headers_append_common (request_headers, SOUP_HEADER_ACCEPT_LANGUAGE, priv->accept_language, FALSE);
|
|
|
|
conn = soup_message_get_connection (item->msg);
|
|
soup_message_set_http_version (item->msg, soup_connection_get_negotiated_protocol (conn));
|
|
Index: libsoup-3.6.5/libsoup/websocket/soup-websocket.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/libsoup/websocket/soup-websocket.c
|
|
+++ libsoup-3.6.5/libsoup/websocket/soup-websocket.c
|
|
@@ -257,21 +257,21 @@ soup_websocket_client_prepare_handshake
|
|
|
|
g_return_if_fail (SOUP_IS_MESSAGE (msg));
|
|
|
|
- soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_UPGRADE, "websocket");
|
|
- soup_message_headers_append_common (soup_message_get_request_headers (msg), SOUP_HEADER_CONNECTION, "Upgrade");
|
|
+ soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_UPGRADE, "websocket", TRUE);
|
|
+ soup_message_headers_append_common (soup_message_get_request_headers (msg), SOUP_HEADER_CONNECTION, "Upgrade", TRUE);
|
|
|
|
raw[0] = g_random_int ();
|
|
raw[1] = g_random_int ();
|
|
raw[2] = g_random_int ();
|
|
raw[3] = g_random_int ();
|
|
key = g_base64_encode ((const guchar *)raw, sizeof (raw));
|
|
- soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_KEY, key);
|
|
+ soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_KEY, key, TRUE);
|
|
g_free (key);
|
|
|
|
- soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_VERSION, "13");
|
|
+ soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_VERSION, "13", TRUE);
|
|
|
|
if (origin)
|
|
- soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_ORIGIN, origin);
|
|
+ soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_ORIGIN, origin, FALSE);
|
|
|
|
if (protocols && *protocols) {
|
|
char *protocols_str;
|
|
@@ -279,7 +279,7 @@ soup_websocket_client_prepare_handshake
|
|
protocols_str = g_strjoinv (", ", protocols);
|
|
if (*protocols_str)
|
|
soup_message_headers_replace_common (soup_message_get_request_headers (msg),
|
|
- SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL, protocols_str);
|
|
+ SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL, protocols_str, TRUE);
|
|
g_free (protocols_str);
|
|
}
|
|
|
|
@@ -316,7 +316,7 @@ soup_websocket_client_prepare_handshake
|
|
if (extensions->len > 0) {
|
|
soup_message_headers_replace_common (soup_message_get_request_headers (msg),
|
|
SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS,
|
|
- extensions->str);
|
|
+ extensions->str, FALSE);
|
|
} else {
|
|
soup_message_headers_remove_common (soup_message_get_request_headers (msg),
|
|
SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS);
|
|
@@ -633,7 +633,7 @@ respond_handshake_forbidden (SoupServerM
|
|
{
|
|
soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN, NULL);
|
|
soup_message_headers_append_common (soup_server_message_get_response_headers (msg),
|
|
- SOUP_HEADER_CONNECTION, "close");
|
|
+ SOUP_HEADER_CONNECTION, "close", TRUE);
|
|
soup_server_message_set_response (msg, "text/html", SOUP_MEMORY_COPY,
|
|
RESPONSE_FORBIDDEN, strlen (RESPONSE_FORBIDDEN));
|
|
}
|
|
@@ -650,7 +650,7 @@ respond_handshake_bad (SoupServerMessage
|
|
text = g_strdup_printf (RESPONSE_BAD, why);
|
|
soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL);
|
|
soup_message_headers_append_common (soup_server_message_get_response_headers (msg),
|
|
- SOUP_HEADER_CONNECTION, "close");
|
|
+ SOUP_HEADER_CONNECTION, "close", TRUE);
|
|
soup_server_message_set_response (msg, "text/html", SOUP_MEMORY_TAKE,
|
|
text, strlen (text));
|
|
}
|
|
@@ -716,18 +716,18 @@ soup_websocket_server_process_handshake
|
|
|
|
soup_server_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS, NULL);
|
|
response_headers = soup_server_message_get_response_headers (msg);
|
|
- soup_message_headers_replace_common (response_headers, SOUP_HEADER_UPGRADE, "websocket");
|
|
- soup_message_headers_append_common (response_headers, SOUP_HEADER_CONNECTION, "Upgrade");
|
|
+ soup_message_headers_replace_common (response_headers, SOUP_HEADER_UPGRADE, "websocket", TRUE);
|
|
+ soup_message_headers_append_common (response_headers, SOUP_HEADER_CONNECTION, "Upgrade", TRUE);
|
|
|
|
request_headers = soup_server_message_get_request_headers (msg);
|
|
key = soup_message_headers_get_one_common (request_headers, SOUP_HEADER_SEC_WEBSOCKET_KEY);
|
|
accept_key = compute_accept_key (key);
|
|
- soup_message_headers_append_common (response_headers, SOUP_HEADER_SEC_WEBSOCKET_ACCEPT, accept_key);
|
|
+ soup_message_headers_append_common (response_headers, SOUP_HEADER_SEC_WEBSOCKET_ACCEPT, accept_key, TRUE);
|
|
g_free (accept_key);
|
|
|
|
choose_subprotocol (msg, (const char **) protocols, &chosen_protocol);
|
|
if (chosen_protocol)
|
|
- soup_message_headers_append_common (response_headers, SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL, chosen_protocol);
|
|
+ soup_message_headers_append_common (response_headers, SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL, chosen_protocol, TRUE);
|
|
|
|
extensions = soup_message_headers_get_list_common (request_headers, SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS);
|
|
if (extensions && *extensions) {
|
|
@@ -758,7 +758,7 @@ soup_websocket_server_process_handshake
|
|
if (response_extensions->len > 0) {
|
|
soup_message_headers_replace_common (response_headers,
|
|
SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS,
|
|
- response_extensions->str);
|
|
+ response_extensions->str, FALSE);
|
|
} else {
|
|
soup_message_headers_remove_common (response_headers,
|
|
SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS);
|
|
Index: libsoup-3.6.5/tests/header-parsing-test.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/tests/header-parsing-test.c
|
|
+++ libsoup-3.6.5/tests/header-parsing-test.c
|
|
@@ -1301,16 +1301,21 @@ do_append_param_tests (void)
|
|
|
|
static const struct {
|
|
const char *description, *name, *value;
|
|
-} bad_headers[] = {
|
|
- { "Empty name", "", "value" },
|
|
- { "Name with spaces", "na me", "value" },
|
|
- { "Name with colon", "na:me", "value" },
|
|
- { "Name with CR", "na\rme", "value" },
|
|
- { "Name with LF", "na\nme", "value" },
|
|
- { "Name with tab", "na\tme", "value" },
|
|
- { "Value with CR", "name", "val\rue" },
|
|
- { "Value with LF", "name", "val\nue" },
|
|
- { "Value with LWS", "name", "val\r\n ue" }
|
|
+} bad_header_names[] = {
|
|
+ { "empty name", "", "value" },
|
|
+ { "name with spaces", "na me", "value" },
|
|
+ { "name with colon", "na:me", "value" },
|
|
+ { "name with CR", "na\rme", "value" },
|
|
+ { "name with LF", "na\nme", "value" },
|
|
+ { "name with tab", "na\tme", "value" }
|
|
+};
|
|
+
|
|
+static const struct {
|
|
+ const char *description, *name, *value;
|
|
+} bad_header_values[] = {
|
|
+ { "value with CR", "name", "val\rue" },
|
|
+ { "value with LF", "name", "val\nue" },
|
|
+ { "value with LWS", "name", "val\r\n ue" }
|
|
};
|
|
|
|
static void
|
|
@@ -1320,15 +1325,79 @@ do_bad_header_tests (void)
|
|
int i;
|
|
|
|
hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
|
|
- for (i = 0; i < G_N_ELEMENTS (bad_headers); i++) {
|
|
- debug_printf (1, " %s\n", bad_headers[i].description);
|
|
|
|
- g_test_expect_message ("libsoup", G_LOG_LEVEL_CRITICAL,
|
|
- "*soup_message_headers_append*assertion*failed*");
|
|
- soup_message_headers_append (hdrs, bad_headers[i].name,
|
|
- bad_headers[i].value);
|
|
- g_test_assert_expected_messages ();
|
|
+ /* soup_message_headers_append: bad names */
|
|
+ for (i = 0; i < G_N_ELEMENTS (bad_header_names); i++) {
|
|
+ debug_printf (1, " Append %s\n", bad_header_names[i].description);
|
|
+
|
|
+ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
|
|
+ "*soup_message_headers_append*Rejecting bad name*");
|
|
+ soup_message_headers_append (hdrs, bad_header_names[i].name,
|
|
+ bad_header_names[i].value);
|
|
+ g_test_assert_expected_messages ();
|
|
+ }
|
|
+
|
|
+ /* soup_message_headers_append: bad values */
|
|
+ for (i = 0; i < G_N_ELEMENTS (bad_header_values); i++) {
|
|
+ debug_printf (1, " Append %s\n", bad_header_values[i].description);
|
|
+
|
|
+ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
|
|
+ "*soup_message_headers_append*Rejecting bad value*");
|
|
+ soup_message_headers_append (hdrs, bad_header_values[i].name,
|
|
+ bad_header_values[i].value);
|
|
+ g_test_assert_expected_messages ();
|
|
+ }
|
|
+
|
|
+ /* soup_message_headers_replace: bad values */
|
|
+ for (i = 0; i < G_N_ELEMENTS (bad_header_values); i++) {
|
|
+ debug_printf (1, " Replace %s\n", bad_header_values[i].description);
|
|
+
|
|
+ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
|
|
+ "*soup_message_headers_append*Rejecting bad value*");
|
|
+ soup_message_headers_replace (hdrs, bad_header_values[i].name,
|
|
+ bad_header_values[i].value);
|
|
+ g_test_assert_expected_messages ();
|
|
}
|
|
+
|
|
+ /* soup_message_headers_set_content_type: bad values */
|
|
+ for (i = 0; i < G_N_ELEMENTS (bad_header_values); i++) {
|
|
+ GHashTable *params;
|
|
+
|
|
+ debug_printf (1, " Content type with %s\n", bad_header_values[i].description);
|
|
+
|
|
+ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
|
|
+ "*soup_message_headers_append*Rejecting bad value*");
|
|
+ soup_message_headers_set_content_type (hdrs, bad_header_values[i].value, NULL);
|
|
+ g_test_assert_expected_messages ();
|
|
+
|
|
+ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
|
|
+ "*soup_message_headers_append*Rejecting bad value*");
|
|
+ params = g_hash_table_new (g_str_hash, g_str_equal);
|
|
+ g_hash_table_insert (params, CONTENT_TYPE_TEST_ATTRIBUTE, (gpointer)bad_header_values[i].value);
|
|
+ soup_message_headers_set_content_type (hdrs, CONTENT_TYPE_TEST_MIME_TYPE, params);
|
|
+ g_hash_table_destroy (params);
|
|
+ g_test_assert_expected_messages ();
|
|
+ }
|
|
+
|
|
+ /* soup_message_headers_set_content_disposition: bad values */
|
|
+ for (i = 0; i < G_N_ELEMENTS (bad_header_values); i++) {
|
|
+ GHashTable *params;
|
|
+
|
|
+ debug_printf (1, " Content disposition with %s\n", bad_header_values[i].description);
|
|
+
|
|
+ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
|
|
+ "*soup_message_headers_append*Rejecting bad value*");
|
|
+ soup_message_headers_set_content_disposition (hdrs, bad_header_values[i].value, NULL);
|
|
+ g_test_assert_expected_messages ();
|
|
+
|
|
+ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
|
|
+ "*soup_message_headers_append*Rejecting bad value*");
|
|
+ params = g_hash_table_new (g_str_hash, g_str_equal);
|
|
+ g_hash_table_insert (params, "filename", (gpointer)bad_header_values[i].value);
|
|
+ soup_message_headers_set_content_disposition (hdrs, "attachment", params);
|
|
+ g_hash_table_destroy (params);
|
|
+ g_test_assert_expected_messages ();
|
|
+ }
|
|
soup_message_headers_unref (hdrs);
|
|
}
|
|
|
|
Index: libsoup-3.6.5/tests/http2-test.c
|
|
===================================================================
|
|
--- libsoup-3.6.5.orig/tests/http2-test.c
|
|
+++ libsoup-3.6.5/tests/http2-test.c
|
|
@@ -1365,8 +1365,8 @@ server_handler (SoupServer *serve
|
|
SoupMessageHeaders *response_headers;
|
|
|
|
response_headers = soup_server_message_get_response_headers (msg);
|
|
- /* Use soup_message_headers_append_common to skip the validation check. */
|
|
- soup_message_headers_append_common (response_headers, SOUP_HEADER_CONTENT_TYPE, "\r");
|
|
+ /* Use soup_message_headers_append_common with trusted_value=TRUE to skip the validation check. */
|
|
+ soup_message_headers_append_common (response_headers, SOUP_HEADER_CONTENT_TYPE, "\r", TRUE);
|
|
soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
|
|
} else if (strcmp (path, "/invalid-header-rfc9113") == 0) {
|
|
SoupMessageHeaders *response_headers;
|