109 lines
4.1 KiB
Diff
109 lines
4.1 KiB
Diff
commit ef3bfb5f910011f3780cb06aa47e730035f53285
|
|
Author: Rocket Ma <marocketbd@gmail.com>
|
|
Date: Fri May 1 20:39:07 2026 -0700
|
|
|
|
libio: Fix ungetwc operating on byte stream [BZ #33998]
|
|
|
|
* libio/wgenops.c: When _IO_wdefault_pbackfail attempts to push back one
|
|
character, it accidently compare the wchar to push back with the last
|
|
char from byte stream, instead of wide stream. Under specific coding,
|
|
attacker may exploit this to leak information. This commit fix bug
|
|
33998, or CVE-2026-5928.
|
|
|
|
Signed-off-by: Rocket Ma <marocketbd@gmail.com>
|
|
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
|
|
|
Conflicts:
|
|
libio/Makefile
|
|
(Usual conflict when adding tests due to missing backports.)
|
|
|
|
diff -Nrup a/libio/Makefile b/libio/Makefile
|
|
--- a/libio/Makefile 2026-06-25 12:22:31.811580535 -0400
|
|
+++ b/libio/Makefile 2026-06-25 12:26:47.978009204 -0400
|
|
@@ -58,8 +58,8 @@ tests = tst_swprintf tst_wprintf tst_sws
|
|
tst-freopen bug-rewind bug-rewind2 bug-ungetc bug-fseek \
|
|
tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \
|
|
tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \
|
|
- bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \
|
|
- tst-memstream1 tst-memstream2 tst-memstream3 \
|
|
+ bug-wgenops-bz33998 bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 \
|
|
+ tst-fopenloc2 tst-memstream1 tst-memstream2 tst-memstream3 \
|
|
tst-wmemstream1 tst-wmemstream2 tst-wmemstream3 \
|
|
bug-memstream1 bug-wmemstream1 \
|
|
tst-setvbuf1 tst-popen-fork tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
|
|
diff --git a/libio/bug-wgenops-bz33998.c b/libio/bug-wgenops-bz33998.c
|
|
new file mode 100644
|
|
index 0000000000..cc4067da99
|
|
--- /dev/null
|
|
+++ b/libio/bug-wgenops-bz33998.c
|
|
@@ -0,0 +1,54 @@
|
|
+/* Regression test for ungetwc operating on byte stream (BZ #33998)
|
|
+ Copyright (C) 2026 The GNU Toolchain Authors.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can redistribute it and/or
|
|
+ modify it under the terms of the GNU Lesser General Public
|
|
+ License as published by the Free Software Foundation; either
|
|
+ version 2.1 of the License, or (at your option) any later version.
|
|
+
|
|
+ The GNU C 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
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include "support/temp_file.h"
|
|
+#include "support/xstdio.h"
|
|
+#include "support/xunistd.h"
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/mman.h>
|
|
+#include <stdio.h>
|
|
+#include <wchar.h>
|
|
+#include <support/check.h>
|
|
+
|
|
+static int
|
|
+do_test (void)
|
|
+{
|
|
+ char *filename;
|
|
+ int fd = create_temp_file ("tst-bz33998-", &filename);
|
|
+ TEST_VERIFY (fd != -1);
|
|
+ xwrite (fd, "A", sizeof ("A")); // write "A\0" by design
|
|
+ xclose (fd);
|
|
+
|
|
+ FILE *fp = xfopen (filename, "r+");
|
|
+ TEST_COMPARE (getwc (fp), L'A');
|
|
+ /* If the bug is fixed, then ungetwc should not touch byte stream.
|
|
+ If the bug is not fixed, ungetwc firstly match last read char, L'A',
|
|
+ failed, then the pbackfail branch, matching last read char in byte
|
|
+ stream, that is, '\0' (initialized when setup wide stream). */
|
|
+ char *old_read_ptr = fp->_IO_read_ptr;
|
|
+ TEST_COMPARE (ungetwc (L'\0', fp), L'\0');
|
|
+ TEST_VERIFY (fp->_IO_read_ptr == old_read_ptr);
|
|
+
|
|
+ xfclose (fp);
|
|
+ free (filename);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#include <support/test-driver.c>
|
|
diff --git a/libio/wgenops.c b/libio/wgenops.c
|
|
index 6829477e0c..5f36bc49a1 100644
|
|
--- a/libio/wgenops.c
|
|
+++ b/libio/wgenops.c
|
|
@@ -110,8 +110,8 @@ _IO_wdefault_pbackfail (FILE *fp, wint_t c)
|
|
{
|
|
if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
|
|
&& !_IO_in_backup (fp)
|
|
- && (wint_t) fp->_IO_read_ptr[-1] == c)
|
|
- --fp->_IO_read_ptr;
|
|
+ && (wint_t) fp->_wide_data->_IO_read_ptr[-1] == c)
|
|
+ --fp->_wide_data->_IO_read_ptr;
|
|
else
|
|
{
|
|
/* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
|