glib2/backport-CVE-2025-3360.patch
2025-05-11 00:33:13 +08:00

273 lines
8.8 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 37ae3d76695e2afe9646bc6a971110b50d080f73 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Tue, 18 Feb 2025 16:44:58 +0000
Subject: gdatetime: Fix integer overflow when parsing very long ISO8601 inputs
This will only happen with invalid (or maliciously invalid) potential
ISO8601 strings, but `g_date_time_new_from_iso8601()` needs to be robust
against that.
Prevent `length` overflowing by correctly defining it as a `size_t`.
Similarly for `date_length`, but additionally track its validity in a
boolean rather than as its sign.
Spotted by chamalsl as #YWH-PGM9867-43.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
---
glib/gdatetime.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index a43efab0b..c42cbca8c 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -1492,7 +1492,8 @@ parse_iso8601_time (const gchar *text, gsize length,
GDateTime *
g_date_time_new_from_iso8601 (const gchar *text, GTimeZone *default_tz)
{
- gint length, date_length = -1;
+ size_t length, date_length = 0;
+ gboolean date_length_set = FALSE;
gint hour = 0, minute = 0;
gdouble seconds = 0.0;
GTimeZone *tz = NULL;
@@ -1503,11 +1504,14 @@ g_date_time_new_from_iso8601 (const gchar *text, GTimeZone *default_tz)
/* Count length of string and find date / time separator ('T', 't', or ' ') */
for (length = 0; text[length] != '\0'; length++)
{
- if (date_length < 0 && (text[length] == 'T' || text[length] == 't' || text[length] == ' '))
- date_length = length;
+ if (!date_length_set && (text[length] == 'T' || text[length] == 't' || text[length] == ' '))
+ {
+ date_length = length;
+ date_length_set = TRUE;
+ }
}
- if (date_length < 0)
+ if (!date_length_set)
return NULL;
if (!parse_iso8601_time (text + date_length + 1, length - (date_length + 1),
--
2.30.2
From 1b9f28bb3d1900c725edcd5ff13a6257cc089839 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Tue, 18 Feb 2025 16:51:36 +0000
Subject: gdatetime: Fix potential integer overflow in timezone offset handling
This one is much harder to trigger than the one in the previous commit,
but mixing `gssize` and `gsize` always runs the risk of the former
overflowing for very (very very) long input strings.
Avoid that possibility by not using the sign of the `tz_offset` to
indicate its validity, and instead using the return value of the
function.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
---
glib/gdatetime.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index c42cbca8c..b410fb9f9 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -1341,8 +1341,10 @@ parse_iso8601_date (const gchar *text, gsize length,
return FALSE;
}
+/* Value returned in tz_offset is valid if and only if the function return value
+ * is non-NULL. */
static GTimeZone *
-parse_iso8601_timezone (const gchar *text, gsize length, gssize *tz_offset)
+parse_iso8601_timezone (const gchar *text, gsize length, size_t *tz_offset)
{
gint i, tz_length, offset_hours, offset_minutes;
gint offset_sign = 1;
@@ -1410,11 +1412,11 @@ static gboolean
parse_iso8601_time (const gchar *text, gsize length,
gint *hour, gint *minute, gdouble *seconds, GTimeZone **tz)
{
- gssize tz_offset = -1;
+ size_t tz_offset = 0;
/* Check for timezone suffix */
*tz = parse_iso8601_timezone (text, length, &tz_offset);
- if (tz_offset >= 0)
+ if (*tz != NULL)
length = tz_offset;
/* hh:mm:ss(.sss) */
--
2.30.2
From aae5ff8dac5371e951a2592ca9c392f17e1a3892 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Tue, 18 Feb 2025 16:55:18 +0000
Subject: gdatetime: Track timezone length as an unsigned size_t
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Its guaranteed to be in (0, length] by the calculations above.
This avoids the possibility of integer overflow through `gssize` not
being as big as `size_t`.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
---
glib/gdatetime.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index b410fb9f9..5d10c29bc 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -1346,7 +1346,8 @@ parse_iso8601_date (const gchar *text, gsize length,
static GTimeZone *
parse_iso8601_timezone (const gchar *text, gsize length, size_t *tz_offset)
{
- gint i, tz_length, offset_hours, offset_minutes;
+ size_t tz_length;
+ gint i, offset_hours, offset_minutes;
gint offset_sign = 1;
GTimeZone *tz;
--
2.30.2
From 65beb5b44ee4f51472ecb42b4c423bb1e8f57af9 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Tue, 18 Feb 2025 17:07:24 +0000
Subject: gdatetime: Factor out some string pointer arithmetic
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Makes the following code a little clearer, but doesnt introduce any
functional changes.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
---
glib/gdatetime.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index 5d10c29bc..5d02c8738 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -1350,6 +1350,7 @@ parse_iso8601_timezone (const gchar *text, gsize length, size_t *tz_offset)
gint i, offset_hours, offset_minutes;
gint offset_sign = 1;
GTimeZone *tz;
+ const char *tz_start;
/* UTC uses Z suffix */
if (length > 0 && text[length - 1] == 'Z')
@@ -1367,34 +1368,35 @@ parse_iso8601_timezone (const gchar *text, gsize length, size_t *tz_offset)
}
if (i < 0)
return NULL;
+ tz_start = text + i;
tz_length = length - i;
/* +hh:mm or -hh:mm */
- if (tz_length == 6 && text[i+3] == ':')
+ if (tz_length == 6 && tz_start[3] == ':')
{
- if (!get_iso8601_int (text + i + 1, 2, &offset_hours) ||
- !get_iso8601_int (text + i + 4, 2, &offset_minutes))
+ if (!get_iso8601_int (tz_start + 1, 2, &offset_hours) ||
+ !get_iso8601_int (tz_start + 4, 2, &offset_minutes))
return NULL;
}
/* +hhmm or -hhmm */
else if (tz_length == 5)
{
- if (!get_iso8601_int (text + i + 1, 2, &offset_hours) ||
- !get_iso8601_int (text + i + 3, 2, &offset_minutes))
+ if (!get_iso8601_int (tz_start + 1, 2, &offset_hours) ||
+ !get_iso8601_int (tz_start + 3, 2, &offset_minutes))
return NULL;
}
/* +hh or -hh */
else if (tz_length == 3)
{
- if (!get_iso8601_int (text + i + 1, 2, &offset_hours))
+ if (!get_iso8601_int (tz_start + 1, 2, &offset_hours))
return NULL;
offset_minutes = 0;
}
else
return NULL;
- *tz_offset = i;
- tz = g_time_zone_new (text + i);
+ *tz_offset = tz_start - text;
+ tz = g_time_zone_new (tz_start);
/* Double-check that the GTimeZone matches our interpretation of the timezone.
* This can fail because our interpretation is less strict than (for example)
--
2.30.2
From 0df4f223046b56db6446d1458c8a3fe61b3fed00 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Tue, 18 Feb 2025 17:28:33 +0000
Subject: gdatetime: Factor out an undersized variable
For long input strings, it would have been possible for `i` to overflow.
Avoid that problem by using the `tz_length` instead, so that we count up
rather than down.
This commit introduces no functional changes (outside of changing
undefined behaviour), and can be verified using the identity
`i === length - tz_length`.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
---
glib/gdatetime.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index 5d02c8738..1ecb6e0b3 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -1347,7 +1347,7 @@ static GTimeZone *
parse_iso8601_timezone (const gchar *text, gsize length, size_t *tz_offset)
{
size_t tz_length;
- gint i, offset_hours, offset_minutes;
+ gint offset_hours, offset_minutes;
gint offset_sign = 1;
GTimeZone *tz;
const char *tz_start;
@@ -1360,16 +1360,15 @@ parse_iso8601_timezone (const gchar *text, gsize length, size_t *tz_offset)
}
/* Look for '+' or '-' of offset */
- for (i = length - 1; i >= 0; i--)
- if (text[i] == '+' || text[i] == '-')
+ for (tz_length = 1; tz_length <= length; tz_length++)
+ if (text[length - tz_length] == '+' || text[length - tz_length] == '-')
{
- offset_sign = text[i] == '-' ? -1 : 1;
+ offset_sign = text[length - tz_length] == '-' ? -1 : 1;
break;
}
- if (i < 0)
+ if (tz_length > length)
return NULL;
- tz_start = text + i;
- tz_length = length - i;
+ tz_start = text + length - tz_length;
/* +hh:mm or -hh:mm */
if (tz_length == 6 && tz_start[3] == ':')
--
2.30.2