File libsoup-CVE-2026-1760.patch of Package libsoup.42964
From 6224df5a471e9040a99dd3dc2e91817a701b1bf6 Mon Sep 17 00:00:00 2001
From: Carlos Garcia Campos <cgarcia@igalia.com>
Date: Thu, 29 Jan 2026 16:43:28 +0100
Subject: [PATCH] server: close the connection after responsing a request
containing Content-Length and Transfer-Encoding
Closes #475
---
.../http1/soup-server-message-io-http1.c | 8 ++
libsoup/soup-message-headers.c | 88 +++++++++----------
tests/server-test.c | 4 +-
3 files changed, 52 insertions(+), 48 deletions(-)
Index: libsoup-3.0.4/libsoup/server/soup-server-io.c
===================================================================
--- libsoup-3.0.4.orig/libsoup/server/soup-server-io.c
+++ libsoup-3.0.4/libsoup/server/soup-server-io.c
@@ -599,6 +599,14 @@ parse_headers (SoupServerMessage *msg,
return SOUP_STATUS_BAD_REQUEST;
}
+ /* A server MAY reject a request that contains both Content-Length and
+ * Transfer-Encoding or process such a request in accordance with the
+ * Transfer-Encoding alone. Regardless, the server MUST close the connection
+ * after responding to such a request to avoid the potential attacks
+ */
+ if (*encoding == SOUP_ENCODING_CHUNKED && soup_message_headers_get_one_common (request_headers, SOUP_HEADER_CONTENT_LENGTH))
+ soup_message_headers_replace_common (request_headers, SOUP_HEADER_CONNECTION, "close", 1);
+
/* Generate correct context for request */
req_host = soup_message_headers_get_one_common (request_headers, SOUP_HEADER_HOST);
if (req_host && strchr (req_host, '/')) {
Index: libsoup-3.0.4/libsoup/soup-message-headers.c
===================================================================
--- libsoup-3.0.4.orig/libsoup/soup-message-headers.c
+++ libsoup-3.0.4/libsoup/soup-message-headers.c
@@ -155,19 +155,8 @@ soup_message_headers_set (SoupMessageHea
{
switch (name) {
case SOUP_HEADER_CONTENT_LENGTH:
- if (hdrs->encoding == SOUP_ENCODING_CHUNKED)
- return;
-
- if (value) {
- char *end;
-
- hdrs->content_length = g_ascii_strtoull (value, &end, 10);
- if (*end)
- hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
- else
- hdrs->encoding = SOUP_ENCODING_CONTENT_LENGTH;
- } else
- hdrs->encoding = -1;
+ case SOUP_HEADER_TRANSFER_ENCODING:
+ hdrs->encoding = -1;
break;
case SOUP_HEADER_CONTENT_TYPE:
g_clear_pointer (&hdrs->content_type, g_free);
@@ -193,21 +182,6 @@ soup_message_headers_set (SoupMessageHea
} else
hdrs->expectations = 0;
break;
- case SOUP_HEADER_TRANSFER_ENCODING:
- if (value) {
- /* "identity" is a wrong value according to RFC errata 408,
- * and RFC 7230 does not list it as valid transfer-coding.
- * Nevertheless, the obsolete RFC 2616 stated "identity"
- * as valid, so we can't handle it as unrecognized here
- * for compatibility reasons.
- */
- if (g_ascii_strcasecmp (value, "chunked") == 0)
- hdrs->encoding = SOUP_ENCODING_CHUNKED;
- else if (g_ascii_strcasecmp (value, "identity") != 0)
- hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
- } else
- hdrs->encoding = -1;
- break;
default:
break;
}
@@ -979,30 +953,51 @@ soup_message_headers_foreach (SoupMessag
SoupEncoding
soup_message_headers_get_encoding (SoupMessageHeaders *hdrs)
{
- const char *header;
+ const char *content_length;
+ const char *transfer_encoding;
if (hdrs->encoding != -1)
return hdrs->encoding;
- /* If Transfer-Encoding was set, hdrs->encoding would already
- * be set. So we don't need to check that possibility.
- */
- header = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_CONTENT_LENGTH);
- if (header) {
- soup_message_headers_set (hdrs, SOUP_HEADER_CONTENT_LENGTH, header);
- if (hdrs->encoding != -1)
- return hdrs->encoding;
+ /* Transfer-Encoding is check first because it overrides the Content-Length */
+ transfer_encoding = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING);
+ if (transfer_encoding) {
+ /* "identity" is a wrong value according to RFC errata 408,
+ * and RFC 7230 does not list it as valid transfer-coding.
+ * Nevertheless, the obsolete RFC 2616 stated "identity"
+ * as valid, so we can't handle it as unrecognized here
+ * for compatibility reasons.
+ */
+ if (g_ascii_strcasecmp (transfer_encoding, "chunked") == 0)
+ hdrs->encoding = SOUP_ENCODING_CHUNKED;
+ else if (g_ascii_strcasecmp (transfer_encoding, "identity") != 0)
+ hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
+ } else {
+ content_length = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_CONTENT_LENGTH);
+ if (content_length) {
+ char *end;
+
+ hdrs->content_length = g_ascii_strtoull (content_length, &end, 10);
+ if (*end)
+ hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
+ else
+ hdrs->encoding = SOUP_ENCODING_CONTENT_LENGTH;
+ }
+
+ }
+
+ if (hdrs->encoding == -1) {
+ /* Per RFC 2616 4.4, a response body that doesn't indicate its
+ * encoding otherwise is terminated by connection close, and a
+ * request that doesn't indicate otherwise has no body. Note
+ * that SoupMessage calls soup_message_headers_set_encoding()
+ * to override the response body default for our own
+ * server-side messages.
+ */
+ hdrs->encoding = (hdrs->type == SOUP_MESSAGE_HEADERS_RESPONSE) ?
+ SOUP_ENCODING_EOF : SOUP_ENCODING_NONE;
}
- /* Per RFC 2616 4.4, a response body that doesn't indicate its
- * encoding otherwise is terminated by connection close, and a
- * request that doesn't indicate otherwise has no body. Note
- * that SoupMessage calls soup_message_headers_set_encoding()
- * to override the response body default for our own
- * server-side messages.
- */
- hdrs->encoding = (hdrs->type == SOUP_MESSAGE_HEADERS_RESPONSE) ?
- SOUP_ENCODING_EOF : SOUP_ENCODING_NONE;
return hdrs->encoding;
}