From 0fca37e0fce479284e62091ffb9b7d6caff1c7e4 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos 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 Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/6224df5a471e9040a99dd3dc2e91817a701b1bf6] CVE: CVE-2026-1760 Signed-off-by: Changqing Li --- libsoup/soup-message-headers.c | 86 +++++++++++++++----------------- libsoup/soup-message-server-io.c | 8 +++ 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c index 535cf14..06d9600 100644 --- a/libsoup/soup-message-headers.c +++ b/libsoup/soup-message-headers.c @@ -666,38 +666,13 @@ clear_special_headers (SoupMessageHeaders *hdrs) static void transfer_encoding_setter (SoupMessageHeaders *hdrs, const char *value) { - 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; + hdrs->encoding = -1; } static void content_length_setter (SoupMessageHeaders *hdrs, const char *value) { - /* Transfer-Encoding trumps 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; + hdrs->encoding = -1; } /** @@ -730,29 +705,50 @@ 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 (hdrs, "Content-Length"); - if (header) { - content_length_setter (hdrs, header); - if (hdrs->encoding != -1) - return hdrs->encoding; - } + /* Transfer-Encoding is checked first because it overrides the Content-Length */ + transfer_encoding = soup_message_headers_get_one (hdrs, "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 (hdrs, "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; } diff --git a/libsoup/soup-message-server-io.c b/libsoup/soup-message-server-io.c index 71e943b..df5eafc 100644 --- a/libsoup/soup-message-server-io.c +++ b/libsoup/soup-message-server-io.c @@ -80,6 +80,14 @@ parse_request_headers (SoupMessage *msg, char *headers, guint headers_len, 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 (msg->request_headers, "Content-Length")) + soup_message_headers_replace (msg->request_headers, "Connection", "close"); + /* Generate correct context for request */ req_host = soup_message_headers_get_one (msg->request_headers, "Host"); if (req_host && strchr (req_host, '/')) { -- 2.34.1