From 884fea101a40dd9abd369b1bb8b709c8ccf57d58 Mon Sep 17 00:00:00 2001 From: Jacob Wang Date: Wed, 5 Nov 2025 11:03:40 +0800 Subject: [PATCH 1/2] [CVE]update to libsoup-2.62.3-10 to #ID53GE update to libsoup-2.62.3-10 for CVE-2025-4945 CVE-2025-11021 Project: TC2024080204 Signed-off-by: Jacob Wang --- CVE-2025-4945-CVE-2025-11021.patch | 931 +++++++++++++++++++++++++++++ libsoup.spec | 24 +- 2 files changed, 937 insertions(+), 18 deletions(-) create mode 100644 CVE-2025-4945-CVE-2025-11021.patch diff --git a/CVE-2025-4945-CVE-2025-11021.patch b/CVE-2025-4945-CVE-2025-11021.patch new file mode 100644 index 0000000..71f4afc --- /dev/null +++ b/CVE-2025-4945-CVE-2025-11021.patch @@ -0,0 +1,931 @@ +From 52825c2eb7043698d7a0668cfe6bb5a23da87cf5 Mon Sep 17 00:00:00 2001 +From: Milan Crha +Date: Thu, 15 May 2025 07:59:14 +0200 +Subject: [PATCH 1/2] soup-date-utils: Add value checks for date/time parsing + +Reject date/time when it does not represent a valid value. + +Closes https://gitlab.gnome.org/GNOME/libsoup/-/issues/448 +--- + libsoup/soup-date.c | 23 ++- + tests/cookies-test.c | 10 + + tests/date-test.c | 434 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 459 insertions(+), 8 deletions(-) + create mode 100644 tests/date-test.c + +diff --git a/libsoup/soup-date.c b/libsoup/soup-date.c +index dabae9d4..8b2beea4 100644 +--- a/libsoup/soup-date.c ++++ b/libsoup/soup-date.c +@@ -284,7 +284,7 @@ parse_day (SoupDate *date, const char **date_string) + while (*end == ' ' || *end == '-') + end++; + *date_string = end; +- return TRUE; ++ return date->day >= 1 && date->day <= 31; + } + + static inline gboolean +@@ -324,7 +324,7 @@ parse_year (SoupDate *date, const char **date_string) + while (*end == ' ' || *end == '-') + end++; + *date_string = end; +- return TRUE; ++ return date->year > 0 && date->year < 9999; + } + + static inline gboolean +@@ -348,7 +348,7 @@ parse_time (SoupDate *date, const char **date_string) + while (*p == ' ') + p++; + *date_string = p; +- return TRUE; ++ return date->hour >= 0 && date->hour < 24 && date->minute >= 0 && date->minute < 60 && date->second >= 0 && date->second < 60; + } + + static inline gboolean +@@ -361,9 +361,14 @@ parse_timezone (SoupDate *date, const char **date_string) + gulong val; + int sign = (**date_string == '+') ? -1 : 1; + val = strtoul (*date_string + 1, (char **)date_string, 10); +- if (**date_string == ':') +- val = 60 * val + strtoul (*date_string + 1, (char **)date_string, 10); +- else ++ if (val > 9999) ++ return FALSE; ++ if (**date_string == ':') { ++ gulong val2 = strtoul (*date_string + 1, (char **)date_string, 10); ++ if (val > 99 || val2 > 99) ++ return FALSE; ++ val = 60 * val + val2; ++ } else + val = 60 * (val / 100) + (val % 100); + date->offset = sign * val; + date->utc = (sign == -1) && !val; +@@ -407,7 +412,8 @@ parse_textual_date (SoupDate *date, const char *date_string) + if (!parse_month (date, &date_string) || + !parse_day (date, &date_string) || + !parse_time (date, &date_string) || +- !parse_year (date, &date_string)) ++ !parse_year (date, &date_string) || ++ !g_date_valid_dmy (date->day, date->month, date->year)) + return FALSE; + + /* There shouldn't be a timezone, but check anyway */ +@@ -419,7 +425,8 @@ parse_textual_date (SoupDate *date, const char *date_string) + if (!parse_day (date, &date_string) || + !parse_month (date, &date_string) || + !parse_year (date, &date_string) || +- !parse_time (date, &date_string)) ++ !parse_time (date, &date_string) || ++ !g_date_valid_dmy (date->day, date->month, date->year)) + return FALSE; + + /* This time there *should* be a timezone, but we +diff --git a/tests/cookies-test.c b/tests/cookies-test.c +index 17b77f29..61adfac5 100644 +--- a/tests/cookies-test.c ++++ b/tests/cookies-test.c +@@ -288,6 +288,15 @@ do_cookies_parsing_nopath_nullorigin (void) + soup_cookie_free (cookie); + } + ++static void ++do_cookies_parsing_int32_overflow (void) ++{ ++ SoupCookie *cookie = soup_cookie_parse ("Age=1;expires=3Mar9 999:9:9+ 999999999-age=main=gne=", NULL); ++ g_assert_nonnull (cookie); ++ g_assert_null (soup_cookie_get_expires (cookie)); ++ soup_cookie_free (cookie); ++} ++ + int + main (int argc, char **argv) + { +@@ -309,6 +318,7 @@ main (int argc, char **argv) + g_test_add_func ("/cookies/accept-policy-subdomains", do_cookies_subdomain_policy_test); + g_test_add_func ("/cookies/parsing", do_cookies_parsing_test); + g_test_add_func ("/cookies/parsing/no-path-null-origin", do_cookies_parsing_nopath_nullorigin); ++ g_test_add_func ("/cookies/parsing/int32-overflow", do_cookies_parsing_int32_overflow); + + ret = g_test_run (); + +diff --git a/tests/date-test.c b/tests/date-test.c +new file mode 100644 +index 00000000..38f27335 +--- /dev/null ++++ b/tests/date-test.c +@@ -0,0 +1,434 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++/* ++ * Copyright (C) 2005 Novell, Inc. ++ */ ++ ++#include "test-utils.h" ++ ++static void check_ok (gconstpointer data); ++ ++static SoupDate * ++make_date (const char *strdate) ++{ ++ char *dup; ++ SoupDate *date; ++ ++ /* We do it this way so that if soup_date_new_from_string() ++ * reads off the end of the string, it will trigger an error ++ * when valgrinding, rather than just reading the start of the ++ * next const string. ++ */ ++ dup = g_strdup (strdate); ++ date = soup_date_new_from_string (dup); ++ g_free (dup); ++ return date; ++} ++ ++static SoupDate * ++check_correct_date (const char *strdate) ++{ ++ SoupDate *date; ++ ++ date = make_date (strdate); ++ if (!date) { ++ g_assert_nonnull (date); ++ return NULL; ++ } ++ ++ g_assert_cmpint (date->year, ==, 2004); ++ g_assert_cmpint (date->month, ==, 11); ++ g_assert_cmpint (date->day, ==, 6); ++ g_assert_cmpint (date->hour, ==, 8); ++ g_assert_cmpint (date->minute, ==, 9); ++ g_assert_cmpint (date->second, ==, 7); ++ ++ return date; ++} ++ ++typedef struct { ++ SoupDateFormat format; ++ const char *date; ++ const char *bugref; ++} GoodDate; ++ ++static const GoodDate good_dates[] = { ++ { SOUP_DATE_HTTP, "Sat, 06 Nov 2004 08:09:07 GMT", NULL }, ++ { SOUP_DATE_COOKIE, "Sat, 06-Nov-2004 08:09:07 GMT", NULL }, ++ { SOUP_DATE_RFC2822, "Sat, 6 Nov 2004 08:09:07 -0430", "579055" }, ++ { SOUP_DATE_ISO8601_COMPACT, "20041106T080907", NULL }, ++ { SOUP_DATE_ISO8601_FULL, "2004-11-06T08:09:07", NULL }, ++ { SOUP_DATE_ISO8601_XMLRPC, "20041106T08:09:07", NULL } ++}; ++ ++static void ++check_good (gconstpointer data) ++{ ++ GoodDate *good = (GoodDate *)data; ++ SoupDate *date; ++ char *strdate2; ++ ++ if (good->bugref) ++ g_test_bug (good->bugref); ++ ++ date = check_correct_date (good->date); ++ if (!date) ++ return; ++ ++ strdate2 = soup_date_to_string (date, good->format); ++ soup_date_free (date); ++ ++ soup_test_assert (strcmp (good->date, strdate2) == 0, ++ "restringification failed: '%s' -> '%s'\n", ++ good->date, strdate2); ++ g_free (strdate2); ++} ++ ++typedef struct { ++ const char *date; ++ const char *bugref; ++} OkDate; ++ ++static const OkDate ok_dates[] = { ++ /* rfc1123-date, and broken variants */ ++ { "Sat, 06 Nov 2004 08:09:07 GMT", NULL }, ++ { "Sat, 6 Nov 2004 08:09:07 GMT", NULL }, ++ { "Sat, 6 Nov 2004 08:09:07 GMT", NULL }, ++ { "Sat, 06 Nov 2004 08:09:07", NULL }, ++ { "06 Nov 2004 08:09:07 GMT", NULL }, ++ { "SAT, 06 NOV 2004 08:09:07 +1000", "644048" }, ++ { "Sat, 06-Nov-2004 08:09:07 -10000", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" }, ++ { "Sat, 06-Nov-2004 08:09:07 +01:30", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" }, ++ { "Sat, 06-Nov-2004 08:09:07 +0:180", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" }, ++ { "Sat, 06-Nov-2004 08:09:07 +100:100", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" }, ++ { "Sat, 06-Nov-2004 08:09:07 Z", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" }, ++ ++ /* rfc850-date, and broken variants */ ++ { "Saturday, 06-Nov-04 08:09:07 GMT", NULL }, ++ { "Saturday, 6-Nov-04 08:09:07 GMT", NULL }, ++ { "Saturday, 6-Nov-04 08:09:07 GMT", NULL }, ++ { "Saturday, 06-Nov-104 08:09:07 GMT", NULL }, ++ { "Saturday, 06-Nov-2004 08:09:07 GMT", NULL }, ++ { "Saturday, 6-Nov-2004 08:09:07 GMT", NULL }, ++ { "Saturday, 6-Nov-2004 08:09:07 GMT", NULL }, ++ { "Saturday, 06-Nov-04 08:09:07", NULL }, ++ { "06-Nov-04 08:09:07 GMT", NULL }, ++ ++ /* asctime-date, and broken variants */ ++ { "Sat Nov 6 08:09:07 2004", NULL }, ++ { "Sat Nov 06 08:09:07 2004", NULL }, ++ { "Sat Nov 6 08:09:07 2004", NULL }, ++ { "Sat Nov 6 08:09:07 2004 GMT", NULL }, ++ { "Sat Nov 6 08:09:07 2004 NoZone", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" }, ++ { "Sat Nov 6 08:09:07 2004 UTC", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" }, ++ ++ /* ISO 8601 */ ++ { "2004-11-06T08:09:07Z", NULL }, ++ { "20041106T08:09:07Z", NULL }, ++ { "20041106T08:09:07+00:00", NULL }, ++ { "20041106T080907+00:00", NULL }, ++ ++ /* Netscape cookie spec date, and broken variants */ ++ { "Sat, 06-Nov-2004 08:09:07 GMT", NULL }, ++ { "Sat, 6-Nov-2004 08:09:07 GMT", NULL }, ++ { "Sat, 6-Nov-2004 08:09:07 GMT", NULL }, ++ { "Sat, 06-Nov-2004 08:09:07", NULL }, ++ ++ /* Original version of Netscape cookie spec, and broken variants */ ++ { "Sat, 06-Nov-04 08:09:07 GMT", NULL }, ++ { "Sat, 6-Nov-04 08:09:07 GMT", NULL }, ++ { "Sat, 6-Nov-04 08:09:07 GMT", NULL }, ++ { "Sat, 06-Nov-104 08:09:07 GMT", NULL }, ++ { "Sat, 06-Nov-04 08:09:07", NULL }, ++ ++ /* Miscellaneous broken formats seen on the web */ ++ { "Sat 06-Nov-2004 08:9:07", NULL }, ++ { "Saturday, 06-Nov-04 8:9:07 GMT", NULL }, ++ { "Sat, 06 Nov 2004 08:09:7 GMT", NULL } ++}; ++ ++static void ++check_ok (gconstpointer data) ++{ ++ OkDate *ok = (OkDate *)data; ++ SoupDate *date; ++ ++ if (ok->bugref) ++ g_test_bug (ok->bugref); ++ ++ date = check_correct_date (ok->date); ++ if (!date) ++ return; ++ soup_date_free (date); ++} ++ ++#define TIME_T 1099728547L ++#define TIME_T_STRING "1099728547" ++ ++static void ++check_ok_time_t (void) ++{ ++ SoupDate *date; ++ ++ date = soup_date_new_from_time_t (TIME_T); ++ ++ g_assert_cmpint (date->year, ==, 2004); ++ g_assert_cmpint (date->month, ==, 11); ++ g_assert_cmpint (date->day, ==, 6); ++ g_assert_cmpint (date->hour, ==, 8); ++ g_assert_cmpint (date->minute, ==, 9); ++ g_assert_cmpint (date->second, ==, 7); ++ ++ g_assert_cmpuint (TIME_T, ==, soup_date_to_time_t (date)); ++ ++ soup_date_free (date); ++} ++ ++typedef struct { ++ const char *date; ++ const char *bugref; ++} BadDate; ++ ++static const BadDate bad_dates[] = { ++ /* broken rfc1123-date */ ++ { ", 06 Nov 2004 08:09:07 GMT", NULL }, ++ { "Sat, Nov 2004 08:09:07 GMT", NULL }, ++ { "Sat, 06 2004 08:09:07 GMT", NULL }, ++ { "Sat, 06 Nov 08:09:07 GMT", NULL }, ++ { "Sat, 06 Nov 2004 :09:07 GMT", NULL }, ++ { "Sat, 06 Nov 2004 09:07 GMT", NULL }, ++ { "Sat, 06 Nov 2004 08::07 GMT", NULL }, ++ { "Sat, 06 Nov 2004 08:09: GMT", NULL }, ++ ++ /* broken rfc850-date */ ++ { ", 06-Nov-04 08:09:07 GMT", NULL }, ++ { "Saturday, -Nov-04 08:09:07 GMT", NULL }, ++ { "Saturday, Nov-04 08:09:07 GMT", NULL }, ++ { "Saturday, 06-04 08:09:07 GMT", NULL }, ++ { "Saturday, 06--04 08:09:07 GMT", NULL }, ++ { "Saturday, 06-Nov- 08:09:07 GMT", NULL }, ++ { "Saturday, 06-Nov 08:09:07 GMT", NULL }, ++ { "Saturday, 06-Nov-04 :09:07 GMT", NULL }, ++ { "Saturday, 06-Nov-04 09:07 GMT", NULL }, ++ { "Saturday, 06-Nov-04 08::07 GMT", NULL }, ++ { "Saturday, 06-Nov-04 08:09: GMT", NULL }, ++ ++ /* broken asctime-date */ ++ { "Nov 6 08:09:07 2004", NULL }, ++ { "Sat 6 08:09:07 2004", NULL }, ++ { "Sat Nov 08:09:07 2004", NULL }, ++ { "Sat Nov 6 :09:07 2004", NULL }, ++ { "Sat Nov 6 09:07 2004", NULL }, ++ { "Sat Nov 6 08::07 2004", NULL }, ++ { "Sat Nov 6 08:09: 2004", NULL }, ++ { "Sat Nov 6 08:09:07", NULL }, ++ { "Sat Nov 6 08:09:07 GMT 2004", NULL }, ++ ++ /* range constraints added "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" */ ++ { "Sat, 00-Nov-2004 08:09:07 GMT", NULL }, ++ { "Sat, 32-Nov-2004 08:09:07 GMT", NULL }, ++ { "Sat, 06-Nov-0 08:09:07 GMT", NULL }, ++ { "Sat, 06-Nov-9999 08:09:07 GMT", NULL }, ++ { "Sat, 06-Nov-2004 0-1:09:07 GMT", NULL }, ++ { "(Sat), Nov 6 -1:09:07 2004", NULL }, ++ { "Sat, 06-Nov-2004 24:09:07 GMT", NULL }, ++ { "Sat, 06-Nov-2004 08:-1:07 GMT", NULL }, ++ { "Sat, 06-Nov-2004 08:60:07 GMT", NULL }, ++ { "Sat, 06-Nov-2004 08:09:-10 GMT", NULL }, ++ { "Sat, 06-Nov-2004 08:09:60 GMT", NULL }, ++ { "Sat, 06-Nov-71 08:09:99 UTC", NULL }, ++ { "Sat, 31-Feb-2004 08:09:07 UTC", NULL }, ++}; ++ ++static void ++check_bad (gconstpointer data) ++{ ++ BadDate *bad = (BadDate *)data; ++ SoupDate *date; ++ ++ if (bad->bugref) ++ g_test_bug (bad->bugref); ++ ++ date = make_date (bad->date); ++ soup_test_assert (date == NULL, ++ "date parsing succeeded for '%s': %d %d %d - %d %d %d", ++ bad->date, ++ date->year, date->month, date->day, ++ date->hour, date->minute, date->second); ++ g_clear_pointer (&date, soup_date_free); ++} ++ ++typedef struct { ++ const char *source; ++ const char *http, *cookie, *rfc2822, *compact, *full, *xmlrpc; ++} DateConversion; ++ ++static const DateConversion conversions[] = { ++ /* SOUP_DATE_HTTP */ ++ { "Sat, 06 Nov 2004 08:09:07 GMT", ++ ++ "Sat, 06 Nov 2004 08:09:07 GMT", ++ "Sat, 06-Nov-2004 08:09:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 +0000", ++ "20041106T080907Z", ++ "2004-11-06T08:09:07Z", ++ "20041106T08:09:07" }, ++ ++ /* RFC2822 GMT */ ++ { "Sat, 6 Nov 2004 08:09:07 +0000", ++ ++ "Sat, 06 Nov 2004 08:09:07 GMT", ++ "Sat, 06-Nov-2004 08:09:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 +0000", ++ "20041106T080907Z", ++ "2004-11-06T08:09:07Z", ++ "20041106T08:09:07" }, ++ ++ /* RFC2822 with positive offset */ ++ { "Sat, 6 Nov 2004 08:09:07 +0430", ++ ++ "Sat, 06 Nov 2004 04:39:07 GMT", ++ "Sat, 06-Nov-2004 04:39:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 +0430", ++ "20041106T080907+0430", ++ "2004-11-06T08:09:07+04:30", ++ "20041106T08:09:07" }, ++ ++ /* RFC2822 with negative offset */ ++ { "Sat, 6 Nov 2004 08:09:07 -0430", ++ ++ "Sat, 06 Nov 2004 12:39:07 GMT", ++ "Sat, 06-Nov-2004 12:39:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 -0430", ++ "20041106T080907-0430", ++ "2004-11-06T08:09:07-04:30", ++ "20041106T08:09:07" }, ++ ++ /* RFC2822 floating */ ++ { "Sat, 6 Nov 2004 08:09:07 -0000", ++ ++ "Sat, 06 Nov 2004 08:09:07 GMT", ++ "Sat, 06-Nov-2004 08:09:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 -0000", ++ "20041106T080907", ++ "2004-11-06T08:09:07", ++ "20041106T08:09:07" }, ++ ++ /* ISO GMT */ ++ { "2004-11-06T08:09:07Z", ++ ++ "Sat, 06 Nov 2004 08:09:07 GMT", ++ "Sat, 06-Nov-2004 08:09:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 +0000", ++ "20041106T080907Z", ++ "2004-11-06T08:09:07Z", ++ "20041106T08:09:07" }, ++ ++ /* ISO with positive offset */ ++ { "2004-11-06T08:09:07+04:30", ++ ++ "Sat, 06 Nov 2004 04:39:07 GMT", ++ "Sat, 06-Nov-2004 04:39:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 +0430", ++ "20041106T080907+0430", ++ "2004-11-06T08:09:07+04:30", ++ "20041106T08:09:07" }, ++ ++ /* ISO with negative offset */ ++ { "2004-11-06T08:09:07-04:30", ++ ++ "Sat, 06 Nov 2004 12:39:07 GMT", ++ "Sat, 06-Nov-2004 12:39:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 -0430", ++ "20041106T080907-0430", ++ "2004-11-06T08:09:07-04:30", ++ "20041106T08:09:07" }, ++ ++ /* ISO floating */ ++ { "2004-11-06T08:09:07", ++ ++ "Sat, 06 Nov 2004 08:09:07 GMT", ++ "Sat, 06-Nov-2004 08:09:07 GMT", ++ "Sat, 6 Nov 2004 08:09:07 -0000", ++ "20041106T080907", ++ "2004-11-06T08:09:07", ++ "20041106T08:09:07" } ++}; ++ ++static void ++check_conversion (gconstpointer data) ++{ ++ const DateConversion *conv = data; ++ SoupDate *date; ++ char *str; ++ ++ date = make_date (conv->source); ++ if (!date) { ++ soup_test_assert (FALSE, "date parsing failed for '%s'.", conv->source); ++ return; ++ } ++ ++ str = soup_date_to_string (date, SOUP_DATE_HTTP); ++ g_assert_cmpstr (str, ==, conv->http); ++ g_free (str); ++ ++ str = soup_date_to_string (date, SOUP_DATE_COOKIE); ++ g_assert_cmpstr (str, ==, conv->cookie); ++ g_free (str); ++ ++ str = soup_date_to_string (date, SOUP_DATE_RFC2822); ++ g_assert_cmpstr (str, ==, conv->rfc2822); ++ g_free (str); ++ ++ str = soup_date_to_string (date, SOUP_DATE_ISO8601_COMPACT); ++ g_assert_cmpstr (str, ==, conv->compact); ++ g_free (str); ++ ++ str = soup_date_to_string (date, SOUP_DATE_ISO8601_FULL); ++ g_assert_cmpstr (str, ==, conv->full); ++ g_free (str); ++ ++ str = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC); ++ g_assert_cmpstr (str, ==, conv->xmlrpc); ++ g_free (str); ++ ++ soup_date_free (date); ++} ++ ++int ++main (int argc, char **argv) ++{ ++ int i, ret; ++ char *path; ++ ++ test_init (argc, argv, NULL); ++ ++ for (i = 0; i < G_N_ELEMENTS (good_dates); i++) { ++ path = g_strdup_printf ("/date/good/%s", good_dates[i].date); ++ g_test_add_data_func (path, &good_dates[i], check_good); ++ g_free (path); ++ } ++ ++ for (i = 0; i < G_N_ELEMENTS (ok_dates); i++) { ++ path = g_strdup_printf ("/date/ok/%s", ok_dates[i].date); ++ g_test_add_data_func (path, &ok_dates[i], check_ok); ++ g_free (path); ++ } ++ g_test_add_func ("/date/ok/" TIME_T_STRING, check_ok_time_t); ++ ++ for (i = 0; i < G_N_ELEMENTS (bad_dates); i++) { ++ path = g_strdup_printf ("/date/bad/%s", bad_dates[i].date); ++ g_test_add_data_func (path, &bad_dates[i], check_bad); ++ g_free (path); ++ } ++ ++ for (i = 0; i < G_N_ELEMENTS (conversions); i++) { ++ path = g_strdup_printf ("/date/conversions/%s", conversions[i].source); ++ g_test_add_data_func (path, &conversions[i], check_conversion); ++ g_free (path); ++ } ++ ++ ret = g_test_run (); ++ ++ test_cleanup (); ++ return ret; ++} +-- +2.51.0 + + +From 724efae52bcf2c0b8a247f736103285ad68d1b15 Mon Sep 17 00:00:00 2001 +From: Brian Yurko <155515-byurko@users.noreply.gitlab.gnome.org> +Date: Wed, 11 Jun 2025 11:00:56 -0400 +Subject: [PATCH 2/2] tests: Add tests for date-time including timezone + validation work + +These tests are built on top of earlier work in a related pull request. + +Closes #448 +--- + libsoup/soup-date-utils.c | 339 ++++++++++++++++++++++++++++++++++++++ + tests/cookies-test.c | 1 + + 2 files changed, 340 insertions(+) + create mode 100644 libsoup/soup-date-utils.c + +diff --git a/libsoup/soup-date-utils.c b/libsoup/soup-date-utils.c +new file mode 100644 +index 00000000..73f80ab6 +--- /dev/null ++++ b/libsoup/soup-date-utils.c +@@ -0,0 +1,339 @@ ++/* ++ * Copyright (C) 2020 Igalia, S.L. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public License ++ * along with this library; see the file COPYING.LIB. If not, write to ++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++ ++#include "soup-date-utils.h" ++#include "soup-date-utils-private.h" ++ ++/** ++ * soup_date_time_is_past: ++ * @date: a #GDateTime ++ * ++ * Determines if @date is in the past. ++ * ++ * Returns: %TRUE if @date is in the past ++ */ ++gboolean ++soup_date_time_is_past (GDateTime *date) ++{ ++ g_return_val_if_fail (date != NULL, TRUE); ++ ++ /* optimization */ ++ if (g_date_time_get_year (date) < 2025) ++ return TRUE; ++ ++ return g_date_time_to_unix (date) < time (NULL); ++} ++ ++/** ++ * SoupDateFormat: ++ * @SOUP_DATE_HTTP: RFC 1123 format, used by the HTTP "Date" header. Eg ++ * "Sun, 06 Nov 1994 08:49:37 GMT". ++ * @SOUP_DATE_COOKIE: The format for the "Expires" timestamp in the ++ * Netscape cookie specification. Eg, "Sun, 06-Nov-1994 08:49:37 GMT". ++ * ++ * Date formats that [func@date_time_to_string] can use. ++ * ++ * @SOUP_DATE_HTTP and @SOUP_DATE_COOKIE always coerce the time to ++ * UTC. ++ * ++ * This enum may be extended with more values in future releases. ++ **/ ++ ++/* Do not internationalize */ ++static const char *const months[] = { ++ "Jan", "Feb", "Mar", "Apr", "May", "Jun", ++ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ++}; ++ ++/* Do not internationalize */ ++static const char *const days[] = { ++ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" ++}; ++ ++/** ++ * soup_date_time_to_string: ++ * @date: a #GDateTime ++ * @format: the format to generate the date in ++ * ++ * Converts @date to a string in the format described by @format. ++ * ++ * Returns: (transfer full): @date as a string or %NULL ++ **/ ++char * ++soup_date_time_to_string (GDateTime *date, ++ SoupDateFormat format) ++{ ++ g_return_val_if_fail (date != NULL, NULL); ++ ++ if (format == SOUP_DATE_HTTP || format == SOUP_DATE_COOKIE) { ++ /* HTTP and COOKIE formats require UTC timestamp, so coerce ++ * @date if it's non-UTC. ++ */ ++ GDateTime *utcdate = g_date_time_to_utc (date); ++ char *date_format; ++ char *formatted_date; ++ ++ // We insert days/months ourselves to avoid locale specific formatting ++ if (format == SOUP_DATE_HTTP) { ++ /* "Sun, 06 Nov 1994 08:49:37 GMT" */ ++ date_format = g_strdup_printf ("%s, %%d %s %%Y %%T GMT", ++ days[g_date_time_get_day_of_week (utcdate) - 1], ++ months[g_date_time_get_month (utcdate) - 1]); ++ } else { ++ /* "Sun, 06-Nov-1994 08:49:37 GMT" */ ++ date_format = g_strdup_printf ("%s, %%d-%s-%%Y %%T GMT", ++ days[g_date_time_get_day_of_week (utcdate) - 1], ++ months[g_date_time_get_month (utcdate) - 1]); ++ } ++ ++ formatted_date = g_date_time_format (utcdate, (const char*)date_format); ++ g_date_time_unref (utcdate); ++ g_free (date_format); ++ return formatted_date; ++ } ++ ++ g_return_val_if_reached (NULL); ++} ++ ++static inline gboolean ++parse_day (int *day, const char **date_string) ++{ ++ char *end; ++ ++ *day = strtoul (*date_string, &end, 10); ++ if (end == (char *)*date_string) ++ return FALSE; ++ ++ while (*end == ' ' || *end == '-') ++ end++; ++ *date_string = end; ++ return *day >= 1 && *day <= 31; ++} ++ ++static inline gboolean ++parse_month (int *month, const char **date_string) ++{ ++ int i; ++ ++ for (i = 0; i < G_N_ELEMENTS (months); i++) { ++ if (!g_ascii_strncasecmp (*date_string, months[i], 3)) { ++ *month = i + 1; ++ *date_string += 3; ++ while (**date_string == ' ' || **date_string == '-') ++ (*date_string)++; ++ return TRUE; ++ } ++ } ++ return FALSE; ++} ++ ++static inline gboolean ++parse_year (int *year, const char **date_string) ++{ ++ char *end; ++ ++ *year = strtoul (*date_string, &end, 10); ++ if (end == (char *)*date_string) ++ return FALSE; ++ ++ if (end == (char *)*date_string + 2) { ++ if (*year < 70) ++ *year += 2000; ++ else ++ *year += 1900; ++ } else if (end == (char *)*date_string + 3) ++ *year += 1900; ++ ++ while (*end == ' ' || *end == '-') ++ end++; ++ *date_string = end; ++ return *year > 0 && *year < 9999; ++} ++ ++static inline gboolean ++parse_time (int *hour, int *minute, int *second, const char **date_string) ++{ ++ char *p, *end; ++ ++ *hour = strtoul (*date_string, &end, 10); ++ if (end == (char *)*date_string || *end++ != ':') ++ return FALSE; ++ p = end; ++ *minute = strtoul (p, &end, 10); ++ if (end == p || *end++ != ':') ++ return FALSE; ++ p = end; ++ *second = strtoul (p, &end, 10); ++ if (end == p) ++ return FALSE; ++ p = end; ++ ++ while (*p == ' ') ++ p++; ++ *date_string = p; ++ return *hour >= 0 && *hour < 24 && *minute >= 0 && *minute < 60 && *second >= 0 && *second < 60; ++} ++ ++static inline gboolean ++parse_timezone (GTimeZone **timezone, const char **date_string) ++{ ++ gint32 offset_minutes; ++ gboolean utc; ++ ++ if (!**date_string) { ++ utc = FALSE; ++ offset_minutes = 0; ++ } else if (**date_string == '+' || **date_string == '-') { ++ gulong val; ++ int sign = (**date_string == '+') ? 1 : -1; ++ val = strtoul (*date_string + 1, (char **)date_string, 10); ++ if (val > 9999) ++ return FALSE; ++ if (**date_string == ':') { ++ gulong val2 = strtoul (*date_string + 1, (char **)date_string, 10); ++ if (val > 99 || val2 > 99) ++ return FALSE; ++ val = 60 * val + val2; ++ } else ++ val = 60 * (val / 100) + (val % 100); ++ offset_minutes = sign * val; ++ utc = (sign == -1) && !val; ++ } else if (**date_string == 'Z') { ++ offset_minutes = 0; ++ utc = TRUE; ++ (*date_string)++; ++ } else if (!strcmp (*date_string, "GMT") || ++ !strcmp (*date_string, "UTC")) { ++ offset_minutes = 0; ++ utc = TRUE; ++ (*date_string) += 3; ++ } else if (strchr ("ECMP", **date_string) && ++ ((*date_string)[1] == 'D' || (*date_string)[1] == 'S') && ++ (*date_string)[2] == 'T') { ++ offset_minutes = -60 * (5 * strcspn ("ECMP", *date_string)); ++ if ((*date_string)[1] == 'D') ++ offset_minutes += 60; ++ utc = FALSE; ++ } else ++ return FALSE; ++ ++ if (utc) ++ *timezone = g_time_zone_new_utc (); ++ else ++ *timezone = g_time_zone_new_offset (offset_minutes * 60); ++ return TRUE; ++} ++ ++static GDateTime * ++parse_textual_date (const char *date_string) ++{ ++ int month, day, year, hour, minute, second; ++ GTimeZone *tz = NULL; ++ GDateTime *date; ++ ++ /* If it starts with a word, it must be a weekday, which we skip */ ++ if (g_ascii_isalpha (*date_string)) { ++ while (g_ascii_isalpha (*date_string)) ++ date_string++; ++ if (*date_string == ',') ++ date_string++; ++ while (g_ascii_isspace (*date_string)) ++ date_string++; ++ } ++ ++ /* If there's now another word, this must be an asctime-date */ ++ if (g_ascii_isalpha (*date_string)) { ++ /* (Sun) Nov 6 08:49:37 1994 */ ++ if (!parse_month (&month, &date_string) || ++ !parse_day (&day, &date_string) || ++ !parse_time (&hour, &minute, &second, &date_string) || ++ !parse_year (&year, &date_string) || ++ !g_date_valid_dmy (day, month, year)) ++ return NULL; ++ ++ /* There shouldn't be a timezone, but check anyway */ ++ parse_timezone (&tz, &date_string); ++ } else { ++ /* Non-asctime date, so some variation of ++ * (Sun,) 06 Nov 1994 08:49:37 GMT ++ */ ++ if (!parse_day (&day, &date_string) || ++ !parse_month (&month, &date_string) || ++ !parse_year (&year, &date_string) || ++ !parse_time (&hour, &minute, &second, &date_string) || ++ !g_date_valid_dmy (day, month, year)) ++ return NULL; ++ ++ /* This time there *should* be a timezone, but we ++ * survive if there isn't. ++ */ ++ parse_timezone (&tz, &date_string); ++ } ++ ++ if (!tz) ++ tz = g_time_zone_new_utc (); ++ ++ date = g_date_time_new (tz, year, month, day, hour, minute, second); ++ g_time_zone_unref (tz); ++ ++ return date; ++} ++ ++/** ++ * soup_date_time_new_from_http_string: ++ * @date_string: The date as a string ++ * ++ * Parses @date_string and tries to extract a date from it. ++ * ++ * This recognizes all of the "HTTP-date" formats from RFC 2616, RFC 2822 dates, ++ * and reasonable approximations thereof. (Eg, it is lenient about whitespace, ++ * leading "0"s, etc.) ++ * ++ * Returns: (nullable): a new #GDateTime, or %NULL if @date_string ++ * could not be parsed. ++ **/ ++GDateTime * ++soup_date_time_new_from_http_string (const char *date_string) ++{ ++ g_return_val_if_fail (date_string != NULL, NULL); ++ ++ while (g_ascii_isspace (*date_string)) ++ date_string++; ++ ++ /* If it starts with a digit, it's either an ISO 8601 date, or ++ * an RFC2822 date without the optional weekday; in the later ++ * case, there will be a month name later on, so look for one ++ * of the month-start letters. ++ * Previous versions of this library supported parsing iso8601 strings ++ * however g_date_time_new_from_iso8601() should be used now. Just ++ * catch those in case for testing. ++ */ ++ if (G_UNLIKELY (g_ascii_isdigit (*date_string) && !strpbrk (date_string, "JFMASOND"))) { ++ g_debug ("Unsupported format passed to soup_date_time_new_from_http_string(): %s", date_string); ++ return NULL; ++ } ++ ++ return parse_textual_date (date_string); ++} +diff --git a/tests/cookies-test.c b/tests/cookies-test.c +index 61adfac5..aa719cdc 100644 +--- a/tests/cookies-test.c ++++ b/tests/cookies-test.c +@@ -292,6 +292,7 @@ static void + do_cookies_parsing_int32_overflow (void) + { + SoupCookie *cookie = soup_cookie_parse ("Age=1;expires=3Mar9 999:9:9+ 999999999-age=main=gne=", NULL); ++ g_test_bug ("https://gitlab.gnome.org/GNOME/libsoup/-/issues/448"); + g_assert_nonnull (cookie); + g_assert_null (soup_cookie_get_expires (cookie)); + soup_cookie_free (cookie); +-- +2.51.0 + diff --git a/libsoup.spec b/libsoup.spec index 32f9bb1..f130a58 100644 --- a/libsoup.spec +++ b/libsoup.spec @@ -1,9 +1,8 @@ -%define anolis_release .0.1 %define glib2_version 2.38.0 Name: libsoup Version: 2.62.3 -Release: 9%{anolis_release}%{?dist} +Release: 10%{?dist} Summary: Soup, an HTTP library implementation License: LGPLv2 @@ -44,6 +43,8 @@ Patch0020: CVE-2025-4948.patch Patch0021: fix-ssl-test.patch # https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/454 Patch0022: server-test-timeouts.patch +# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/473 +Patch0023: CVE-2025-4945-CVE-2025-11021.patch BuildRequires: chrpath BuildRequires: glib2-devel >= %{glib2_version} @@ -59,9 +60,6 @@ BuildRequires: vala Requires: glib2%{?_isa} >= %{glib2_version} Requires: glib-networking%{?_isa} >= %{glib2_version} -Requires: glibc -Requires: libxml2 - %description Libsoup is an HTTP library implementation in C. It was originally part of a SOAP (Simple Object Access Protocol) implementation called Soup, but @@ -81,14 +79,6 @@ Requires: %{name}%{?_isa} = %{version}-%{release} Libsoup is an HTTP library implementation in C. This package allows you to develop applications that use the libsoup library. -%package doc -Summary: Documents for %{name} -BuildArch: noarch -Requires: %{name} = %{version}-%{release} - -%description doc -Doc pages for %{name}. - %prep %autosetup -p1 @@ -112,6 +102,7 @@ chrpath --delete $RPM_BUILD_ROOT%{_libdir}/*.so %files -f libsoup.lang %license COPYING +%doc README NEWS AUTHORS %{_libdir}/lib*.so.* %{_libdir}/girepository-1.0/Soup*2.4.typelib @@ -127,12 +118,9 @@ chrpath --delete $RPM_BUILD_ROOT%{_libdir}/*.so %{_datadir}/vala/vapi/libsoup-2.4.deps %{_datadir}/vala/vapi/libsoup-2.4.vapi -%files doc -%doc README NEWS AUTHORS - %changelog -* Tue May 27 2025 Weisson - 2.62.3-9.0.1 -- Add doc sub package +* Thu Oct 30 2025 Michael Catanzaro - 2.62.3-10 +- Backport patch for CVE-2025-4945 and CVE-2025-11021 * Thu May 22 2025 Michael Catanzaro - 2.62.3-9 - Add patches to improve test reliability -- Gitee From 51fa3cedb2d6b607e5bb753d9568ed97e756597b Mon Sep 17 00:00:00 2001 From: Weisson Date: Mon, 18 Jul 2022 10:59:52 +0800 Subject: [PATCH 2/2] spec: add doc sub package Signed-off-by: Weisson --- libsoup.spec | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/libsoup.spec b/libsoup.spec index f130a58..85dec56 100644 --- a/libsoup.spec +++ b/libsoup.spec @@ -1,8 +1,9 @@ +%define anolis_release .0.1 %define glib2_version 2.38.0 Name: libsoup Version: 2.62.3 -Release: 10%{?dist} +Release: 10%{anolis_release}%{?dist} Summary: Soup, an HTTP library implementation License: LGPLv2 @@ -60,6 +61,9 @@ BuildRequires: vala Requires: glib2%{?_isa} >= %{glib2_version} Requires: glib-networking%{?_isa} >= %{glib2_version} +Requires: glibc +Requires: libxml2 + %description Libsoup is an HTTP library implementation in C. It was originally part of a SOAP (Simple Object Access Protocol) implementation called Soup, but @@ -79,6 +83,14 @@ Requires: %{name}%{?_isa} = %{version}-%{release} Libsoup is an HTTP library implementation in C. This package allows you to develop applications that use the libsoup library. +%package doc +Summary: Documents for %{name} +BuildArch: noarch +Requires: %{name} = %{version}-%{release} + +%description doc +Doc pages for %{name}. + %prep %autosetup -p1 @@ -102,7 +114,6 @@ chrpath --delete $RPM_BUILD_ROOT%{_libdir}/*.so %files -f libsoup.lang %license COPYING -%doc README NEWS AUTHORS %{_libdir}/lib*.so.* %{_libdir}/girepository-1.0/Soup*2.4.typelib @@ -118,7 +129,13 @@ chrpath --delete $RPM_BUILD_ROOT%{_libdir}/*.so %{_datadir}/vala/vapi/libsoup-2.4.deps %{_datadir}/vala/vapi/libsoup-2.4.vapi +%files doc +%doc README NEWS AUTHORS + %changelog +* Wed Nov 05 2025 Weisson - 2.62.3-10.0.1 +- Add doc sub package + * Thu Oct 30 2025 Michael Catanzaro - 2.62.3-10 - Backport patch for CVE-2025-4945 and CVE-2025-11021 -- Gitee