glibc: 2.42-61 -> 2.42-67

This commit is contained in:
zowoq 2026-05-09 12:06:55 +10:00
commit 4a8e8392a4
2 changed files with 762 additions and 3 deletions

View file

@ -7154,3 +7154,762 @@ index 00181cfefb..e83ea2b939 100644
TEST_VERIFY (ret != 0);
TEST_COMPARE (errno, EBUSY);
}
commit f13c1bb0f97fbc12a6ba1ab5669ce561ea32b80a
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Apr 16 19:13:43 2026 +0200
Use pending character state in IBM1390, IBM1399 character sets (CVE-2026-4046)
Follow the example in iso-2022-jp-3.c and use the __count state
variable to store the pending character. This avoids restarting
the conversion if the output buffer ends between two 4-byte UCS-4
code points, so that the assert reported in the bug can no longer
happen.
Even though the fix is applied to ibm1364.c, the change is only
effective for the two HAS_COMBINED codecs for IBM1390, IBM1399.
The test case was mostly auto-generated using
claude-4.6-opus-high-thinking, and composer-2-fast shows up in the
log as well. During review, gpt-5.4-xhigh flagged that the original
version of the test case was not exercising the new character
flush logic.
This fixes bug 33980.
Assisted-by: LLM
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit d6f08d1cf027f4eb2ba289a6cc66853722d4badc)
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index 5a2abeea24..cc689f63e9 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -76,7 +76,7 @@ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
bug-iconv13 bug-iconv14 bug-iconv15 \
- tst-iconv-iso-2022-cn-ext
+ tst-iconv-iso-2022-cn-ext tst-bug33980
ifeq ($(have-thread-library),yes)
tests += bug-iconv3
endif
@@ -333,6 +333,8 @@ $(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
+$(objpfx)tst-bug33980.out: $(addprefix $(objpfx), $(gconv-modules)) \
+ $(addprefix $(objpfx),$(modules.so))
$(objpfx)iconv-test.out: run-iconv-test.sh \
$(addprefix $(objpfx), $(gconv-modules)) \
diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c
index 45c62acee5..244c61ad7a 100644
--- a/iconvdata/ibm1364.c
+++ b/iconvdata/ibm1364.c
@@ -67,12 +67,29 @@
/* Since this is a stateful encoding we have to provide code which resets
the output state to the initial state. This has to be done during the
- flushing. */
+ flushing. For the to-internal direction (FROM_DIRECTION is true),
+ there may be a pending character that needs flushing. */
#define EMIT_SHIFT_TO_INIT \
if ((data->__statep->__count & ~7) != sb) \
{ \
if (FROM_DIRECTION) \
- data->__statep->__count &= 7; \
+ { \
+ uint32_t ch = data->__statep->__count >> 7; \
+ if (__glibc_unlikely (ch != 0)) \
+ { \
+ if (__glibc_unlikely (outend - outbuf < 4)) \
+ status = __GCONV_FULL_OUTPUT; \
+ else \
+ { \
+ put32 (outbuf, ch); \
+ outbuf += 4; \
+ /* Clear character and db bit. */ \
+ data->__statep->__count &= 7; \
+ } \
+ } \
+ else \
+ data->__statep->__count &= 7; \
+ } \
else \
{ \
/* We are not in the initial state. To switch back we have \
@@ -99,11 +116,13 @@
*curcsp = save_curcs
-/* Current codeset type. */
+/* Current codeset type. The bit is stored in the __count variable of
+ the conversion state. If the db bit is set, bit 7 and above store
+ a pending UCS-4 code point if non-zero. */
enum
{
- sb = 0,
- db = 64
+ sb = 0, /* Single byte mode. */
+ db = 64 /* Double byte mode. */
};
@@ -119,21 +138,29 @@ enum
} \
else \
{ \
- /* This is a combined character. Make sure we have room. */ \
- if (__glibc_unlikely (outptr + 8 > outend)) \
- { \
- result = __GCONV_FULL_OUTPUT; \
- break; \
- } \
- \
const struct divide *cmbp \
= &DB_TO_UCS4_COMB[ch - __TO_UCS4_COMBINED_MIN]; \
assert (cmbp->res1 != 0 && cmbp->res2 != 0); \
\
put32 (outptr, cmbp->res1); \
outptr += 4; \
- put32 (outptr, cmbp->res2); \
- outptr += 4; \
+ \
+ /* See whether we have room for the second character. */ \
+ if (outend - outptr >= 4) \
+ { \
+ put32 (outptr, cmbp->res2); \
+ outptr += 4; \
+ } \
+ else \
+ { \
+ /* Otherwise store only the first character now, and \
+ put the second one into the queue. */ \
+ curcs |= cmbp->res2 << 7; \
+ inptr += 2; \
+ /* Tell the caller why we terminate the loop. */ \
+ result = __GCONV_FULL_OUTPUT; \
+ break; \
+ } \
} \
}
#else
@@ -153,7 +180,20 @@ enum
#define LOOPFCT FROM_LOOP
#define BODY \
{ \
- uint32_t ch = *inptr; \
+ uint32_t ch; \
+ \
+ ch = curcs >> 7; \
+ if (__glibc_unlikely (ch != 0)) \
+ { \
+ put32 (outptr, ch); \
+ outptr += 4; \
+ /* Remove the pending character, but preserve state bits. */ \
+ curcs &= (1 << 7) - 1; \
+ continue; \
+ } \
+ \
+ /* Otherwise read the next input byte. */ \
+ ch = *inptr; \
\
if (__builtin_expect (ch, 0) == SO) \
{ \
diff --git a/iconvdata/tst-bug33980.c b/iconvdata/tst-bug33980.c
new file mode 100644
index 0000000000..c9693e0efe
--- /dev/null
+++ b/iconvdata/tst-bug33980.c
@@ -0,0 +1,153 @@
+/* Test for bug 33980: combining characters in IBM1390/IBM1399.
+ Copyright (C) 2026 Free Software Foundation, Inc.
+ 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 <alloc_buffer.h>
+#include <errno.h>
+#include <iconv.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/next_to_fault.h>
+#include <support/support.h>
+
+/* Run iconv in a loop with a small output buffer of OUTBUFSIZE bytes
+ starting at OUTBUF. OUTBUF should be right before an unmapped page
+ so that writing past the end will fault. Skip SHIFT bytes at the
+ start of the input and output, to exercise different buffer
+ alignment. TRUNCATE indicates skipped bytes at the end of
+ input (0 and 1 a valid). */
+static void
+test_one (const char *encoding, unsigned int shift, unsigned int truncate,
+ char *outbuf, size_t outbufsize)
+{
+ /* In IBM1390 and IBM1399, the DBCS code 0xECB5 expands to two
+ Unicode code points when translated. */
+ static char input[] =
+ {
+ /* 8 letters X. */
+ 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+ /* SO, 0xECB5, SI: shift to DBCS, special character, shift back. */
+ 0x0e, 0xec, 0xb5, 0x0f
+ };
+
+ /* Expected output after UTF-8 conversion. */
+ static char expected[] =
+ {
+ 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X',
+ /* U+304B (HIRAGANA LETTER KA). */
+ 0xe3, 0x81, 0x8b,
+ /* U+309A (COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK). */
+ 0xe3, 0x82, 0x9a
+ };
+
+ iconv_t cd = iconv_open ("UTF-8", encoding);
+ TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+ char result_storage[64];
+ struct alloc_buffer result_buf
+ = alloc_buffer_create (result_storage, sizeof (result_storage));
+
+ char *inptr = &input[shift];
+ size_t inleft = sizeof (input) - shift - truncate;
+
+ while (inleft > 0)
+ {
+ char *outptr = outbuf;
+ size_t outleft = outbufsize;
+ size_t inleft_before = inleft;
+
+ size_t ret = iconv (cd, &inptr, &inleft, &outptr, &outleft);
+ size_t produced = outptr - outbuf;
+ alloc_buffer_copy_bytes (&result_buf, outbuf, produced);
+
+ if (ret == (size_t) -1 && errno == E2BIG)
+ {
+ if (produced == 0 && inleft == inleft_before)
+ {
+ /* Output buffer too small to make progress. This is
+ expected for very small output buffer sizes. */
+ TEST_VERIFY_EXIT (outbufsize < 3);
+ break;
+ }
+ continue;
+ }
+ if (ret == (size_t) -1)
+ FAIL_EXIT1 ("%s (outbufsize %zu): iconv: %m", encoding, outbufsize);
+ break;
+ }
+
+ /* Flush any pending state (e.g. a buffered combined character).
+ With outbufsize < 3, we could not store the first character, so
+ the second character did not become pending, and there is nothing
+ to flush. */
+ {
+ char *outptr = outbuf;
+ size_t outleft = outbufsize;
+
+ size_t ret = iconv (cd, NULL, NULL, &outptr, &outleft);
+ TEST_VERIFY_EXIT (ret == 0);
+ size_t produced = outptr - outbuf;
+ alloc_buffer_copy_bytes (&result_buf, outbuf, produced);
+
+ /* Second flush does not provide more data. */
+ outptr = outbuf;
+ outleft = outbufsize;
+ ret = iconv (cd, NULL, NULL, &outptr, &outleft);
+ TEST_VERIFY_EXIT (ret == 0);
+ TEST_VERIFY (outptr == outbuf);
+ }
+
+ TEST_VERIFY_EXIT (!alloc_buffer_has_failed (&result_buf));
+ size_t result_used
+ = sizeof (result_storage) - alloc_buffer_size (&result_buf);
+
+ if (outbufsize >= 3)
+ {
+ TEST_COMPARE (inleft, 0);
+ TEST_COMPARE (result_used, sizeof (expected) - shift);
+ TEST_COMPARE_BLOB (result_storage, result_used,
+ &expected[shift], sizeof (expected) - shift);
+ }
+ else
+ /* If the buffer is too small, only the leading X could be converted. */
+ TEST_COMPARE (result_used, 8 - shift);
+
+ TEST_VERIFY_EXIT (iconv_close (cd) == 0);
+}
+
+static int
+do_test (void)
+{
+ struct support_next_to_fault ntf
+ = support_next_to_fault_allocate (8);
+
+ for (int shift = 0; shift <= 8; ++shift)
+ for (int truncate = 0; truncate < 2; ++truncate)
+ for (size_t outbufsize = 1; outbufsize <= 8; outbufsize++)
+ {
+ char *outbuf = ntf.buffer + ntf.length - outbufsize;
+ test_one ("IBM1390", shift, truncate, outbuf, outbufsize);
+ test_one ("IBM1399", shift, truncate, outbuf, outbufsize);
+ }
+
+ support_next_to_fault_free (&ntf);
+ return 0;
+}
+
+#include <support/test-driver.c>
commit 12feedaf67e11c4618dc50c6aab4dbfd1e6d9531
Author: DJ Delorie <dj@redhat.com>
Date: Mon Jan 26 22:24:42 2026 -0500
include: isolate __O_CLOEXEC flag for sys/mount.h and fcntl.h
Including sys/mount.h should not implicitly include fcntl.h
as that causes namespace pollution and conflicts with kernel
headers. It only needs O_CLOEXEC for OPEN_TREE_CLOEXEC
(although it shouldn't need that, but it's defined that way)
so we provide that define (via a private version) separately.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Tested-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 419245719ccbc7dad6a97f24465e7f09c090327a)
diff --git a/io/fcntl.c b/io/fcntl.c
index e88e28664c..b7dab1bb39 100644
--- a/io/fcntl.c
+++ b/io/fcntl.c
@@ -18,6 +18,10 @@
#include <errno.h>
#include <fcntl.h>
+#ifndef __O_CLOEXEC
+# error __O_CLOEXEC not defined by fcntl.h/cloexec.h
+#endif
+
/* Perform file control operations on FD. */
int
__fcntl (int fd, int cmd, ...)
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index c47cbdf428..053041f256 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -129,6 +129,7 @@ CFLAGS-test-errno-linux.c += $(no-fortify-source)
sysdep_headers += \
bits/a.out.h \
+ bits/cloexec.h \
bits/epoll.h \
bits/eventfd.h \
bits/inotify.h \
diff --git a/sysdeps/unix/sysv/linux/alpha/bits/cloexec.h b/sysdeps/unix/sysv/linux/alpha/bits/cloexec.h
new file mode 100644
index 0000000000..f381f28a53
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/alpha/bits/cloexec.h
@@ -0,0 +1 @@
+#define __O_CLOEXEC 010000000
diff --git a/sysdeps/unix/sysv/linux/bits/cloexec.h b/sysdeps/unix/sysv/linux/bits/cloexec.h
new file mode 100644
index 0000000000..3059fb6473
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bits/cloexec.h
@@ -0,0 +1 @@
+#define __O_CLOEXEC 02000000
diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
index f425a4bf22..98954feaca 100644
--- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
+++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
@@ -81,9 +81,7 @@
#ifndef __O_NOFOLLOW
# define __O_NOFOLLOW 0400000
#endif
-#ifndef __O_CLOEXEC
-# define __O_CLOEXEC 02000000
-#endif
+#include <bits/cloexec.h>
#ifndef __O_DIRECT
# define __O_DIRECT 040000
#endif
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/cloexec.h b/sysdeps/unix/sysv/linux/hppa/bits/cloexec.h
new file mode 100644
index 0000000000..f381f28a53
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/hppa/bits/cloexec.h
@@ -0,0 +1 @@
+#define __O_CLOEXEC 010000000
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/cloexec.h b/sysdeps/unix/sysv/linux/sparc/bits/cloexec.h
new file mode 100644
index 0000000000..6706eaa7d5
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/bits/cloexec.h
@@ -0,0 +1 @@
+#define __O_CLOEXEC 0x400000
diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
index b549e75148..365da1c296 100644
--- a/sysdeps/unix/sysv/linux/sys/mount.h
+++ b/sysdeps/unix/sysv/linux/sys/mount.h
@@ -21,7 +21,6 @@
#ifndef _SYS_MOUNT_H
#define _SYS_MOUNT_H 1
-#include <fcntl.h>
#include <features.h>
#include <stdint.h>
#include <stddef.h>
@@ -266,6 +265,11 @@ enum fsconfig_command
/* open_tree flags. */
#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
+#ifndef O_CLOEXEC
+# include <bits/cloexec.h>
+# define O_CLOEXEC __O_CLOEXEC
+#endif
+#undef OPEN_TREE_CLOEXEC
#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
diff --git a/sysdeps/unix/sysv/linux/tst-mount.c b/sysdeps/unix/sysv/linux/tst-mount.c
index 40913c7082..78a2772b2f 100644
--- a/sysdeps/unix/sysv/linux/tst-mount.c
+++ b/sysdeps/unix/sysv/linux/tst-mount.c
@@ -20,6 +20,7 @@
#include <support/check.h>
#include <support/xunistd.h>
#include <support/namespace.h>
+#include <fcntl.h> /* For AT_ constants. */
#include <sys/mount.h>
_Static_assert (sizeof (struct mount_attr) == MOUNT_ATTR_SIZE_VER0,
commit 3ecfa68561d723564a1fb565366182eb4acb3e8f
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Mar 4 18:32:36 2026 +0100
Linux: Only define OPEN_TREE_* macros in <sys/mount.h> if undefined (bug 33921)
There is a conditional inclusion of <linux/mount.h> earlier in the file.
If that defines the macros, do not redefine them. This addresses build
problems as the token sequence used by the UAPI macro definitions
changes between Linux versions.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit d12b017cddfeb9fe9920ba054ae3dfcb8e9238b8)
diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
index 365da1c296..30ba56c1e8 100644
--- a/sysdeps/unix/sysv/linux/sys/mount.h
+++ b/sysdeps/unix/sysv/linux/sys/mount.h
@@ -264,14 +264,16 @@ enum fsconfig_command
#define FSOPEN_CLOEXEC 0x00000001
/* open_tree flags. */
-#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
+#ifndef OPEN_TREE_CLONE
+# define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
+#endif
#ifndef O_CLOEXEC
# include <bits/cloexec.h>
# define O_CLOEXEC __O_CLOEXEC
#endif
-#undef OPEN_TREE_CLOEXEC
-#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
-
+#ifndef OPEN_TREE_CLOEXEC
+# define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
+#endif
__BEGIN_DECLS
commit 3e87cf9be93acf19d685e8003fc649cdb052a891
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Apr 13 10:46:42 2026 +0800
abilist.awk: Handle weak unversioned defined symbols
After
commit f685e3953f9a38a41bbd0a597f9882870cee13d5
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Wed Oct 29 09:49:57 2025 +0800
elf: Don't set its DT_VERSYM entry for unversioned symbol
ld no longer assigns version index 1 to unversioned defined symbol.
For libmachuser.so, "objdump --dynamic-syms" reports:
0000dd30 w DF .text 000000f8 processor_start
instead of
0000dd30 w DF .text 000000f8 (Base) processor_start
Also allow NF == 6 for weak unversioned dynamic symbols. This fixes BZ
33650.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit ee5d1db2a81468413fbf7c82779ffa782f429d1a)
diff --git a/scripts/abilist.awk b/scripts/abilist.awk
index 6cc7af6ac8..7ea1edf8c0 100644
--- a/scripts/abilist.awk
+++ b/scripts/abilist.awk
@@ -38,7 +38,7 @@ $4 == "*UND*" { next }
$2 == "l" { next }
# If the target uses ST_OTHER, it will be output before the symbol name.
-$2 == "g" || $2 == "w" && (NF == 7 || NF == 8) {
+$2 == "g" || $2 == "w" && (NF == 6 || NF == 7 || NF == 8) {
type = $3;
size = $5;
sub(/^0*/, "", size);
commit b4bca35ab9e76890504c4dbdd5eaf15a93514580
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>
(cherry picked from commit ef3bfb5f910011f3780cb06aa47e730035f53285)
diff --git a/libio/Makefile b/libio/Makefile
index f020f8ec4d..fa2b8ae791 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -83,6 +83,7 @@ tests = \
bug-ungetwc1 \
bug-ungetwc2 \
bug-wfflush \
+ bug-wgenops-bz33998 \
bug-wmemstream1 \
bug-wsetpos \
test-fmemopen \
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 0a11d1b1de..9e0b2c00ea 100644
--- a/libio/wgenops.c
+++ b/libio/wgenops.c
@@ -108,8 +108,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!*/
commit 4ebd33dd77eabe8d4c45232bed4b42a31d2f9edc
Author: Rocket Ma <marocketbd@gmail.com>
Date: Fri Apr 17 23:48:41 2026 -0700
stdio-common: Fix buffer overflow in scanf %mc [BZ #34008]
* stdio-common/vfscanf-internal.c: When enlarging allocated buffer with
format %mc or %mC, glibc allocates one byte less, leading to
user-controlled one byte overflow. This commit fixes BZ #34008, or
CVE-2026-5450.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Signed-off-by: Rocket Ma <marocketbd@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 839898777226a3ed88c0859f25ffe712519b4ead)
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 64b3575acb..e52c333808 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -347,6 +347,7 @@ tests := \
tst-vfprintf-user-type \
tst-vfprintf-width-i18n \
tst-vfprintf-width-prec-alloc \
+ tst-vfscanf-bz34008 \
tst-wc-printf \
tstdiomisc \
tstgetln \
@@ -562,6 +563,9 @@ tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \
tst-vfprintf-width-prec-ENV = \
MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+tst-vfscanf-bz34008-ENV = \
+ MALLOC_CHECK_=3 \
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
tst-printf-bz25691-ENV = \
MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
diff --git a/stdio-common/tst-vfscanf-bz34008.c b/stdio-common/tst-vfscanf-bz34008.c
new file mode 100644
index 0000000000..48371c8a3d
--- /dev/null
+++ b/stdio-common/tst-vfscanf-bz34008.c
@@ -0,0 +1,48 @@
+/* Regression test for vfscanf %Nmc out-of-bound write (BZ #34008)
+ 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 "malloc/mcheck.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <support/check.h>
+
+#define WIDTH 0x410
+#define SCANFSTR "%1040mc"
+static int
+do_test (void)
+{
+ mcheck_pedantic (NULL);
+ char *input = malloc (WIDTH + 1);
+ TEST_VERIFY (input != NULL);
+ memset (input, 'A', WIDTH);
+ input[WIDTH] = '\0';
+
+ char *buf = NULL;
+ TEST_VERIFY (sscanf (input, SCANFSTR, &buf) != -1);
+ TEST_VERIFY (buf != NULL);
+
+ free (buf);
+ free (input);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 86ae5019a6..17b5565d0f 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -853,8 +853,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
{
/* Enlarge the buffer. */
size_t newsize
- = strsize
- + (strsize >= width ? width - 1 : strsize);
+ = strsize + (strsize >= width ? width : strsize);
str = (char *) realloc (*strptr, newsize);
if (str == NULL)
@@ -925,7 +924,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& wstr == (wchar_t *) *strptr + strsize)
{
size_t newsize
- = strsize + (strsize > width ? width - 1 : strsize);
+ = strsize + (strsize >= width ? width : strsize);
/* Enlarge the buffer. */
wstr = (wchar_t *) realloc (*strptr,
newsize * sizeof (wchar_t));
@@ -980,7 +979,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& wstr == (wchar_t *) *strptr + strsize)
{
size_t newsize
- = strsize + (strsize > width ? width - 1 : strsize);
+ = strsize + (strsize >= width ? width : strsize);
/* Enlarge the buffer. */
wstr = (wchar_t *) realloc (*strptr,
newsize * sizeof (wchar_t));

View file

@ -51,7 +51,7 @@
let
version = "2.42";
patchSuffix = "-61";
patchSuffix = "-67";
sha256 = "sha256-0XdeMuRijmTvkw9DW2e7Y691may2viszW58Z8WUJ8X8=";
in
@ -68,8 +68,8 @@ stdenv.mkDerivation (
patches = [
/*
No tarballs for stable upstream branch, only https://sourceware.org/git/glibc.git and using git would complicate bootstrapping.
$ git fetch --all -p && git checkout origin/release/2.40/master && git describe
glibc-2.42-61-ga56a2943d2
$ git fetch --all -p && git checkout origin/release/2.42/master && git describe
glibc-2.42-67-g4ebd33dd77
$ git show --minimal --reverse glibc-2.42.. ':!ADVISORIES' > 2.42-master.patch
To compare the archive contents zdiff can be used.