glib2/CVE-2026-58013.patch
RHEL Packaging Agent 3c65c9e35d Fix CVE-2026-58013: buffer over-read in GIOChannel with long terminators
Backport upstream fix for CVE-2026-58013, which addresses a
buffer over-read in GIOChannel when using multi-byte line
terminators. The memcmp() call could read past the end of
the internal GString buffer when the line extends to the
buffer boundary. The patch adds a length check before the
memcmp() and includes a new unit test. The test was adapted
for GLib 2.68 by replacing unavailable C99/GLib 2.70
constructs (uint8_t, g_steal_fd) with their GLib 2.68
equivalents.

CVE: CVE-2026-58013
Upstream patches:
 - 9f557746c5.patch
Resolves: RHEL-212237

This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.

Assisted-by: Ymir
2026-08-19 16:26:07 +00:00

171 lines
5.9 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 89f27b020f0e61a66c9308a0e67846e155c110ba Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@gnome.org>
Date: Tue, 28 Apr 2026 16:45:14 +0100
Subject: [PATCH 1/2] giochannel: Fix memcmp() off the end of the buffer with
long terminators
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If the line terminator is longer than a single byte, and the current
line extends to the end of the buffer, and the buffer (which is a
`GString`) is near a power of two in length (as thats how `GString`s
are allocated) its possible for the `memcmp()` which checks the
terminator to read off the end of the string buffer.
Fix that by checking the terminator length against the last character
before calling `memcmp()`. Add a unit test.
Spotted by linhlhq as #YWH-PGM9867-199. The fix is theirs (validated by
me), and the unit test is adapted from their proof of concept.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: #3925
---
glib/giochannel.c | 3 ++-
glib/tests/io-channel.c | 60 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/glib/giochannel.c b/glib/giochannel.c
index e93c4b458..66b68e645 100644
--- a/glib/giochannel.c
+++ b/glib/giochannel.c
@@ -1830,7 +1830,8 @@ read_again:
{
if (channel->line_term)
{
- if (memcmp (channel->line_term, nextchar, line_term_len) == 0)
+ if ((size_t) (lastchar - nextchar) >= line_term_len &&
+ memcmp (channel->line_term, nextchar, line_term_len) == 0)
{
line_length = nextchar - use_buf->str;
got_term_len = line_term_len;
diff --git a/glib/tests/io-channel.c b/glib/tests/io-channel.c
index 4a1b10876..c619fb00f 100644
--- a/glib/tests/io-channel.c
+++ b/glib/tests/io-channel.c
@@ -69,6 +69,65 @@ test_read_line_embedded_nuls (void)
g_free (filename);
}
+static void
+test_read_line_long_terminator (void)
+{
+ uint8_t *test_data = NULL;
+ size_t test_data_len = 0;
+ int fd;
+ char *filename = NULL;
+ GIOChannel *channel = NULL;
+ GError *local_error = NULL;
+ char *line = NULL;
+ size_t line_length, terminator_pos;
+ const char *line_term;
+ int line_term_length;
+ GIOStatus status;
+
+ g_test_summary ("Test that reading a line when using a long terminator doesnt over-read the buffer.");
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/work_items/3925");
+
+ /* Write out a temporary file containing 2047 bytes. This is enough to make it
+ * near the length of the GString buffer when read back in. */
+ fd = g_file_open_tmp ("glib-test-io-channel-XXXXXX", &filename, &local_error);
+ g_assert_no_error (local_error);
+ g_close (g_steal_fd (&fd), NULL);
+
+ test_data_len = 2047;
+ test_data = g_malloc (test_data_len);
+ memset (test_data, 'M', test_data_len);
+ g_file_set_contents (filename, (const gchar *) test_data, test_data_len, &local_error);
+ g_assert_no_error (local_error);
+
+ /* Create the channel. */
+ channel = g_io_channel_new_file (filename, "r", &local_error);
+ g_assert_no_error (local_error);
+
+ /* Use a long line terminator so it could potentially over-read the end of the buffer. */
+ g_io_channel_set_line_term (channel, "DEADBEEF", 8);
+
+ line_term = g_io_channel_get_line_term (channel, &line_term_length);
+ g_assert_cmpstr (line_term, ==, "DEADBEEF");
+ g_assert_cmpint (line_term_length, ==, 8);
+
+ g_io_channel_set_encoding (channel, "UTF-8", &local_error);
+ g_assert_no_error (local_error);
+
+ status = g_io_channel_read_line (channel, &line, &line_length,
+ &terminator_pos, &local_error);
+ g_assert_no_error (local_error);
+ g_assert_cmpint (status, ==, G_IO_STATUS_NORMAL);
+ g_assert_cmpuint (line_length, ==, 2047);
+ g_assert_cmpuint (terminator_pos, ==, 2047);
+ g_assert_cmpmem (line, line_length, test_data, test_data_len);
+
+ g_free (line);
+ g_io_channel_unref (channel);
+ g_free (test_data);
+ g_unlink (filename);
+ g_free (filename);
+}
+
int
main (int argc,
char *argv[])
@@ -76,6 +135,7 @@ main (int argc,
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/io-channel/read-line/embedded-nuls", test_read_line_embedded_nuls);
+ g_test_add_func ("/io-channel/read-line/long-terminator", test_read_line_long_terminator);
return g_test_run ();
}
From 94b3e1b6d1380c8f78e1e869b5cb46b2fbfe6689 Mon Sep 17 00:00:00 2001
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
Date: Wed, 19 Aug 2026 15:07:16 +0000
Subject: [PATCH 2/2] Adapt test for GLib 2.68: replace uint8_t with guint8 and
g_steal_fd with inline equivalent
---
glib/tests/io-channel.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/glib/tests/io-channel.c b/glib/tests/io-channel.c
index c619fb00f..afcea93f0 100644
--- a/glib/tests/io-channel.c
+++ b/glib/tests/io-channel.c
@@ -72,16 +72,16 @@ test_read_line_embedded_nuls (void)
static void
test_read_line_long_terminator (void)
{
- uint8_t *test_data = NULL;
- size_t test_data_len = 0;
- int fd;
- char *filename = NULL;
+ guint8 *test_data = NULL;
+ gsize test_data_len = 0;
+ gint fd;
+ gchar *filename = NULL;
GIOChannel *channel = NULL;
GError *local_error = NULL;
- char *line = NULL;
- size_t line_length, terminator_pos;
- const char *line_term;
- int line_term_length;
+ gchar *line = NULL;
+ gsize line_length, terminator_pos;
+ const gchar *line_term;
+ gint line_term_length;
GIOStatus status;
g_test_summary ("Test that reading a line when using a long terminator doesnt over-read the buffer.");
@@ -91,7 +91,8 @@ test_read_line_long_terminator (void)
* near the length of the GString buffer when read back in. */
fd = g_file_open_tmp ("glib-test-io-channel-XXXXXX", &filename, &local_error);
g_assert_no_error (local_error);
- g_close (g_steal_fd (&fd), NULL);
+ g_close (fd, NULL);
+ fd = -1;
test_data_len = 2047;
test_data = g_malloc (test_data_len);