diff options
| author | Changqing Li <changqing.li@windriver.com> | 2026-04-29 14:15:30 +0800 |
|---|---|---|
| committer | Paul Barker <paul@pbarker.dev> | 2026-05-12 21:31:34 +0100 |
| commit | ad166a6de25062ef7297affc245c3dfb375256a2 (patch) | |
| tree | 26eb31b282a845eccc8d6d911d6f28dfc56d341f /meta | |
| parent | 16d874ad977f90b3d71fdd574eef746cde56f5fc (diff) | |
| download | poky-ad166a6de25062ef7297affc245c3dfb375256a2.tar.gz | |
libsoup: fix CVE-2025-14523
Refer:
https://gitlab.gnome.org/GNOME/libsoup/-/work_items/472
(From OE-Core rev: 277297409dbf0bdb17653419e2d5e4a5ee8f33d5)
Signed-off-by: Changqing Li <changqing.li@windriver.com>
Signed-off-by: Fabien Thomas <fabien.thomas@smile.fr>
Signed-off-by: Paul Barker <paul@pbarker.dev>
Diffstat (limited to 'meta')
| -rw-r--r-- | meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch | 715 | ||||
| -rw-r--r-- | meta/recipes-support/libsoup/libsoup_3.4.4.bb | 1 |
2 files changed, 716 insertions, 0 deletions
diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch new file mode 100644 index 0000000000..1cf5c9d667 --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch | |||
| @@ -0,0 +1,715 @@ | |||
| 1 | From 70123da95418f5d6e00e8ac2d586fb6c5d02cdc6 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Michael Catanzaro <mcatanzaro@redhat.com> | ||
| 3 | Date: Wed, 7 Jan 2026 14:50:33 -0600 | ||
| 4 | Subject: [PATCH] Reject duplicate Host headers | ||
| 5 | |||
| 6 | RFC 9112 section 3.2 says: | ||
| 7 | |||
| 8 | A server MUST respond with a 400 (Bad Request) status code to any | ||
| 9 | HTTP/1.1 request message that lacks a Host header field and to any | ||
| 10 | request message that contains more than one Host header field line or a | ||
| 11 | Host header field with an invalid field value. | ||
| 12 | |||
| 13 | In addition to rejecting a duplicate header when parsing headers, also | ||
| 14 | reject attempts to add the duplicate header using the | ||
| 15 | soup_message_headers_append() API, and add tests for both cases. | ||
| 16 | |||
| 17 | These checks will also apply to HTTP/2. I'm not sure whether this is | ||
| 18 | actually desired or not, but the header processing code is not aware of | ||
| 19 | which HTTP version is in use. | ||
| 20 | |||
| 21 | (Note that while SoupMessageHeaders does not require the Host header to | ||
| 22 | be present in an HTTP/1.1 request, SoupServer itself does. So we can't | ||
| 23 | test the case of missing Host header via the header parsing test, but it | ||
| 24 | really is enforced.) | ||
| 25 | |||
| 26 | Fixes #472 | ||
| 27 | |||
| 28 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/aecd8daadc110f8561fb2d6b2806a4cacf2e4c85] | ||
| 29 | CVE: CVE-2025-14523 | ||
| 30 | |||
| 31 | Signed-off-by: Changqing Li <changqing.li@windriver.com> | ||
| 32 | --- | ||
| 33 | libsoup/soup-headers.c | 3 +- | ||
| 34 | libsoup/soup-message-headers-private.h | 4 +- | ||
| 35 | libsoup/soup-message-headers.c | 80 +++++++------ | ||
| 36 | tests/header-parsing-test.c | 148 +++++++++++++++++-------- | ||
| 37 | 4 files changed, 153 insertions(+), 82 deletions(-) | ||
| 38 | |||
| 39 | diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c | ||
| 40 | index 155c11d..3fec9b3 100644 | ||
| 41 | --- a/libsoup/soup-headers.c | ||
| 42 | +++ b/libsoup/soup-headers.c | ||
| 43 | @@ -139,7 +139,8 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) | ||
| 44 | for (p = strchr (value, '\r'); p; p = strchr (p, '\r')) | ||
| 45 | *p = ' '; | ||
| 46 | |||
| 47 | - soup_message_headers_append_untrusted_data (dest, name, value); | ||
| 48 | + if (!soup_message_headers_append_untrusted_data (dest, name, value)) | ||
| 49 | + goto done; | ||
| 50 | } | ||
| 51 | success = TRUE; | ||
| 52 | |||
| 53 | diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h | ||
| 54 | index 9815464..770f3ef 100644 | ||
| 55 | --- a/libsoup/soup-message-headers-private.h | ||
| 56 | +++ b/libsoup/soup-message-headers-private.h | ||
| 57 | @@ -10,10 +10,10 @@ | ||
| 58 | |||
| 59 | G_BEGIN_DECLS | ||
| 60 | |||
| 61 | -void soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, | ||
| 62 | +gboolean soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, | ||
| 63 | const char *name, | ||
| 64 | const char *value); | ||
| 65 | -void soup_message_headers_append_common (SoupMessageHeaders *hdrs, | ||
| 66 | +gboolean soup_message_headers_append_common (SoupMessageHeaders *hdrs, | ||
| 67 | SoupHeaderName name, | ||
| 68 | const char *value); | ||
| 69 | const char *soup_message_headers_get_one_common (SoupMessageHeaders *hdrs, | ||
| 70 | diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c | ||
| 71 | index d69d6e8..ce4b3b3 100644 | ||
| 72 | --- a/libsoup/soup-message-headers.c | ||
| 73 | +++ b/libsoup/soup-message-headers.c | ||
| 74 | @@ -267,12 +267,16 @@ soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs) | ||
| 75 | soup_header_free_list (tokens); | ||
| 76 | } | ||
| 77 | |||
| 78 | -void | ||
| 79 | +gboolean | ||
| 80 | soup_message_headers_append_common (SoupMessageHeaders *hdrs, | ||
| 81 | SoupHeaderName name, | ||
| 82 | const char *value) | ||
| 83 | { | ||
| 84 | SoupCommonHeader header; | ||
| 85 | + if (name == SOUP_HEADER_HOST && soup_message_headers_get_one (hdrs, "Host")) { | ||
| 86 | + g_warning ("soup_message_headers_append_common: Rejecting duplicate Host header"); | ||
| 87 | + return FALSE; | ||
| 88 | + } | ||
| 89 | |||
| 90 | if (!hdrs->common_headers) | ||
| 91 | hdrs->common_headers = g_array_sized_new (FALSE, FALSE, sizeof (SoupCommonHeader), 6); | ||
| 92 | @@ -284,32 +288,18 @@ soup_message_headers_append_common (SoupMessageHeaders *hdrs, | ||
| 93 | g_hash_table_remove (hdrs->common_concat, GUINT_TO_POINTER (header.name)); | ||
| 94 | |||
| 95 | soup_message_headers_set (hdrs, name, value); | ||
| 96 | + return TRUE; | ||
| 97 | } | ||
| 98 | |||
| 99 | -/** | ||
| 100 | - * soup_message_headers_append: | ||
| 101 | - * @hdrs: a #SoupMessageHeaders | ||
| 102 | - * @name: the header name to add | ||
| 103 | - * @value: the new value of @name | ||
| 104 | - * | ||
| 105 | - * Appends a new header with name @name and value @value to @hdrs. | ||
| 106 | - * | ||
| 107 | - * (If there is an existing header with name @name, then this creates a second | ||
| 108 | - * one, which is only allowed for list-valued headers; see also | ||
| 109 | - * [method@MessageHeaders.replace].) | ||
| 110 | - * | ||
| 111 | - * The caller is expected to make sure that @name and @value are | ||
| 112 | - * syntactically correct. | ||
| 113 | - **/ | ||
| 114 | -void | ||
| 115 | -soup_message_headers_append (SoupMessageHeaders *hdrs, | ||
| 116 | - const char *name, const char *value) | ||
| 117 | +static gboolean | ||
| 118 | +soup_message_headers_append_internal (SoupMessageHeaders *hdrs, | ||
| 119 | + const char *name, const char *value) | ||
| 120 | { | ||
| 121 | SoupUncommonHeader header; | ||
| 122 | SoupHeaderName header_name; | ||
| 123 | |||
| 124 | - g_return_if_fail (name != NULL); | ||
| 125 | - g_return_if_fail (value != NULL); | ||
| 126 | + g_return_val_if_fail (name != NULL, FALSE); | ||
| 127 | + g_return_val_if_fail (value != NULL, FALSE); | ||
| 128 | |||
| 129 | /* Setting a syntactically invalid header name or value is | ||
| 130 | * considered to be a programming error. However, it can also | ||
| 131 | @@ -317,23 +307,22 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, | ||
| 132 | * compiled with G_DISABLE_CHECKS. | ||
| 133 | */ | ||
| 134 | #ifndef G_DISABLE_CHECKS | ||
| 135 | - g_return_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL); | ||
| 136 | - g_return_if_fail (strpbrk (value, "\r\n") == NULL); | ||
| 137 | + g_return_val_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL, FALSE); | ||
| 138 | + g_return_val_if_fail (strpbrk (value, "\r\n") == NULL, FALSE); | ||
| 139 | #else | ||
| 140 | if (*name && strpbrk (name, " \t\r\n:")) { | ||
| 141 | - g_warning ("soup_message_headers_append: Ignoring bad name '%s'", name); | ||
| 142 | - return; | ||
| 143 | + g_warning ("soup_message_headers_append: Rejecting bad name '%s'", name); | ||
| 144 | + return FALSE; | ||
| 145 | } | ||
| 146 | if (strpbrk (value, "\r\n")) { | ||
| 147 | - g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value); | ||
| 148 | - return; | ||
| 149 | + g_warning ("soup_message_headers_append: Rejecting bad value '%s'", value); | ||
| 150 | + return FALSE; | ||
| 151 | } | ||
| 152 | #endif | ||
| 153 | |||
| 154 | header_name = soup_header_name_from_string (name); | ||
| 155 | if (header_name != SOUP_HEADER_UNKNOWN) { | ||
| 156 | - soup_message_headers_append_common (hdrs, header_name, value); | ||
| 157 | - return; | ||
| 158 | + return soup_message_headers_append_common (hdrs, header_name, value); | ||
| 159 | } | ||
| 160 | |||
| 161 | if (!hdrs->uncommon_headers) | ||
| 162 | @@ -344,21 +333,48 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, | ||
| 163 | g_array_append_val (hdrs->uncommon_headers, header); | ||
| 164 | if (hdrs->uncommon_concat) | ||
| 165 | g_hash_table_remove (hdrs->uncommon_concat, header.name); | ||
| 166 | + return TRUE; | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +/** | ||
| 170 | + * soup_message_headers_append: | ||
| 171 | + * @hdrs: a #SoupMessageHeaders | ||
| 172 | + * @name: the header name to add | ||
| 173 | + * @value: the new value of @name | ||
| 174 | + * | ||
| 175 | + * Appends a new header with name @name and value @value to @hdrs. | ||
| 176 | + * | ||
| 177 | + * (If there is an existing header with name @name, then this creates a second | ||
| 178 | + * one, which is only allowed for list-valued headers; see also | ||
| 179 | + * [method@MessageHeaders.replace].) | ||
| 180 | + * | ||
| 181 | + * The caller is expected to make sure that @name and @value are | ||
| 182 | + * syntactically correct. | ||
| 183 | + **/ | ||
| 184 | +void | ||
| 185 | +soup_message_headers_append (SoupMessageHeaders *hdrs, | ||
| 186 | + const char *name, const char *value) | ||
| 187 | +{ | ||
| 188 | + soup_message_headers_append_internal (hdrs, name, value); | ||
| 189 | } | ||
| 190 | |||
| 191 | /* | ||
| 192 | - * Appends a header value ensuring that it is valid UTF8. | ||
| 193 | + * Appends a header value ensuring that it is valid UTF-8, and also checking the | ||
| 194 | + * return value of soup_message_headers_append_internal() to report whether the | ||
| 195 | + * headers are invalid for various other reasons. | ||
| 196 | */ | ||
| 197 | -void | ||
| 198 | +gboolean | ||
| 199 | soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, | ||
| 200 | const char *name, | ||
| 201 | const char *value) | ||
| 202 | { | ||
| 203 | char *safe_value = g_utf8_make_valid (value, -1); | ||
| 204 | char *safe_name = g_utf8_make_valid (name, -1); | ||
| 205 | - soup_message_headers_append (hdrs, safe_name, safe_value); | ||
| 206 | + gboolean result = soup_message_headers_append_internal (hdrs, safe_name, safe_value); | ||
| 207 | + | ||
| 208 | g_free (safe_value); | ||
| 209 | g_free (safe_name); | ||
| 210 | + return result; | ||
| 211 | } | ||
| 212 | |||
| 213 | void | ||
| 214 | diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c | ||
| 215 | index 9490559..98a22a4 100644 | ||
| 216 | --- a/tests/header-parsing-test.c | ||
| 217 | +++ b/tests/header-parsing-test.c | ||
| 218 | @@ -24,6 +24,7 @@ static struct RequestTest { | ||
| 219 | const char *method, *path; | ||
| 220 | SoupHTTPVersion version; | ||
| 221 | Header headers[10]; | ||
| 222 | + GLogLevelFlags log_flags; | ||
| 223 | } reqtests[] = { | ||
| 224 | /**********************/ | ||
| 225 | /*** VALID REQUESTS ***/ | ||
| 226 | @@ -33,7 +34,7 @@ static struct RequestTest { | ||
| 227 | "GET / HTTP/1.0\r\n", -1, | ||
| 228 | SOUP_STATUS_OK, | ||
| 229 | "GET", "/", SOUP_HTTP_1_0, | ||
| 230 | - { { NULL } } | ||
| 231 | + { { NULL } }, 0 | ||
| 232 | }, | ||
| 233 | |||
| 234 | { "Req w/ 1 header", NULL, | ||
| 235 | @@ -42,7 +43,7 @@ static struct RequestTest { | ||
| 236 | "GET", "/", SOUP_HTTP_1_1, | ||
| 237 | { { "Host", "example.com" }, | ||
| 238 | { NULL } | ||
| 239 | - } | ||
| 240 | + }, 0 | ||
| 241 | }, | ||
| 242 | |||
| 243 | { "Req w/ 1 header, no leading whitespace", NULL, | ||
| 244 | @@ -51,7 +52,7 @@ static struct RequestTest { | ||
| 245 | "GET", "/", SOUP_HTTP_1_1, | ||
| 246 | { { "Host", "example.com" }, | ||
| 247 | { NULL } | ||
| 248 | - } | ||
| 249 | + }, 0 | ||
| 250 | }, | ||
| 251 | |||
| 252 | { "Req w/ 1 header including trailing whitespace", NULL, | ||
| 253 | @@ -60,7 +61,7 @@ static struct RequestTest { | ||
| 254 | "GET", "/", SOUP_HTTP_1_1, | ||
| 255 | { { "Host", "example.com" }, | ||
| 256 | { NULL } | ||
| 257 | - } | ||
| 258 | + }, 0 | ||
| 259 | }, | ||
| 260 | |||
| 261 | { "Req w/ 1 header, wrapped", NULL, | ||
| 262 | @@ -69,7 +70,7 @@ static struct RequestTest { | ||
| 263 | "GET", "/", SOUP_HTTP_1_1, | ||
| 264 | { { "Foo", "bar baz" }, | ||
| 265 | { NULL } | ||
| 266 | - } | ||
| 267 | + }, 0 | ||
| 268 | }, | ||
| 269 | |||
| 270 | { "Req w/ 1 header, wrapped with additional whitespace", NULL, | ||
| 271 | @@ -78,7 +79,7 @@ static struct RequestTest { | ||
| 272 | "GET", "/", SOUP_HTTP_1_1, | ||
| 273 | { { "Foo", "bar baz" }, | ||
| 274 | { NULL } | ||
| 275 | - } | ||
| 276 | + }, 0 | ||
| 277 | }, | ||
| 278 | |||
| 279 | { "Req w/ 1 header, wrapped with tab", NULL, | ||
| 280 | @@ -87,7 +88,7 @@ static struct RequestTest { | ||
| 281 | "GET", "/", SOUP_HTTP_1_1, | ||
| 282 | { { "Foo", "bar baz" }, | ||
| 283 | { NULL } | ||
| 284 | - } | ||
| 285 | + }, 0 | ||
| 286 | }, | ||
| 287 | |||
| 288 | { "Req w/ 1 header, wrapped before value", NULL, | ||
| 289 | @@ -96,7 +97,7 @@ static struct RequestTest { | ||
| 290 | "GET", "/", SOUP_HTTP_1_1, | ||
| 291 | { { "Foo", "bar baz" }, | ||
| 292 | { NULL } | ||
| 293 | - } | ||
| 294 | + }, 0 | ||
| 295 | }, | ||
| 296 | |||
| 297 | { "Req w/ 1 header with empty value", NULL, | ||
| 298 | @@ -105,7 +106,7 @@ static struct RequestTest { | ||
| 299 | "GET", "/", SOUP_HTTP_1_1, | ||
| 300 | { { "Host", "" }, | ||
| 301 | { NULL } | ||
| 302 | - } | ||
| 303 | + }, 0 | ||
| 304 | }, | ||
| 305 | |||
| 306 | { "Req w/ 2 headers", NULL, | ||
| 307 | @@ -115,7 +116,7 @@ static struct RequestTest { | ||
| 308 | { { "Host", "example.com" }, | ||
| 309 | { "Connection", "close" }, | ||
| 310 | { NULL } | ||
| 311 | - } | ||
| 312 | + }, 0 | ||
| 313 | }, | ||
| 314 | |||
| 315 | { "Req w/ 3 headers", NULL, | ||
| 316 | @@ -126,7 +127,7 @@ static struct RequestTest { | ||
| 317 | { "Connection", "close" }, | ||
| 318 | { "Blah", "blah" }, | ||
| 319 | { NULL } | ||
| 320 | - } | ||
| 321 | + }, 0 | ||
| 322 | }, | ||
| 323 | |||
| 324 | { "Req w/ 3 headers, 1st wrapped", NULL, | ||
| 325 | @@ -137,7 +138,7 @@ static struct RequestTest { | ||
| 326 | { "Foo", "bar baz" }, | ||
| 327 | { "Blah", "blah" }, | ||
| 328 | { NULL } | ||
| 329 | - } | ||
| 330 | + }, 0 | ||
| 331 | }, | ||
| 332 | |||
| 333 | { "Req w/ 3 headers, 2nd wrapped", NULL, | ||
| 334 | @@ -148,7 +149,7 @@ static struct RequestTest { | ||
| 335 | { "Blah", "blah" }, | ||
| 336 | { "Foo", "bar baz" }, | ||
| 337 | { NULL } | ||
| 338 | - } | ||
| 339 | + }, 0 | ||
| 340 | }, | ||
| 341 | |||
| 342 | { "Req w/ 3 headers, 3rd wrapped", NULL, | ||
| 343 | @@ -159,7 +160,7 @@ static struct RequestTest { | ||
| 344 | { "Blah", "blah" }, | ||
| 345 | { "Foo", "bar baz" }, | ||
| 346 | { NULL } | ||
| 347 | - } | ||
| 348 | + }, 0 | ||
| 349 | }, | ||
| 350 | |||
| 351 | { "Req w/ same header multiple times", NULL, | ||
| 352 | @@ -168,7 +169,7 @@ static struct RequestTest { | ||
| 353 | "GET", "/", SOUP_HTTP_1_1, | ||
| 354 | { { "Foo", "bar, baz, quux" }, | ||
| 355 | { NULL } | ||
| 356 | - } | ||
| 357 | + }, 0 | ||
| 358 | }, | ||
| 359 | |||
| 360 | { "Connection header on HTTP/1.0 message", NULL, | ||
| 361 | @@ -178,21 +179,21 @@ static struct RequestTest { | ||
| 362 | { { "Connection", "Bar, Quux" }, | ||
| 363 | { "Foo", "bar" }, | ||
| 364 | { NULL } | ||
| 365 | - } | ||
| 366 | + }, 0 | ||
| 367 | }, | ||
| 368 | |||
| 369 | { "GET with full URI", "667637", | ||
| 370 | "GET http://example.com HTTP/1.1\r\n", -1, | ||
| 371 | SOUP_STATUS_OK, | ||
| 372 | "GET", "http://example.com", SOUP_HTTP_1_1, | ||
| 373 | - { { NULL } } | ||
| 374 | + { { NULL } }, 0 | ||
| 375 | }, | ||
| 376 | |||
| 377 | { "GET with full URI in upper-case", "667637", | ||
| 378 | "GET HTTP://example.com HTTP/1.1\r\n", -1, | ||
| 379 | SOUP_STATUS_OK, | ||
| 380 | "GET", "HTTP://example.com", SOUP_HTTP_1_1, | ||
| 381 | - { { NULL } } | ||
| 382 | + { { NULL } }, 0 | ||
| 383 | }, | ||
| 384 | |||
| 385 | /* It's better for this to be passed through: this means a SoupServer | ||
| 386 | @@ -202,7 +203,7 @@ static struct RequestTest { | ||
| 387 | "GET AbOuT: HTTP/1.1\r\n", -1, | ||
| 388 | SOUP_STATUS_OK, | ||
| 389 | "GET", "AbOuT:", SOUP_HTTP_1_1, | ||
| 390 | - { { NULL } } | ||
| 391 | + { { NULL } }, 0 | ||
| 392 | }, | ||
| 393 | |||
| 394 | /****************************/ | ||
| 395 | @@ -217,7 +218,7 @@ static struct RequestTest { | ||
| 396 | "GET", "/", SOUP_HTTP_1_1, | ||
| 397 | { { "Host", "example.com" }, | ||
| 398 | { NULL } | ||
| 399 | - } | ||
| 400 | + }, 0 | ||
| 401 | }, | ||
| 402 | |||
| 403 | /* RFC 2616 section 3.1 says we MUST accept this */ | ||
| 404 | @@ -228,7 +229,7 @@ static struct RequestTest { | ||
| 405 | "GET", "/", SOUP_HTTP_1_1, | ||
| 406 | { { "Host", "example.com" }, | ||
| 407 | { NULL } | ||
| 408 | - } | ||
| 409 | + }, 0 | ||
| 410 | }, | ||
| 411 | |||
| 412 | /* RFC 2616 section 19.3 says we SHOULD accept these */ | ||
| 413 | @@ -240,7 +241,7 @@ static struct RequestTest { | ||
| 414 | { { "Host", "example.com" }, | ||
| 415 | { "Connection", "close" }, | ||
| 416 | { NULL } | ||
| 417 | - } | ||
| 418 | + }, 0 | ||
| 419 | }, | ||
| 420 | |||
| 421 | { "LF instead of CRLF after Request-Line", NULL, | ||
| 422 | @@ -249,7 +250,7 @@ static struct RequestTest { | ||
| 423 | "GET", "/", SOUP_HTTP_1_1, | ||
| 424 | { { "Host", "example.com" }, | ||
| 425 | { NULL } | ||
| 426 | - } | ||
| 427 | + }, 0 | ||
| 428 | }, | ||
| 429 | |||
| 430 | { "Mixed CRLF/LF", "666316", | ||
| 431 | @@ -261,7 +262,7 @@ static struct RequestTest { | ||
| 432 | { "e", "f" }, | ||
| 433 | { "g", "h" }, | ||
| 434 | { NULL } | ||
| 435 | - } | ||
| 436 | + }, 0 | ||
| 437 | }, | ||
| 438 | |||
| 439 | { "Req w/ incorrect whitespace in Request-Line", NULL, | ||
| 440 | @@ -270,7 +271,7 @@ static struct RequestTest { | ||
| 441 | "GET", "/", SOUP_HTTP_1_1, | ||
| 442 | { { "Host", "example.com" }, | ||
| 443 | { NULL } | ||
| 444 | - } | ||
| 445 | + }, 0 | ||
| 446 | }, | ||
| 447 | |||
| 448 | { "Req w/ incorrect whitespace after Request-Line", "475169", | ||
| 449 | @@ -279,7 +280,7 @@ static struct RequestTest { | ||
| 450 | "GET", "/", SOUP_HTTP_1_1, | ||
| 451 | { { "Host", "example.com" }, | ||
| 452 | { NULL } | ||
| 453 | - } | ||
| 454 | + }, 0 | ||
| 455 | }, | ||
| 456 | |||
| 457 | /* If the request/status line is parseable, then we | ||
| 458 | @@ -293,7 +294,7 @@ static struct RequestTest { | ||
| 459 | { { "Host", "example.com" }, | ||
| 460 | { "Bar", "two" }, | ||
| 461 | { NULL } | ||
| 462 | - } | ||
| 463 | + }, 0 | ||
| 464 | }, | ||
| 465 | |||
| 466 | { "First header line is continuation", "666316", | ||
| 467 | @@ -303,7 +304,7 @@ static struct RequestTest { | ||
| 468 | { { "Host", "example.com" }, | ||
| 469 | { "c", "d" }, | ||
| 470 | { NULL } | ||
| 471 | - } | ||
| 472 | + }, 0 | ||
| 473 | }, | ||
| 474 | |||
| 475 | { "Zero-length header name", "666316", | ||
| 476 | @@ -313,7 +314,7 @@ static struct RequestTest { | ||
| 477 | { { "a", "b" }, | ||
| 478 | { "c", "d" }, | ||
| 479 | { NULL } | ||
| 480 | - } | ||
| 481 | + }, 0 | ||
| 482 | }, | ||
| 483 | |||
| 484 | { "CR in header name", "666316", | ||
| 485 | @@ -323,7 +324,7 @@ static struct RequestTest { | ||
| 486 | { { "a", "b" }, | ||
| 487 | { "c", "d" }, | ||
| 488 | { NULL } | ||
| 489 | - } | ||
| 490 | + }, 0 | ||
| 491 | }, | ||
| 492 | |||
| 493 | { "CR in header value", "666316", | ||
| 494 | @@ -336,7 +337,7 @@ static struct RequestTest { | ||
| 495 | { "s", "t" }, /* CR at end is ignored */ | ||
| 496 | { "c", "d" }, | ||
| 497 | { NULL } | ||
| 498 | - } | ||
| 499 | + }, 0 | ||
| 500 | }, | ||
| 501 | |||
| 502 | { "Tab in header name", "666316", | ||
| 503 | @@ -351,7 +352,7 @@ static struct RequestTest { | ||
| 504 | { "p", "q z: w" }, | ||
| 505 | { "c", "d" }, | ||
| 506 | { NULL } | ||
| 507 | - } | ||
| 508 | + }, 0 | ||
| 509 | }, | ||
| 510 | |||
| 511 | { "Tab in header value", "666316", | ||
| 512 | @@ -364,7 +365,7 @@ static struct RequestTest { | ||
| 513 | { "z", "w" }, /* trailing tab ignored */ | ||
| 514 | { "c", "d" }, | ||
| 515 | { NULL } | ||
| 516 | - } | ||
| 517 | + }, 0 | ||
| 518 | }, | ||
| 519 | |||
| 520 | /************************/ | ||
| 521 | @@ -375,77 +376,77 @@ static struct RequestTest { | ||
| 522 | "GET /\r\n", -1, | ||
| 523 | SOUP_STATUS_BAD_REQUEST, | ||
| 524 | NULL, NULL, -1, | ||
| 525 | - { { NULL } } | ||
| 526 | + { { NULL } }, 0 | ||
| 527 | }, | ||
| 528 | |||
| 529 | { "HTTP 1.2 request (no such thing)", NULL, | ||
| 530 | "GET / HTTP/1.2\r\n", -1, | ||
| 531 | SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED, | ||
| 532 | NULL, NULL, -1, | ||
| 533 | - { { NULL } } | ||
| 534 | + { { NULL } }, 0 | ||
| 535 | }, | ||
| 536 | |||
| 537 | { "HTTP 2000 request (no such thing)", NULL, | ||
| 538 | "GET / HTTP/2000.0\r\n", -1, | ||
| 539 | SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED, | ||
| 540 | NULL, NULL, -1, | ||
| 541 | - { { NULL } } | ||
| 542 | + { { NULL } }, 0 | ||
| 543 | }, | ||
| 544 | |||
| 545 | { "Long HTTP version terminating at missing minor version", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/404", | ||
| 546 | unterminated_http_version, sizeof (unterminated_http_version), | ||
| 547 | SOUP_STATUS_BAD_REQUEST, | ||
| 548 | NULL, NULL, -1, | ||
| 549 | - { { NULL } } | ||
| 550 | + { { NULL } }, 0 | ||
| 551 | }, | ||
| 552 | |||
| 553 | { "Non-HTTP request", NULL, | ||
| 554 | "GET / SOUP/1.1\r\nHost: example.com\r\n", -1, | ||
| 555 | SOUP_STATUS_BAD_REQUEST, | ||
| 556 | NULL, NULL, -1, | ||
| 557 | - { { NULL } } | ||
| 558 | + { { NULL } }, 0 | ||
| 559 | }, | ||
| 560 | |||
| 561 | { "Junk after Request-Line", NULL, | ||
| 562 | "GET / HTTP/1.1 blah\r\nHost: example.com\r\n", -1, | ||
| 563 | SOUP_STATUS_BAD_REQUEST, | ||
| 564 | NULL, NULL, -1, | ||
| 565 | - { { NULL } } | ||
| 566 | + { { NULL } }, 0 | ||
| 567 | }, | ||
| 568 | |||
| 569 | { "NUL in Method", NULL, | ||
| 570 | "G\x00T / HTTP/1.1\r\nHost: example.com\r\n", 37, | ||
| 571 | SOUP_STATUS_BAD_REQUEST, | ||
| 572 | NULL, NULL, -1, | ||
| 573 | - { { NULL } } | ||
| 574 | + { { NULL } }, 0 | ||
| 575 | }, | ||
| 576 | |||
| 577 | { "NUL at beginning of Method", "666316", | ||
| 578 | "\x00 / HTTP/1.1\r\nHost: example.com\r\n", 35, | ||
| 579 | SOUP_STATUS_BAD_REQUEST, | ||
| 580 | NULL, NULL, -1, | ||
| 581 | - { { NULL } } | ||
| 582 | + { { NULL } }, 0 | ||
| 583 | }, | ||
| 584 | |||
| 585 | { "NUL in Path", NULL, | ||
| 586 | "GET /\x00 HTTP/1.1\r\nHost: example.com\r\n", 38, | ||
| 587 | SOUP_STATUS_BAD_REQUEST, | ||
| 588 | NULL, NULL, -1, | ||
| 589 | - { { NULL } } | ||
| 590 | + { { NULL } }, 0 | ||
| 591 | }, | ||
| 592 | |||
| 593 | { "No terminating CRLF", NULL, | ||
| 594 | "GET / HTTP/1.1\r\nHost: example.com", -1, | ||
| 595 | SOUP_STATUS_BAD_REQUEST, | ||
| 596 | NULL, NULL, -1, | ||
| 597 | - { { NULL } } | ||
| 598 | + { { NULL } }, 0 | ||
| 599 | }, | ||
| 600 | |||
| 601 | { "Unrecognized expectation", NULL, | ||
| 602 | "GET / HTTP/1.1\r\nHost: example.com\r\nExpect: the-impossible\r\n", -1, | ||
| 603 | SOUP_STATUS_EXPECTATION_FAILED, | ||
| 604 | NULL, NULL, -1, | ||
| 605 | - { { NULL } } | ||
| 606 | + { { NULL } }, 0 | ||
| 607 | }, | ||
| 608 | |||
| 609 | // https://gitlab.gnome.org/GNOME/libsoup/-/issues/377 | ||
| 610 | @@ -453,21 +454,40 @@ static struct RequestTest { | ||
| 611 | "GET / HTTP/1.1\r\nHost\x00: example.com\r\n", 36, | ||
| 612 | SOUP_STATUS_BAD_REQUEST, | ||
| 613 | NULL, NULL, -1, | ||
| 614 | - { { NULL } } | ||
| 615 | + { { NULL } }, 0 | ||
| 616 | }, | ||
| 617 | |||
| 618 | { "NUL in header value", NULL, | ||
| 619 | "HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28, | ||
| 620 | SOUP_STATUS_BAD_REQUEST, | ||
| 621 | NULL, NULL, -1, | ||
| 622 | - { { NULL } } | ||
| 623 | + { { NULL } }, 0 | ||
| 624 | }, | ||
| 625 | |||
| 626 | { "Only newlines", NULL, | ||
| 627 | only_newlines, sizeof (only_newlines), | ||
| 628 | SOUP_STATUS_BAD_REQUEST, | ||
| 629 | NULL, NULL, -1, | ||
| 630 | - { { NULL } } | ||
| 631 | + { { NULL } }, 0 | ||
| 632 | + }, | ||
| 633 | + { "Duplicate Host headers", | ||
| 634 | + "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472", | ||
| 635 | + "GET / HTTP/1.1\r\nHost: example.com\r\nHost: example.org\r\n", | ||
| 636 | + -1, | ||
| 637 | + SOUP_STATUS_BAD_REQUEST, | ||
| 638 | + NULL, NULL, -1, | ||
| 639 | + { { NULL } }, | ||
| 640 | + G_LOG_LEVEL_WARNING | ||
| 641 | + }, | ||
| 642 | + | ||
| 643 | + { "Duplicate Host headers, case insensitive", | ||
| 644 | + "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472", | ||
| 645 | + "GET / HTTP/1.1\r\nHost: example.com\r\nhost: example.org\r\n", | ||
| 646 | + -1, | ||
| 647 | + SOUP_STATUS_BAD_REQUEST, | ||
| 648 | + NULL, NULL, -1, | ||
| 649 | + { { NULL } }, | ||
| 650 | + G_LOG_LEVEL_WARNING | ||
| 651 | } | ||
| 652 | }; | ||
| 653 | static const int num_reqtests = G_N_ELEMENTS (reqtests); | ||
| 654 | @@ -915,10 +935,17 @@ do_request_tests (void) | ||
| 655 | len = strlen (reqtests[i].request); | ||
| 656 | else | ||
| 657 | len = reqtests[i].length; | ||
| 658 | + | ||
| 659 | + if (reqtests[i].log_flags) | ||
| 660 | + g_test_expect_message ("libsoup", reqtests[i].log_flags, "*"); | ||
| 661 | + | ||
| 662 | status = soup_headers_parse_request (reqtests[i].request, len, | ||
| 663 | headers, &method, &path, | ||
| 664 | &version); | ||
| 665 | g_assert_cmpint (status, ==, reqtests[i].status); | ||
| 666 | + if (reqtests[i].log_flags) | ||
| 667 | + g_test_assert_expected_messages (); | ||
| 668 | + | ||
| 669 | if (SOUP_STATUS_IS_SUCCESSFUL (status)) { | ||
| 670 | g_assert_cmpstr (method, ==, reqtests[i].method); | ||
| 671 | g_assert_cmpstr (path, ==, reqtests[i].path); | ||
| 672 | @@ -1312,6 +1339,32 @@ do_bad_header_tests (void) | ||
| 673 | soup_message_headers_unref (hdrs); | ||
| 674 | } | ||
| 675 | |||
| 676 | +static void | ||
| 677 | +do_append_duplicate_host_test (void) | ||
| 678 | +{ | ||
| 679 | + SoupMessageHeaders *hdrs; | ||
| 680 | + const char *list_value; | ||
| 681 | + | ||
| 682 | + hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST); | ||
| 683 | + soup_message_headers_append (hdrs, "Host", "a"); | ||
| 684 | + | ||
| 685 | + g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING, | ||
| 686 | + "soup_message_headers_append_common: Rejecting duplicate Host header"); | ||
| 687 | + soup_message_headers_append (hdrs, "Host", "b"); | ||
| 688 | + g_test_assert_expected_messages (); | ||
| 689 | + | ||
| 690 | + /* Case insensitive */ | ||
| 691 | + g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING, | ||
| 692 | + "soup_message_headers_append_common: Rejecting duplicate Host header"); | ||
| 693 | + soup_message_headers_append (hdrs, "host", "b"); | ||
| 694 | + g_test_assert_expected_messages (); | ||
| 695 | + | ||
| 696 | + list_value = soup_message_headers_get_list (hdrs, "Host"); | ||
| 697 | + g_assert_cmpstr (list_value, ==, "a"); | ||
| 698 | + | ||
| 699 | + soup_message_headers_unref (hdrs); | ||
| 700 | +} | ||
| 701 | + | ||
| 702 | int | ||
| 703 | main (int argc, char **argv) | ||
| 704 | { | ||
| 705 | @@ -1327,6 +1380,7 @@ main (int argc, char **argv) | ||
| 706 | g_test_add_func ("/header-parsing/content-type", do_content_type_tests); | ||
| 707 | g_test_add_func ("/header-parsing/append-param", do_append_param_tests); | ||
| 708 | g_test_add_func ("/header-parsing/bad", do_bad_header_tests); | ||
| 709 | + g_test_add_func ("/header-parsing/append-duplicate-host", do_append_duplicate_host_test); | ||
| 710 | |||
| 711 | ret = g_test_run (); | ||
| 712 | |||
| 713 | -- | ||
| 714 | 2.34.1 | ||
| 715 | |||
diff --git a/meta/recipes-support/libsoup/libsoup_3.4.4.bb b/meta/recipes-support/libsoup/libsoup_3.4.4.bb index c09b06fec2..6be31806f1 100644 --- a/meta/recipes-support/libsoup/libsoup_3.4.4.bb +++ b/meta/recipes-support/libsoup/libsoup_3.4.4.bb | |||
| @@ -46,6 +46,7 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ | |||
| 46 | file://CVE-2025-2784.patch \ | 46 | file://CVE-2025-2784.patch \ |
| 47 | file://CVE-2025-4945.patch \ | 47 | file://CVE-2025-4945.patch \ |
| 48 | file://CVE-2025-12105.patch \ | 48 | file://CVE-2025-12105.patch \ |
| 49 | file://CVE-2025-14523.patch \ | ||
| 49 | " | 50 | " |
| 50 | SRC_URI[sha256sum] = "291c67725f36ed90ea43efff25064b69c5a2d1981488477c05c481a3b4b0c5aa" | 51 | SRC_URI[sha256sum] = "291c67725f36ed90ea43efff25064b69c5a2d1981488477c05c481a3b4b0c5aa" |
| 51 | 52 | ||
