Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
340 changes: 340 additions & 0 deletions SPECS/libsoup/CVE-2026-2443.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,340 @@
From f74004bdd775c41b2a395799a6219f0fa81729fd Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Fri, 19 Dec 2025 23:49:05 +0000
Subject: [PATCH 1/7] soup-message-headers: Reject invalid Range ends longer
than the content

If the `Range` header in a request specifies a range longer than the
full content, it should be rejected. Previously, only the start of the
range was validated, rather than the start and the end. This led to an
assertion failure in `g_bytes_new_from_bytes()` (or a buffer overflow if
GLib was compiled with `G_DISABLE_CHECKS`, which is not recommended).

Add the missing check on the Range end, and add a unit test.

Spotted by Codean Labs.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Fixes: #487
---
libsoup/soup-message-headers.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index 9a5e101..3d7157a 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -1200,7 +1200,9 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
if (*end) {
status = SOUP_STATUS_OK;
break;
- } else if (check_satisfiable && cur.start >= total_length) {
+ } else if (check_satisfiable &&
+ (cur.start >= total_length ||
+ cur.end >= total_length)) {
if (status == SOUP_STATUS_OK)
status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
continue;
--
2.45.4


From bfefe646aedbe2d67dd1a90837b6f071fa0b66e2 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Fri, 19 Dec 2025 23:51:52 +0000
Subject: [PATCH 2/7] soup-message-headers: Reject ranges where end is before
start

Previously this returned HTTP status 200 OK, which is not what MDN says
should happen for an invalid range:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Range.

Add a unit test.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
---
libsoup/soup-message-headers.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index 3d7157a..4d8f0b8 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -1191,7 +1191,7 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
if (*end) {
cur.end = g_ascii_strtoull (end, &end, 10);
if (cur.end < cur.start) {
- status = SOUP_STATUS_OK;
+ status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
break;
}
} else
--
2.45.4


From b80120f89a4a2fa138ae2aa03807d363a9144098 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Sat, 20 Dec 2025 00:14:00 +0000
Subject: [PATCH 3/7] soup-message-headers: Fix parsing of invalid Range suffix
lengths

The way the parser for the `Range` header is implemented, this would
result in a range with an end 1 byte before its start.

Add a unit test.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
---
libsoup/soup-message-headers.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index 4d8f0b8..a4285a9 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -1184,6 +1184,10 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
if (*spec == '-') {
cur.start = g_ascii_strtoll (spec, &end, 10) + total_length;
cur.end = total_length - 1;
+ if (cur.end < cur.start) {
+ status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
+ break;
+ }
} else {
cur.start = g_ascii_strtoull (spec, &end, 10);
if (*end == '-')
--
2.45.4


From 0ffc98a5d3edcb0d92050a6e7fa3edb0f1fb0624 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Sat, 20 Dec 2025 00:18:25 +0000
Subject: [PATCH 4/7] soup-message-headers: Fix rejection of Range headers with
trailing garbage
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

If there’s unparseable content after a range, reject the header as
invalid rather than ignoring it and returning status 200 OK.

Add a unit test.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
---
libsoup/soup-message-headers.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index a4285a9..7a33c5e 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -1202,7 +1202,7 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
cur.end = total_length - 1;
}
if (*end) {
- status = SOUP_STATUS_OK;
+ status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
break;
} else if (check_satisfiable &&
(cur.start >= total_length ||
--
2.45.4


From c8b98212716b6c2ebe2bc943e062ac5ae2180440 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Thu, 25 Dec 2025 23:16:02 +0000
Subject: [PATCH 5/7] tests: Allow range tests to check more response statuses

Currently the tests can either assert that a response to a Range request
is HTTP 206 (Partial Content) or HTTP 416 (Range Not Satisfiable).
However, many of the states resulting from parsing a Range header
actually should have a HTTP 200 (OK) response, where the Range header is
ignored due to being completely invalid. This is what Apache does when,
for example, given a Range header where the end of the range is before
the start.

Add some extra arguments to the helper functions in `range-test.c` to
allow the expected response status and expected response start and end
(of the full response) to be given by the test, and change the existing
tests to use these extra arguments.

This introduces no behavioural changes for now, but will allow following
commits to test their status 200 responses.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
--
2.45.4


From de53063c742d4174ac03dfeb302bba4cdc3dc4b6 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Thu, 25 Dec 2025 23:20:03 +0000
Subject: [PATCH 6/7] soup-message-headers: Rework Range response statuses to
match Apache

And for the parsing logic to more closely match the wording of the
HTTP specification (https://httpwg.org/specs/rfc9110.html#field.range).

The previous behaviour (from my previous few commits) was potentially
correct according to the spec, but differed from what Apache implements,
so was inadvisable. Specifically, the code returned HTTP 416 for various
parsing errors on the Range header; whereas Apache ignores completely
invalid Range headers and returns HTTP 200 with the full response. For
partially invalid Range headers, it returns the valid ranges.

Implement that behaviour instead, and rework the structure of the Range
parsing code to (hopefully) make that intent clearer. For example,
separate the string parsing code from the numeric range checks, and
separate those from the decision about which HTTP status to return.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #487
---
libsoup/soup-message-headers.c | 68 ++++++++++++++++++++++------------
1 file changed, 44 insertions(+), 24 deletions(-)

diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index 7a33c5e..41d56b8 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -1143,10 +1143,16 @@ sort_ranges (gconstpointer a, gconstpointer b)
}

/* like soup_message_headers_get_ranges(), except it returns:
- * SOUP_STATUS_OK if there is no Range or it should be ignored.
- * SOUP_STATUS_PARTIAL_CONTENT if there is at least one satisfiable range.
- * SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE if @check_satisfiable
- * is %TRUE and the request is not satisfiable given @total_length.
+ * - SOUP_STATUS_OK if there is no Range or it should be ignored due to being
+ * entirely invalid.
+ * - SOUP_STATUS_PARTIAL_CONTENT if there is at least one satisfiable range.
+ * - SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE if @check_satisfiable
+ * is %TRUE, the Range is valid, but no part of the request is satisfiable
+ * given @total_length.
+ *
+ * @ranges and @length are only set if SOUP_STATUS_PARTIAL_CONTENT is returned.
+ *
+ * See https://httpwg.org/specs/rfc9110.html#field.range
*/
guint
soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
@@ -1160,22 +1166,28 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
GArray *array;
char *spec, *end;
guint status = SOUP_STATUS_OK;
+ gboolean is_all_valid = TRUE;

if (!range || strncmp (range, "bytes", 5) != 0)
- return status;
+ return SOUP_STATUS_OK; /* invalid header or unknown range unit */

range += 5;
while (g_ascii_isspace (*range))
range++;
if (*range++ != '=')
- return status;
+ return SOUP_STATUS_OK; /* invalid header */
while (g_ascii_isspace (*range))
range++;

range_list = soup_header_parse_list (range);
if (!range_list)
- return status;
+ return SOUP_STATUS_OK; /* invalid list */

+ /* Loop through the ranges and modify the status accordingly. Default to
+ * status 200 (OK, ignoring the ranges). Switch to status 206 (Partial
+ * Content) if there is at least one partially valid range. Switch to
+ * status 416 (Range Not Satisfiable) if there are no partially valid
+ * ranges at all. */
array = g_array_new (FALSE, FALSE, sizeof (SoupRange));
for (r = range_list; r; r = r->next) {
SoupRange cur;
@@ -1184,40 +1196,48 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
if (*spec == '-') {
cur.start = g_ascii_strtoll (spec, &end, 10) + total_length;
cur.end = total_length - 1;
- if (cur.end < cur.start) {
- status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
- break;
- }
} else {
cur.start = g_ascii_strtoull (spec, &end, 10);
if (*end == '-')
end++;
- if (*end) {
+ if (*end)
cur.end = g_ascii_strtoull (end, &end, 10);
- if (cur.end < cur.start) {
- status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
- break;
- }
- } else
+ else
cur.end = total_length - 1;
}
+
if (*end) {
- status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
- break;
- } else if (check_satisfiable &&
- (cur.start >= total_length ||
- cur.end >= total_length)) {
- if (status == SOUP_STATUS_OK)
- status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
+ /* Junk after the range */
+ is_all_valid = FALSE;
continue;
}

+ if (cur.end < cur.start) {
+ is_all_valid = FALSE;
+ continue;
+ }
+
+ g_assert (cur.start >= 0);
+ if (cur.end >= total_length)
+ cur.end = total_length - 1;
+
+ if (cur.start >= total_length) {
+ /* Range is valid, but unsatisfiable */
+ continue;
+ }
+
+ /* We have at least one (at least partially) satisfiable range */
g_array_append_val (array, cur);
status = SOUP_STATUS_PARTIAL_CONTENT;
}
soup_header_free_list (range_list);

if (status != SOUP_STATUS_PARTIAL_CONTENT) {
+ g_assert (status == SOUP_STATUS_OK);
+
+ if (is_all_valid && check_satisfiable)
+ status = SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;
+
g_array_free (array, TRUE);
return status;
}
--
2.45.4


From a3633a263631348abd9c2036170bdfe9facef04d Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Thu, 25 Dec 2025 23:50:30 +0000
Subject: [PATCH 7/7] tests: Add more tests for invalid Range headers

This gives full line and branch coverage of
`soup_message_headers_get_ranges_internal()`.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
--
2.45.4

6 changes: 5 additions & 1 deletion SPECS/libsoup/libsoup.spec
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Summary: libsoup HTTP client/server library
Name: libsoup
Version: 3.4.4
Release: 12%{?dist}
Release: 13%{?dist}
License: GPLv2
Vendor: Microsoft Corporation
Distribution: Azure Linux
Expand Down Expand Up @@ -74,6 +74,7 @@ Patch24: CVE-2026-1467.patch
Patch25: CVE-2026-1536.patch
Patch26: CVE-2026-1761.patch
Patch27: CVE-2026-1801.patch
Patch28: CVE-2026-2443.patch

%description
libsoup is HTTP client/server library for GNOME
Expand Down Expand Up @@ -141,6 +142,9 @@ find %{buildroot} -type f -name "*.la" -delete -print
%defattr(-,root,root)

%changelog
* Fri Feb 20 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.4.4-13
- Patch for CVE-2026-2443

* Mon Feb 09 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.4.4-12
- Patch for CVE-2026-1801, CVE-2026-1761, CVE-2026-1536, CVE-2025-32049, CVE-2026-1467

Expand Down
Loading