import CS git glibc-2.34-272.el9_8
This commit is contained in:
parent
bd103df304
commit
d39fb886f1
206
SOURCES/glibc-RHEL-145156-1.patch
Normal file
206
SOURCES/glibc-RHEL-145156-1.patch
Normal file
@ -0,0 +1,206 @@
|
||||
commit 0981c03c2752b5f12ede24e6e696d5a29f7c6396
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
Date: Wed Apr 29 15:53:51 2026 +0200
|
||||
|
||||
libio: Fix gconv module reference counter overflow in swscanf
|
||||
|
||||
The swscanf family of functions creates a wide-oriented FILE stream
|
||||
on the stack. Initialization of this stream invokes `_IO_fwide`, which
|
||||
clones the global locale's gconv transformation steps via
|
||||
`__wcsmbs_clone_conv`. This increments the reference counter (`__counter`)
|
||||
of the gconv module.
|
||||
|
||||
Because the FILE stream is stack-allocated, `fclose` cannot be called,
|
||||
and so `__gconv_release_step` is never invoked. The counter leaks,
|
||||
eventually hitting the 32-bit integer overflow limit and aborting the
|
||||
process.
|
||||
|
||||
To resolve this, we introduce `_IO_wstrfile_fclose_stack`, a dedicated
|
||||
cleanup function for stack-allocated FILE streams. This function invokes
|
||||
`_IO_FINISH` and correctly releases the gconv steps via
|
||||
`__gconv_release_step` without attempting to `free` the FILE pointer.
|
||||
This cleanup function is then hooked into all variants of swscanf right
|
||||
before they return.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
sysdeps/ieee754/ldbl-opt/nldbl-compat.c
|
||||
(isoc23 variants not present downstream)
|
||||
sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc23_swscanf.c
|
||||
(not present downstream)
|
||||
sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc23_vswscanf.c
|
||||
(not present downstream)
|
||||
wcsmbs/isoc23_swscanf.c
|
||||
(not present downstream)
|
||||
wcsmbs/isoc23_vswscanf.c
|
||||
(not present downstream)
|
||||
|
||||
diff --git a/libio/iofwide.c b/libio/iofwide.c
|
||||
index a7f29fa0b9693cc3..972f154365e88bb3 100644
|
||||
--- a/libio/iofwide.c
|
||||
+++ b/libio/iofwide.c
|
||||
@@ -257,3 +257,18 @@ __libio_codecvt_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
|
||||
|
||||
return result;
|
||||
}
|
||||
+
|
||||
+void
|
||||
+_IO_wstrfile_fclose_stack (FILE *fp)
|
||||
+{
|
||||
+ _IO_FINISH (fp);
|
||||
+ if (fp->_mode > 0)
|
||||
+ {
|
||||
+ struct _IO_codecvt *cc = fp->_codecvt;
|
||||
+
|
||||
+ __libc_lock_lock (__gconv_lock);
|
||||
+ __gconv_release_step (cc->__cd_in.step);
|
||||
+ __gconv_release_step (cc->__cd_out.step);
|
||||
+ __libc_lock_unlock (__gconv_lock);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
|
||||
index 35bddc0daeca917f..284c61615ebddd47 100644
|
||||
--- a/libio/iovswscanf.c
|
||||
+++ b/libio/iovswscanf.c
|
||||
@@ -38,6 +38,8 @@ __vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
|
||||
_IO_strfile sf;
|
||||
struct _IO_wide_data wd;
|
||||
FILE *f = _IO_strfile_readw (&sf, &wd, string);
|
||||
- return __vfwscanf_internal (f, format, args, 0);
|
||||
+ int done = __vfwscanf_internal (f, format, args, 0);
|
||||
+ _IO_wstrfile_fclose_stack (f);
|
||||
+ return done;
|
||||
}
|
||||
ldbl_weak_alias (__vswscanf, vswscanf)
|
||||
diff --git a/libio/libioP.h b/libio/libioP.h
|
||||
index 50570f89de5a7010..76fd7853dc087bf9 100644
|
||||
--- a/libio/libioP.h
|
||||
+++ b/libio/libioP.h
|
||||
@@ -594,6 +594,7 @@ extern FILE* _IO_new_file_fopen (FILE *, const char *, const char *,
|
||||
int);
|
||||
extern void _IO_no_init (FILE *, int, int, struct _IO_wide_data *,
|
||||
const struct _IO_jump_t *) __THROW;
|
||||
+extern void _IO_wstrfile_fclose_stack (FILE *) attribute_hidden;
|
||||
extern void _IO_new_file_init_internal (struct _IO_FILE_plus *)
|
||||
__THROW attribute_hidden;
|
||||
extern FILE* _IO_new_file_setbuf (FILE *, char *, ssize_t);
|
||||
diff --git a/libio/swscanf.c b/libio/swscanf.c
|
||||
index 88a19144342cdc38..cb3795599c6f70c6 100644
|
||||
--- a/libio/swscanf.c
|
||||
+++ b/libio/swscanf.c
|
||||
@@ -37,7 +37,7 @@ __swscanf (const wchar_t *s, const wchar_t *format, ...)
|
||||
va_start (arg, format);
|
||||
done = __vfwscanf_internal (f, format, arg, 0);
|
||||
va_end (arg);
|
||||
-
|
||||
+ _IO_wstrfile_fclose_stack (f);
|
||||
return done;
|
||||
}
|
||||
ldbl_strong_alias (__swscanf, swscanf)
|
||||
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_swscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_swscanf.c
|
||||
index ef8c1317dcd7f5e5..96bf2ac3559186e7 100644
|
||||
--- a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_swscanf.c
|
||||
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_swscanf.c
|
||||
@@ -34,7 +34,7 @@ ___ieee128_isoc99_swscanf (const wchar_t *string, const wchar_t *format, ...)
|
||||
va_start (ap, format);
|
||||
done = __vfwscanf_internal (fp, format, ap, mode_flags);
|
||||
va_end (ap);
|
||||
-
|
||||
+ _IO_wstrfile_fclose_stack (fp);
|
||||
return done;
|
||||
}
|
||||
strong_alias (___ieee128_isoc99_swscanf, __isoc99_swscanfieee128)
|
||||
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vswscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vswscanf.c
|
||||
index f77bb64638a4717f..8fa10ee2e22e238f 100644
|
||||
--- a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vswscanf.c
|
||||
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vswscanf.c
|
||||
@@ -27,6 +27,8 @@ ___ieee128_isoc99_vswscanf (wchar_t *string, const wchar_t *format, va_list ap)
|
||||
struct _IO_wide_data wd;
|
||||
FILE *fp = _IO_strfile_readw (&sf, &wd, string);
|
||||
int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
|
||||
- return __vfwscanf_internal (fp, format, ap, mode_flags);
|
||||
+ int done = __vfwscanf_internal (fp, format, ap, mode_flags);
|
||||
+ _IO_wstrfile_fclose_stack (fp);
|
||||
+ return done;
|
||||
}
|
||||
strong_alias (___ieee128_isoc99_vswscanf, __isoc99_vswscanfieee128)
|
||||
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swscanf.c
|
||||
index 04ee5419200298b1..509eaa663d0a9a33 100644
|
||||
--- a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swscanf.c
|
||||
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swscanf.c
|
||||
@@ -34,7 +34,7 @@ ___ieee128_swscanf (const wchar_t *string, const wchar_t *format, ...)
|
||||
done = __vfwscanf_internal (fp, format, ap,
|
||||
SCANF_LDBL_USES_FLOAT128);
|
||||
va_end (ap);
|
||||
-
|
||||
+ _IO_wstrfile_fclose_stack (fp);
|
||||
return done;
|
||||
}
|
||||
strong_alias (___ieee128_swscanf, __swscanfieee128)
|
||||
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswscanf.c
|
||||
index 7aebc5f1c12939b6..18aa6deaacdde682 100644
|
||||
--- a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswscanf.c
|
||||
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswscanf.c
|
||||
@@ -27,6 +27,8 @@ ___ieee128_vswscanf (const wchar_t *string, const wchar_t *format,
|
||||
_IO_strfile sf;
|
||||
struct _IO_wide_data wd;
|
||||
FILE *fp = _IO_strfile_readw (&sf, &wd, string);
|
||||
- return __vfwscanf_internal (fp, format, ap, SCANF_LDBL_USES_FLOAT128);
|
||||
+ int done = __vfwscanf_internal (fp, format, ap, SCANF_LDBL_USES_FLOAT128);
|
||||
+ _IO_wstrfile_fclose_stack (fp);
|
||||
+ return done;
|
||||
}
|
||||
strong_alias (___ieee128_vswscanf, __vswscanfieee128)
|
||||
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
|
||||
index a6c5c49ecb151bf5..81d53a4cf30acb89 100644
|
||||
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
|
||||
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
|
||||
@@ -388,7 +388,9 @@ __nldbl_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
|
||||
struct _IO_wide_data wd;
|
||||
FILE *f = _IO_strfile_readw (&sf, &wd, s);
|
||||
|
||||
- return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
|
||||
+ int ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
|
||||
+ _IO_wstrfile_fclose_stack (f);
|
||||
+ return ret;
|
||||
}
|
||||
libc_hidden_def (__nldbl_vswscanf)
|
||||
|
||||
@@ -952,7 +954,9 @@ __nldbl___isoc99_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
|
||||
struct _IO_wide_data wd;
|
||||
FILE *f = _IO_strfile_readw (&sf, &wd, s);
|
||||
|
||||
- return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
|
||||
+ int ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
|
||||
+ _IO_wstrfile_fclose_stack (f);
|
||||
+ return ret;
|
||||
}
|
||||
libc_hidden_def (__nldbl___isoc99_vswscanf)
|
||||
|
||||
diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
|
||||
index bb6d8f2035d8e4a4..3fda1f7be695b31e 100644
|
||||
--- a/wcsmbs/isoc99_swscanf.c
|
||||
+++ b/wcsmbs/isoc99_swscanf.c
|
||||
@@ -32,6 +32,6 @@ __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
|
||||
va_start (arg, format);
|
||||
done = __vfwscanf_internal (f, format, arg, SCANF_ISOC99_A);
|
||||
va_end (arg);
|
||||
-
|
||||
+ _IO_wstrfile_fclose_stack (f);
|
||||
return done;
|
||||
}
|
||||
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
|
||||
index 3cd0a28c21ffa36f..1df90438416d3bb7 100644
|
||||
--- a/wcsmbs/isoc99_vswscanf.c
|
||||
+++ b/wcsmbs/isoc99_vswscanf.c
|
||||
@@ -33,6 +33,8 @@ __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
|
||||
_IO_strfile sf;
|
||||
struct _IO_wide_data wd;
|
||||
FILE *f = _IO_strfile_readw (&sf, &wd, string);
|
||||
- return __vfwscanf_internal (f, format, args, SCANF_ISOC99_A);
|
||||
+ int done = __vfwscanf_internal (f, format, args, SCANF_ISOC99_A);
|
||||
+ _IO_wstrfile_fclose_stack (f);
|
||||
+ return done;
|
||||
}
|
||||
libc_hidden_def (__isoc99_vswscanf)
|
||||
57
SOURCES/glibc-RHEL-145156-2.patch
Normal file
57
SOURCES/glibc-RHEL-145156-2.patch
Normal file
@ -0,0 +1,57 @@
|
||||
libio: Fix gconv module reference counter overflow in vswprintf
|
||||
|
||||
The vswprintf family of functions (swprintf, vswprintf and their
|
||||
fortified/ldbl-compat wrappers) creates a wide-oriented FILE stream
|
||||
on the stack via _IO_no_init with _IO_wstrn_jumps, then calls
|
||||
_IO_fwide which clones the gconv transformation steps via
|
||||
__wcsmbs_clone_conv, incrementing the __counter reference counter.
|
||||
|
||||
Because the FILE is stack-allocated, fclose is never called, and the
|
||||
counter is never decremented. In a long-running process calling
|
||||
swprintf repeatedly with a non-builtin locale (e.g. en_US.UTF-8),
|
||||
the counter eventually overflows, triggering a fatal abort.
|
||||
|
||||
This is the same class of bug fixed upstream for swscanf in commit
|
||||
0981c03c2752b5f12ede24e6e696d5a29f7c6396. Upstream resolved the
|
||||
swprintf path architecturally by reworking the printf subsystem to
|
||||
use struct __wprintf_buffer instead of FILE * (commit 118816de3383),
|
||||
eliminating the _IO_fwide call entirely. That rework is too large
|
||||
to backport to glibc 2.34.
|
||||
|
||||
Instead, apply the same pattern as the swscanf fix: call
|
||||
_IO_wstrfile_fclose_stack after __vfwprintf_internal returns to
|
||||
release the gconv steps before the stack FILE goes out of scope.
|
||||
All ldbl-compat wrappers (ieee128, nldbl) call __vswprintf_internal,
|
||||
so they are covered by this single change.
|
||||
|
||||
Note: _IO_wstrfile_fclose_stack calls _IO_FINISH which invokes
|
||||
_IO_wstr_finish, and that NULLs out _IO_buf_base. Therefore the
|
||||
cleanup must happen after the overflow check (which compares
|
||||
_IO_buf_base against overflow_buf) and after string termination
|
||||
(which dereferences _IO_write_ptr).
|
||||
|
||||
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
|
||||
index b7036f1480733ac6..accbb8516f860680 100644
|
||||
--- a/libio/vswprintf.c
|
||||
+++ b/libio/vswprintf.c
|
||||
@@ -111,13 +111,17 @@ __vswprintf_internal (wchar_t *string, size_t maxlen, const wchar_t *format,
|
||||
ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, mode_flags);
|
||||
|
||||
if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
|
||||
- /* ISO C99 requires swprintf/vswprintf to return an error if the
|
||||
- output does not fit in the provided buffer. */
|
||||
- return -1;
|
||||
+ {
|
||||
+ /* ISO C99 requires swprintf/vswprintf to return an error if the
|
||||
+ output does not fit in the provided buffer. */
|
||||
+ _IO_wstrfile_fclose_stack ((FILE *) &sf.f._sbf);
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
/* Terminate the string. */
|
||||
*sf.f._sbf._f._wide_data->_IO_write_ptr = '\0';
|
||||
|
||||
+ _IO_wstrfile_fclose_stack ((FILE *) &sf.f._sbf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
123
SOURCES/glibc-RHEL-145156-3.patch
Normal file
123
SOURCES/glibc-RHEL-145156-3.patch
Normal file
@ -0,0 +1,123 @@
|
||||
commit 1cc165baed20b6589ef2f2c8c0e0415139bbb151
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
Date: Wed Apr 29 13:26:38 2026 +0200
|
||||
|
||||
test: Add gconv refcount leak test for swscanf
|
||||
|
||||
Add a new internal test, `tst-wcsmbs-clone-overflow`, to verify correct
|
||||
gconv module reference counting. The Makefile is updated to include this
|
||||
test in the `tests-internal` list and ensure it runs with generated locales.
|
||||
|
||||
This test specifically checks that the `__counter` for `gconv_fcts->towc`
|
||||
does not leak references when `swscanf` is used with a stack-allocated
|
||||
wide character stream. It ensures that `_IO_wstrfile_fclose_stack`
|
||||
properly decrements the module reference counter, preventing a module
|
||||
from staying loaded indefinitely due to unreleased references.
|
||||
|
||||
Assisted-by: LLM
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
wcsmbs/Makefile
|
||||
(test-c8rtomb, test-mbrtoc8, tst-wscanf-to_inpunct not present
|
||||
downstream)
|
||||
wcsmbs/tst-wcsmbs-clone-overflow.c
|
||||
(struct lc_ctype_data not present downstream; use
|
||||
loc->private.ctype directly instead)
|
||||
|
||||
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
|
||||
index 0e5fe909a83c7a13..f74b06d9749eaa02 100644
|
||||
--- a/wcsmbs/Makefile
|
||||
+++ b/wcsmbs/Makefile
|
||||
@@ -59,6 +59,12 @@ tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \
|
||||
# This test runs for a long time.
|
||||
xtests += test-wcsncmp-nonarray
|
||||
|
||||
+tests-internal += \
|
||||
+ tst-wcsmbs-clone-overflow
|
||||
+
|
||||
+tests-static += \
|
||||
+ tst-wcsmbs-clone-overflow
|
||||
+
|
||||
|
||||
include ../Rules
|
||||
|
||||
@@ -77,6 +83,7 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales)
|
||||
$(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
|
||||
$(objpfx)tst-c16-surrogate.out: $(gen-locales)
|
||||
$(objpfx)tst-c32-state.out: $(gen-locales)
|
||||
+$(objpfx)tst-wcsmbs-clone-overflow.out: $(gen-locales)
|
||||
endif
|
||||
|
||||
$(objpfx)tst-wcstod-round: $(libm)
|
||||
diff --git a/wcsmbs/tst-wcsmbs-clone-overflow.c b/wcsmbs/tst-wcsmbs-clone-overflow.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..412e1c54085c68d5
|
||||
--- /dev/null
|
||||
+++ b/wcsmbs/tst-wcsmbs-clone-overflow.c
|
||||
@@ -0,0 +1,65 @@
|
||||
+/* Test for gconv module reference counter leak.
|
||||
+ 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 <locale.h>
|
||||
+#include <stdio.h>
|
||||
+#include <wchar.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+/* Internal headers for accessing the gconv structures. */
|
||||
+#include <locale/localeinfo.h>
|
||||
+#include <iconv/gconv_int.h>
|
||||
+#include <wcsmbs/wcsmbsload.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ if (setlocale (LC_ALL, "de_DE.ISO-8859-1") == NULL)
|
||||
+ FAIL_EXIT1 ("setlocale failed, check if de_DE.ISO-8859-1 is generated");
|
||||
+
|
||||
+ wchar_t buf[32] = L"123";
|
||||
+ int j;
|
||||
+
|
||||
+ /* First iteration initializes the gconv functions internally. */
|
||||
+ if (swscanf (buf, L"%d", &j) < 1)
|
||||
+ FAIL_EXIT1 ("swscanf failed");
|
||||
+
|
||||
+ /* Retrieve the current gconv_fcts from the LC_CTYPE locale data. */
|
||||
+ struct __locale_data *loc = _NL_CURRENT_DATA (LC_CTYPE);
|
||||
+ const struct gconv_fcts *fcts = loc->private.ctype;
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (fcts != NULL);
|
||||
+ TEST_VERIFY_EXIT (fcts->towc != NULL);
|
||||
+
|
||||
+ /* Capture the reference counter. */
|
||||
+ int initial_counter = fcts->towc->__counter;
|
||||
+
|
||||
+ /* Perform a second iteration of swscanf. If the stack-allocated FILE
|
||||
+ leaks the gconv reference, the counter will increment. */
|
||||
+ if (swscanf (buf, L"%d", &j) < 1)
|
||||
+ FAIL_EXIT1 ("swscanf failed");
|
||||
+
|
||||
+ /* The counter should be unchanged, as _IO_wstrfile_fclose_stack should
|
||||
+ have decremented it correctly. */
|
||||
+ TEST_COMPARE (fcts->towc->__counter, initial_counter);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
146
SOURCES/glibc-RHEL-145156-4.patch
Normal file
146
SOURCES/glibc-RHEL-145156-4.patch
Normal file
@ -0,0 +1,146 @@
|
||||
commit 9ef37798fa7dc2b10926742e3f3bd304a17a9ad1
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
Date: Tue May 26 13:29:57 2026 +0200
|
||||
|
||||
test: Fix and stabilize tst-wcsmbs-clone-overflow test
|
||||
|
||||
The test tst-wcsmbs-clone-overflow was initially added to tests-static.
|
||||
However, this causes the test to be unstable because gconv modules
|
||||
dynamically load libc.so. Any discrepancy between the statically linked
|
||||
version and the dynamically loaded one can lead to a crash.
|
||||
|
||||
By removing the test from tests-static, it relies on dynamic linking,
|
||||
safely bypassing the dlopen crash. Since the test is now dynamically
|
||||
linked, it cannot use the internal thread-local symbol
|
||||
_NL_CURRENT_DATA(LC_CTYPE) because _nl_current_LC_CTYPE is hidden in
|
||||
libc.so, leading to undefined references. Thus, the test now uses
|
||||
newlocale and uselocale, safely extracting the locale data from the
|
||||
returned locale_t object.
|
||||
|
||||
Furthermore, using newlocale requires the gconv-modules configuration to
|
||||
be built and available so that the ISO8859-1.so module can be
|
||||
dynamically loaded. Otherwise, glibc falls back to the built-in C locale
|
||||
conversions, leaving __shlib_handle as NULL and silently bypassing the
|
||||
reference counter increment.
|
||||
A new Makefile fragment, gen-gconv-modules.mk, is introduced to ensure
|
||||
the gconv-modules are built before the test runs, and an explicit check
|
||||
for __shlib_handle != NULL is added to the test.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
wcsmbs/Makefile
|
||||
(test-c8rtomb, test-mbrtoc8, tst-wscanf-to_inpunct not present
|
||||
downstream)
|
||||
wcsmbs/tst-wcsmbs-clone-overflow.c
|
||||
(struct lc_ctype_data not present downstream; use
|
||||
loc->private.ctype directly instead)
|
||||
|
||||
diff --git a/gen-gconv-modules.mk b/gen-gconv-modules.mk
|
||||
new file mode 100644
|
||||
index 0000000000000000..046721a7a7bf460c
|
||||
--- /dev/null
|
||||
+++ b/gen-gconv-modules.mk
|
||||
@@ -0,0 +1,6 @@
|
||||
+# defines target $(gen-gconv-modules) that ensures gconv-modules are available
|
||||
+
|
||||
+gen-gconv-modules := $(common-objpfx)iconvdata/gconv-modules
|
||||
+
|
||||
+$(gen-gconv-modules):
|
||||
+ $(MAKE) -C ../iconvdata subdir=iconvdata $@
|
||||
diff --git a/localedata/Makefile b/localedata/Makefile
|
||||
index 56de42e9262decd3..0cc02c430d96d804 100644
|
||||
--- a/localedata/Makefile
|
||||
+++ b/localedata/Makefile
|
||||
@@ -204,7 +204,7 @@ install-others := $(addprefix $(inst_i18ndir)/, \
|
||||
$(locales))
|
||||
endif
|
||||
|
||||
-tests: $(objdir)/iconvdata/gconv-modules
|
||||
+tests: $(gen-gconv-modules)
|
||||
|
||||
tests-static += tst-langinfo-newlocale-static tst-langinfo-setlocale-static
|
||||
|
||||
@@ -315,6 +315,7 @@ LOCALES := \
|
||||
$(NULL)
|
||||
|
||||
include ../gen-locales.mk
|
||||
+include ../gen-gconv-modules.mk
|
||||
|
||||
$(objpfx)tst-iconv-math-trans.out: $(gen-locales)
|
||||
endif
|
||||
@@ -486,6 +487,3 @@ $(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out
|
||||
|
||||
bug-setlocale1-ENV-only = LOCPATH=$(objpfx) LC_CTYPE=de_DE.UTF-8
|
||||
bug-setlocale1-static-ENV-only = $(bug-setlocale1-ENV-only)
|
||||
-
|
||||
-$(objdir)/iconvdata/gconv-modules:
|
||||
- $(MAKE) -C ../iconvdata subdir=iconvdata $@
|
||||
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
|
||||
index f74b06d9749eaa02..bb03d92576700a99 100644
|
||||
--- a/wcsmbs/Makefile
|
||||
+++ b/wcsmbs/Makefile
|
||||
@@ -62,16 +62,13 @@ xtests += test-wcsncmp-nonarray
|
||||
tests-internal += \
|
||||
tst-wcsmbs-clone-overflow
|
||||
|
||||
-tests-static += \
|
||||
- tst-wcsmbs-clone-overflow
|
||||
-
|
||||
-
|
||||
include ../Rules
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
LOCALES := de_DE.ISO-8859-1 de_DE.UTF-8 en_US.ANSI_X3.4-1968 hr_HR.ISO-8859-2 \
|
||||
ja_JP.EUC-JP zh_TW.EUC-TW tr_TR.UTF-8 tr_TR.ISO-8859-9
|
||||
include ../gen-locales.mk
|
||||
+include ../gen-gconv-modules.mk
|
||||
|
||||
$(objpfx)tst-btowc.out: $(gen-locales)
|
||||
$(objpfx)tst-c16c32-1.out: $(gen-locales)
|
||||
@@ -83,7 +80,7 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales)
|
||||
$(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
|
||||
$(objpfx)tst-c16-surrogate.out: $(gen-locales)
|
||||
$(objpfx)tst-c32-state.out: $(gen-locales)
|
||||
-$(objpfx)tst-wcsmbs-clone-overflow.out: $(gen-locales)
|
||||
+$(objpfx)tst-wcsmbs-clone-overflow.out: $(gen-locales) $(gen-gconv-modules)
|
||||
endif
|
||||
|
||||
$(objpfx)tst-wcstod-round: $(libm)
|
||||
diff --git a/wcsmbs/tst-wcsmbs-clone-overflow.c b/wcsmbs/tst-wcsmbs-clone-overflow.c
|
||||
index 412e1c54085c68d5..6d8b643f48aa7775 100644
|
||||
--- a/wcsmbs/tst-wcsmbs-clone-overflow.c
|
||||
+++ b/wcsmbs/tst-wcsmbs-clone-overflow.c
|
||||
@@ -30,8 +30,11 @@
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
- if (setlocale (LC_ALL, "de_DE.ISO-8859-1") == NULL)
|
||||
- FAIL_EXIT1 ("setlocale failed, check if de_DE.ISO-8859-1 is generated");
|
||||
+ locale_t loc_obj = newlocale (LC_ALL_MASK, "de_DE.ISO-8859-1", NULL);
|
||||
+ if (loc_obj == NULL)
|
||||
+ FAIL_EXIT1 ("newlocale failed, check if de_DE.ISO-8859-1 is generated");
|
||||
+
|
||||
+ uselocale (loc_obj);
|
||||
|
||||
wchar_t buf[32] = L"123";
|
||||
int j;
|
||||
@@ -41,7 +44,7 @@ do_test (void)
|
||||
FAIL_EXIT1 ("swscanf failed");
|
||||
|
||||
/* Retrieve the current gconv_fcts from the LC_CTYPE locale data. */
|
||||
- struct __locale_data *loc = _NL_CURRENT_DATA (LC_CTYPE);
|
||||
+ struct __locale_data *loc = loc_obj->__locales[LC_CTYPE];
|
||||
const struct gconv_fcts *fcts = loc->private.ctype;
|
||||
|
||||
TEST_VERIFY_EXIT (fcts != NULL);
|
||||
@@ -50,6 +53,9 @@ do_test (void)
|
||||
/* Capture the reference counter. */
|
||||
int initial_counter = fcts->towc->__counter;
|
||||
|
||||
+ if (fcts->towc->__shlib_handle == NULL)
|
||||
+ FAIL_EXIT1 ("__shlib_handle is NULL!");
|
||||
+
|
||||
/* Perform a second iteration of swscanf. If the stack-allocated FILE
|
||||
leaks the gconv reference, the counter will increment. */
|
||||
if (swscanf (buf, L"%d", &j) < 1)
|
||||
111
SOURCES/glibc-RHEL-145156-5.patch
Normal file
111
SOURCES/glibc-RHEL-145156-5.patch
Normal file
@ -0,0 +1,111 @@
|
||||
test: Add gconv refcount leak test for swprintf
|
||||
|
||||
Add a new internal test, tst-wcsmbs-clone-overflow-swprintf, to verify
|
||||
correct gconv module reference counting for the swprintf path.
|
||||
|
||||
This is the swprintf counterpart to tst-wcsmbs-clone-overflow (which
|
||||
tests swscanf). The vswprintf/swprintf family creates a wide-oriented
|
||||
stack-allocated FILE stream via _IO_no_init and _IO_fwide, which clones
|
||||
the gconv transformation steps. This test verifies that the __counter
|
||||
for gconv_fcts->towc does not leak references after swprintf returns,
|
||||
confirming that _IO_wstrfile_fclose_stack properly releases the gconv
|
||||
steps.
|
||||
|
||||
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
|
||||
index bb03d92576700a99..252630457146de35 100644
|
||||
--- a/wcsmbs/Makefile
|
||||
+++ b/wcsmbs/Makefile
|
||||
@@ -60,7 +60,8 @@ tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \
|
||||
xtests += test-wcsncmp-nonarray
|
||||
|
||||
tests-internal += \
|
||||
- tst-wcsmbs-clone-overflow
|
||||
+ tst-wcsmbs-clone-overflow \
|
||||
+ tst-wcsmbs-clone-overflow-swprintf
|
||||
|
||||
include ../Rules
|
||||
|
||||
@@ -81,6 +82,7 @@ $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
|
||||
$(objpfx)tst-c16-surrogate.out: $(gen-locales)
|
||||
$(objpfx)tst-c32-state.out: $(gen-locales)
|
||||
$(objpfx)tst-wcsmbs-clone-overflow.out: $(gen-locales) $(gen-gconv-modules)
|
||||
+$(objpfx)tst-wcsmbs-clone-overflow-swprintf.out: $(gen-locales) $(gen-gconv-modules)
|
||||
endif
|
||||
|
||||
$(objpfx)tst-wcstod-round: $(libm)
|
||||
diff --git a/wcsmbs/tst-wcsmbs-clone-overflow-swprintf.c b/wcsmbs/tst-wcsmbs-clone-overflow-swprintf.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..daccb08e6352a943
|
||||
--- /dev/null
|
||||
+++ b/wcsmbs/tst-wcsmbs-clone-overflow-swprintf.c
|
||||
@@ -0,0 +1,70 @@
|
||||
+/* Test for gconv module reference counter leak in swprintf.
|
||||
+ 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 <locale.h>
|
||||
+#include <stdio.h>
|
||||
+#include <wchar.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+/* Internal headers for accessing the gconv structures. */
|
||||
+#include <locale/localeinfo.h>
|
||||
+#include <iconv/gconv_int.h>
|
||||
+#include <wcsmbs/wcsmbsload.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ locale_t loc_obj = newlocale (LC_ALL_MASK, "de_DE.ISO-8859-1", NULL);
|
||||
+ if (loc_obj == NULL)
|
||||
+ FAIL_EXIT1 ("newlocale failed, check if de_DE.ISO-8859-1 is generated");
|
||||
+
|
||||
+ uselocale (loc_obj);
|
||||
+
|
||||
+ wchar_t buf[32];
|
||||
+
|
||||
+ /* First iteration initializes the gconv functions internally. */
|
||||
+ if (swprintf (buf, sizeof (buf) / sizeof (buf[0]), L"%d", 123) < 0)
|
||||
+ FAIL_EXIT1 ("swprintf failed");
|
||||
+
|
||||
+ /* Retrieve the current gconv_fcts from the LC_CTYPE locale data. */
|
||||
+ struct __locale_data *loc = loc_obj->__locales[LC_CTYPE];
|
||||
+ const struct gconv_fcts *fcts = loc->private.ctype;
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (fcts != NULL);
|
||||
+ TEST_VERIFY_EXIT (fcts->towc != NULL);
|
||||
+
|
||||
+ /* Capture the reference counter. */
|
||||
+ int initial_counter = fcts->towc->__counter;
|
||||
+
|
||||
+ if (fcts->towc->__shlib_handle == NULL)
|
||||
+ FAIL_EXIT1 ("__shlib_handle is NULL!");
|
||||
+
|
||||
+ /* Perform a second iteration of swprintf. If the stack-allocated FILE
|
||||
+ leaks the gconv reference, the counter will increment. */
|
||||
+ if (swprintf (buf, sizeof (buf) / sizeof (buf[0]), L"%d", 456) < 0)
|
||||
+ FAIL_EXIT1 ("swprintf failed");
|
||||
+
|
||||
+ /* The counter should be unchanged, as _IO_wstrfile_fclose_stack should
|
||||
+ have decremented it correctly. */
|
||||
+ TEST_COMPARE (fcts->towc->__counter, initial_counter);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
126
SOURCES/glibc-RHEL-172710-1.patch
Normal file
126
SOURCES/glibc-RHEL-172710-1.patch
Normal file
@ -0,0 +1,126 @@
|
||||
commit 839898777226a3ed88c0859f25ffe712519b4ead
|
||||
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>
|
||||
|
||||
Conflicts:
|
||||
stdio-common/Makefile
|
||||
(usual test differences)
|
||||
|
||||
diff -Nrup a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
--- a/stdio-common/Makefile 2026-06-16 08:24:01.348860456 -0400
|
||||
+++ b/stdio-common/Makefile 2026-06-16 08:18:22.791126117 -0400
|
||||
@@ -290,6 +290,7 @@ tests := \
|
||||
tst-vfprintf-mbs-prec \
|
||||
tst-vfprintf-user-type \
|
||||
tst-vfprintf-width-prec-alloc \
|
||||
+ tst-vfscanf-bz34008 \
|
||||
tst-wc-printf \
|
||||
tstdiomisc \
|
||||
tstgetln \
|
||||
@@ -441,6 +442,9 @@ tst-printf-bz18872-ENV = MALLOC_TRACE=$(
|
||||
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 59fc8208aa..3d11ac261e 100644
|
||||
--- a/stdio-common/vfscanf-internal.c
|
||||
+++ b/stdio-common/vfscanf-internal.c
|
||||
@@ -855,8 +855,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)
|
||||
@@ -929,7 +928,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));
|
||||
@@ -984,7 +983,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));
|
||||
80
SOURCES/glibc-RHEL-172710-2.patch
Normal file
80
SOURCES/glibc-RHEL-172710-2.patch
Normal file
@ -0,0 +1,80 @@
|
||||
commit b866ef29773b22a1343ff9084374775114350b78
|
||||
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||
Date: Wed May 27 12:57:10 2026 -0400
|
||||
|
||||
support: Implement 'xfmemopen' for seamless 'fmemopen' use
|
||||
|
||||
Add 'xfmemopen' wrapper for seamless 'fmemopen' use in tests, following
|
||||
'xfopen', 'xfclose', etc., and providing a standardized error reporting
|
||||
facility.
|
||||
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
(cherry picked from commit fe709cc24578ecfd2ff5b07e10e3829fcb55075b)
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
support/Makefile
|
||||
(usual test differences)
|
||||
support/xstdio.h
|
||||
(adjust for downstream context difference)
|
||||
|
||||
diff -Nrup a/support/Makefile b/support/Makefile
|
||||
--- a/support/Makefile 2026-06-16 10:34:13.241874132 -0400
|
||||
+++ b/support/Makefile 2026-06-16 10:37:06.085172353 -0400
|
||||
@@ -135,6 +135,7 @@ libsupport-routines = \
|
||||
xfchmod \
|
||||
xfclose \
|
||||
xfdopendir \
|
||||
+ xfmemopen \
|
||||
xfopen \
|
||||
xfork \
|
||||
xfread \
|
||||
diff --git a/support/xfmemopen.c b/support/xfmemopen.c
|
||||
new file mode 100644
|
||||
index 0000000000..f1dbc72c67
|
||||
--- /dev/null
|
||||
+++ b/support/xfmemopen.c
|
||||
@@ -0,0 +1,31 @@
|
||||
+/* fmemopen with error checking.
|
||||
+ Copyright (C) 2025 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 <support/xstdio.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+FILE *
|
||||
+xfmemopen (void *mem, size_t len, const char *mode)
|
||||
+{
|
||||
+ FILE *fp = fmemopen (mem, len, mode);
|
||||
+ if (fp == NULL)
|
||||
+ FAIL_EXIT1 ("fmemopen (mode \"%s\"): %m", mode);
|
||||
+ return fp;
|
||||
+}
|
||||
diff -Nrup a/support/xstdio.h b/support/xstdio.h
|
||||
--- a/support/xstdio.h 2026-06-16 10:34:10.450856660 -0400
|
||||
+++ b/support/xstdio.h 2026-06-16 10:39:05.792825780 -0400
|
||||
@@ -26,6 +26,7 @@ __BEGIN_DECLS
|
||||
|
||||
FILE *xfopen (const char *path, const char *mode);
|
||||
void xfclose (FILE *);
|
||||
+FILE *xfmemopen (void *mem, size_t len, const char *mode);
|
||||
void xfread (void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
|
||||
/* Read a line from FP, using getline. *BUFFER must be NULL, or a
|
||||
457
SOURCES/glibc-RHEL-172710-3.patch
Normal file
457
SOURCES/glibc-RHEL-172710-3.patch
Normal file
@ -0,0 +1,457 @@
|
||||
commit 97926e9017f3faeaacce9337f1288460f5e6ec7d
|
||||
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||
Date: Wed May 27 12:57:10 2026 -0400
|
||||
|
||||
stdio-common: Reject insufficient character data in scanf [BZ #12701]
|
||||
|
||||
Reject invalid formatted scanf character data with the 'c' conversion
|
||||
where there is not enough input available to satisfy the field width
|
||||
requested. It is required by ISO C that this conversion matches a
|
||||
sequence of characters of exactly the number specified by the field
|
||||
width and it is also already documented as such in our own manual:
|
||||
|
||||
"It reads precisely the next N characters, and fails if it cannot get
|
||||
that many."
|
||||
|
||||
Currently a matching success is instead incorrectly produced where the
|
||||
EOF condition is encountered before the required number of characters
|
||||
has been retrieved, and the characters actually obtained are stored in
|
||||
the buffer provided.
|
||||
|
||||
Add test cases accordingly and remove placeholders from 'c' conversion
|
||||
input data for the existing scanf tests.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
[This is a modified version of commit 2b16c76609, which tests for the
|
||||
old behavior and only includes the test cases, for older branches
|
||||
and downstream backports - DJ]
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
localedata/Makefile
|
||||
stdio-common/Makefile
|
||||
(usual test differences)
|
||||
|
||||
diff -Nrup a/localedata/Makefile b/localedata/Makefile
|
||||
--- a/localedata/Makefile 2026-06-16 09:15:19.295653341 -0400
|
||||
+++ b/localedata/Makefile 2026-06-16 09:11:51.111414458 -0400
|
||||
@@ -160,6 +160,7 @@ tests = \
|
||||
bug-iconv-trans \
|
||||
bug-setlocale1 \
|
||||
bug-usesetlocale \
|
||||
+ tst-bz12701-lc \
|
||||
tst-c-utf8-consistency \
|
||||
tst-digits \
|
||||
tst-iconv-math-trans \
|
||||
diff --git a/localedata/tst-bz12701-lc.c b/localedata/tst-bz12701-lc.c
|
||||
new file mode 100644
|
||||
index 0000000000..23c2ab7d2a
|
||||
--- /dev/null
|
||||
+++ b/localedata/tst-bz12701-lc.c
|
||||
@@ -0,0 +1,218 @@
|
||||
+/* Verify scanf field width handling with the 'lc' conversion (BZ #12701).
|
||||
+ Copyright (C) 2025-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 <locale.h>
|
||||
+#include <stddef.h>
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
+#include <wchar.h>
|
||||
+
|
||||
+#include <libc-diag.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/next_to_fault.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+/* Compare character-wise the initial part of the wide character object
|
||||
+ pointed to by WS corresponding to wide characters obtained by the
|
||||
+ conversion of first N bytes of the multibyte character object pointed
|
||||
+ to by S. */
|
||||
+
|
||||
+static int
|
||||
+tst_bz12701_lc_memcmp (const wchar_t *ds, const char *s, size_t n)
|
||||
+{
|
||||
+ size_t nc = mbsnrtowcs (NULL, &s, n, 0, NULL);
|
||||
+
|
||||
+ struct support_next_to_fault ntf;
|
||||
+ ntf = support_next_to_fault_allocate (nc * sizeof (wchar_t));
|
||||
+ wchar_t *ss = (wchar_t *) ntf.buffer;
|
||||
+
|
||||
+ mbsnrtowcs (ss, &s, n, nc, NULL);
|
||||
+ int r = wmemcmp (ds, ss, nc);
|
||||
+
|
||||
+ support_next_to_fault_free (&ntf);
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+/* Verify various aspects of field width handling, including the data
|
||||
+ obtained, the number of bytes consumed, and the stream position. */
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ if (setlocale (LC_ALL, "pl_PL.UTF-8") == NULL)
|
||||
+ FAIL_EXIT1 ("setlocale (LC_ALL, \"pl_PL.UTF-8\")");
|
||||
+
|
||||
+ /* Part of a tongue-twister in Polish, which says:
|
||||
+ "On a rainy morning cuckoos and warblers, rather than starting
|
||||
+ on earthworms, stuffed themselves fasted with the flesh of cress." */
|
||||
+ static const char s[126] = "Dżdżystym rankiem gżegżółki i piegże, "
|
||||
+ "zamiast wziąć się za dżdżownice, "
|
||||
+ "nażarły się na czczo miąższu rzeżuchy";
|
||||
+
|
||||
+ const char *sp = s;
|
||||
+ size_t nc;
|
||||
+ TEST_VERIFY_EXIT ((nc = mbsnrtowcs (NULL, &sp, sizeof (s), 0, NULL)) == 108);
|
||||
+
|
||||
+ struct support_next_to_fault ntfo, ntfi;
|
||||
+ ntfo = support_next_to_fault_allocate (nc * sizeof (wchar_t));
|
||||
+ ntfi = support_next_to_fault_allocate (sizeof (s));
|
||||
+ wchar_t *e = (wchar_t *) ntfo.buffer + nc;
|
||||
+ char *b = ntfi.buffer;
|
||||
+
|
||||
+ wchar_t *c;
|
||||
+ FILE *f;
|
||||
+ int ic;
|
||||
+ int n;
|
||||
+ int i;
|
||||
+
|
||||
+ memcpy (ntfi.buffer, s, sizeof (s));
|
||||
+
|
||||
+ ic = i = 0;
|
||||
+ f = xfmemopen (b, sizeof (s), "r");
|
||||
+
|
||||
+ c = e - 1;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ /* Avoid: "warning: zero width in gnu_scanf format [-Werror=format=]". */
|
||||
+ DIAG_PUSH_NEEDS_COMMENT;
|
||||
+ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wformat");
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%0lc%n", c, &n) == 1);
|
||||
+ DIAG_POP_NEEDS_COMMENT;
|
||||
+ TEST_VERIFY_EXIT (n == 1);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 1;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 1;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 2);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 1;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 1;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%1lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 1);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 1;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 2;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 3);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 2;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 4;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%4lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 4);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 4;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 8;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%8lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 8);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 8;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 16;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%16lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 20);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 16;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 32;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%32lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 38);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 32;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - (nc - ic);
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_COMPARE (fscanf (f, "%64lc%n", c, &n), 1);
|
||||
+ TEST_COMPARE (n , 49);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, sizeof (s) - i) == 0);
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == sizeof (s));
|
||||
+ TEST_VERIFY_EXIT (feof (f) != 0);
|
||||
+
|
||||
+ xfclose (f);
|
||||
+
|
||||
+ ic = i = 0;
|
||||
+ f = xfmemopen (b, 3, "r");
|
||||
+
|
||||
+ c = e - 2;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 3);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 2;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - (nc - ic);
|
||||
+ TEST_VERIFY_EXIT (feof (f) == 0);
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2lc%n", c, &n) == EOF);
|
||||
+ TEST_VERIFY_EXIT (n == 3);
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == 3);
|
||||
+ TEST_VERIFY_EXIT (feof (f) != 0);
|
||||
+
|
||||
+ xfclose (f);
|
||||
+
|
||||
+ ic = i = 0;
|
||||
+ f = xfmemopen (b, 3, "r");
|
||||
+
|
||||
+ c = e - 1;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 1);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
|
||||
+ ic += 1;
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - (nc - ic);
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2lc%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 2);
|
||||
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, 3 - i) == 0);
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == 3);
|
||||
+ TEST_VERIFY_EXIT (feof (f) != 0);
|
||||
+
|
||||
+ xfclose (f);
|
||||
+
|
||||
+ support_next_to_fault_free (&ntfi);
|
||||
+ support_next_to_fault_free (&ntfo);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff -Nrup a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
--- a/stdio-common/Makefile 2026-06-16 09:15:19.320447732 -0400
|
||||
+++ b/stdio-common/Makefile 2026-06-16 09:14:09.814624522 -0400
|
||||
@@ -217,6 +217,7 @@ tests := \
|
||||
tllformat \
|
||||
tst-bz11319 \
|
||||
tst-bz11319-fortify2 \
|
||||
+ tst-bz12701-c \
|
||||
tst-cookie \
|
||||
tst-fclose-devzero \
|
||||
tst-fclose-offset \
|
||||
diff --git a/stdio-common/tst-bz12701-c.c b/stdio-common/tst-bz12701-c.c
|
||||
new file mode 100644
|
||||
index 0000000000..4f3616fbfd
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-bz12701-c.c
|
||||
@@ -0,0 +1,169 @@
|
||||
+/* Verify scanf field width handling with the 'c' conversion (BZ #12701).
|
||||
+ Copyright (C) 2025-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 <stdio.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <libc-diag.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/next_to_fault.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+/* Verify various aspects of field width handling, including the data
|
||||
+ obtained, the number of bytes consumed, and the stream position. */
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ static const char s[43] = "The quick brown fox jumps over the lazy dog";
|
||||
+ struct support_next_to_fault ntfo, ntfi;
|
||||
+ ntfo = support_next_to_fault_allocate (sizeof (s));
|
||||
+ ntfi = support_next_to_fault_allocate (sizeof (s));
|
||||
+ char *e = ntfo.buffer + sizeof (s);
|
||||
+ char *b = ntfi.buffer;
|
||||
+
|
||||
+ char *c;
|
||||
+ FILE *f;
|
||||
+ int n;
|
||||
+ int i;
|
||||
+
|
||||
+ memcpy (ntfi.buffer, s, sizeof (s));
|
||||
+
|
||||
+ i = 0;
|
||||
+ f = xfmemopen (b, sizeof (s), "r");
|
||||
+
|
||||
+ c = e - 1;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ /* Avoid: "warning: zero width in gnu_scanf format [-Werror=format=]". */
|
||||
+ DIAG_PUSH_NEEDS_COMMENT;
|
||||
+ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wformat");
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%0c%n", c, &n) == 1);
|
||||
+ DIAG_POP_NEEDS_COMMENT;
|
||||
+ TEST_VERIFY_EXIT (n == 1);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 1;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 1);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 1;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%1c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 1);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 2;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 2);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 4;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%4c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 4);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 8;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%8c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 8);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 16;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%16c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 16);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - (sizeof (s) - i);
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%32c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 10);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, sizeof (s) - i) == 0);
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == sizeof (s));
|
||||
+ TEST_VERIFY_EXIT (feof (f) != 0);
|
||||
+
|
||||
+ xfclose (f);
|
||||
+
|
||||
+ i = 0;
|
||||
+ f = xfmemopen (b, 3, "r");
|
||||
+
|
||||
+ c = e - 1;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 1);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - 2;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 2);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - (3 - i);
|
||||
+ TEST_VERIFY_EXIT (feof (f) == 0);
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == EOF);
|
||||
+ TEST_VERIFY_EXIT (n == 2);
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (feof (f) != 0);
|
||||
+
|
||||
+ xfclose (f);
|
||||
+
|
||||
+ i = 0;
|
||||
+ f = xfmemopen (b, 3, "r");
|
||||
+
|
||||
+ c = e - 2;
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 2);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
|
||||
+ i += n;
|
||||
+
|
||||
+ c = e - (3 - i);
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == i);
|
||||
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == 1);
|
||||
+ TEST_VERIFY_EXIT (n == 1);
|
||||
+ TEST_VERIFY_EXIT (memcmp (c, s + i, 3 - i) == 0);
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (ftell (f) == 3);
|
||||
+ TEST_VERIFY_EXIT (feof (f) != 0);
|
||||
+
|
||||
+ xfclose (f);
|
||||
+
|
||||
+ support_next_to_fault_free (&ntfi);
|
||||
+ support_next_to_fault_free (&ntfo);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
193
SOURCES/glibc-RHEL-172710-4.patch
Normal file
193
SOURCES/glibc-RHEL-172710-4.patch
Normal file
@ -0,0 +1,193 @@
|
||||
commit 6cebb0b80fd783e442a8ad27c3f52cde52a9cac7
|
||||
Author: DJ Delorie <dj@redhat.com>
|
||||
Date: Wed May 27 12:57:10 2026 -0400
|
||||
|
||||
stdio-common: Allow partially-filled %mc buffers [BZ #12701]
|
||||
|
||||
This is a backwards-compatible alternative to the main solution to
|
||||
the %mc part of 12701. The allocated buffer is expanded to the
|
||||
requested size and NUL padded, but truncated reads are allowed.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
localedata/Makefile
|
||||
stdio-common/Makefile
|
||||
(usual test differences)
|
||||
|
||||
diff -Nrup a/localedata/Makefile b/localedata/Makefile
|
||||
--- a/localedata/Makefile 2026-06-16 10:00:37.802495527 -0400
|
||||
+++ b/localedata/Makefile 2026-06-16 09:59:09.766677507 -0400
|
||||
@@ -161,6 +161,7 @@ tests = \
|
||||
bug-setlocale1 \
|
||||
bug-usesetlocale \
|
||||
tst-bz12701-lc \
|
||||
+ tst-bz12701-lc2 \
|
||||
tst-c-utf8-consistency \
|
||||
tst-digits \
|
||||
tst-iconv-math-trans \
|
||||
diff --git a/localedata/tst-bz12701-lc2.c b/localedata/tst-bz12701-lc2.c
|
||||
new file mode 100644
|
||||
index 0000000000..b24e86df0b
|
||||
--- /dev/null
|
||||
+++ b/localedata/tst-bz12701-lc2.c
|
||||
@@ -0,0 +1,47 @@
|
||||
+/* Verify scanf memory handling with the 'c' conversion (BZ #12701).
|
||||
+ 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 <stdio.h>
|
||||
+#include <malloc.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <libc-diag.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/next_to_fault.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ wchar_t *c = NULL;
|
||||
+ int i;
|
||||
+
|
||||
+ TEST_VERIFY (sscanf ("1234", "%30mlc", &c) == 1);
|
||||
+
|
||||
+ TEST_VERIFY (c != NULL);
|
||||
+ TEST_COMPARE_BLOB (c, 5 * sizeof (wchar_t),
|
||||
+ L"1234\0", 5 * sizeof (wchar_t));
|
||||
+ for (i = 5; i < 30; i ++)
|
||||
+ TEST_VERIFY (c[i] == L'\0');
|
||||
+
|
||||
+ TEST_VERIFY (malloc_usable_size (c) >= 30 * sizeof(wchar_t));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff -Nrup a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
--- a/stdio-common/Makefile 2026-06-16 10:00:37.803143281 -0400
|
||||
+++ b/stdio-common/Makefile 2026-06-16 09:59:54.974421920 -0400
|
||||
@@ -218,6 +218,7 @@ tests := \
|
||||
tst-bz11319 \
|
||||
tst-bz11319-fortify2 \
|
||||
tst-bz12701-c \
|
||||
+ tst-bz12701-c2 \
|
||||
tst-cookie \
|
||||
tst-fclose-devzero \
|
||||
tst-fclose-offset \
|
||||
diff --git a/stdio-common/tst-bz12701-c2.c b/stdio-common/tst-bz12701-c2.c
|
||||
new file mode 100644
|
||||
index 0000000000..5f9ca7c592
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-bz12701-c2.c
|
||||
@@ -0,0 +1,46 @@
|
||||
+/* Verify scanf memory handling with the 'c' conversion (BZ #12701).
|
||||
+ 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 <stdio.h>
|
||||
+#include <malloc.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <libc-diag.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/next_to_fault.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ char *c = NULL;
|
||||
+ int i;
|
||||
+
|
||||
+ TEST_VERIFY (sscanf ("1234", "%30mc", &c) == 1);
|
||||
+
|
||||
+ TEST_VERIFY (c != NULL);
|
||||
+ TEST_COMPARE_BLOB (c, 5, "1234\0", 5);
|
||||
+ for (i = 5; i < 30; i ++)
|
||||
+ TEST_VERIFY (c[i] == '\0');
|
||||
+
|
||||
+ TEST_VERIFY (malloc_usable_size (c) >= 30);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
|
||||
index 17b5565d0f..90a1886951 100644
|
||||
--- a/stdio-common/vfscanf-internal.c
|
||||
+++ b/stdio-common/vfscanf-internal.c
|
||||
@@ -780,9 +780,9 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
conv_error (); \
|
||||
} while (0)
|
||||
#ifdef COMPILE_WSCANF
|
||||
- STRING_ARG (str, char, 100);
|
||||
+ STRING_ARG (str, char, (width > 0 ? width : 1));
|
||||
#else
|
||||
- STRING_ARG (str, char, (width > 1024 ? 1024 : width));
|
||||
+ STRING_ARG (str, char, (width > 0 ? width : 1));
|
||||
#endif
|
||||
|
||||
c = inchar ();
|
||||
@@ -891,6 +891,11 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
|
||||
if (!(flags & SUPPRESS))
|
||||
{
|
||||
+ /* If the buffer isn't completely filled, pad it with NULs. */
|
||||
+ if (flags & MALLOC)
|
||||
+ while (width-- > 0)
|
||||
+ *str++ = '\0';
|
||||
+
|
||||
if ((flags & MALLOC) && str - *strptr != strsize)
|
||||
{
|
||||
char *cp = (char *) realloc (*strptr, str - *strptr);
|
||||
@@ -908,7 +913,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
if (width == -1)
|
||||
width = 1;
|
||||
|
||||
- STRING_ARG (wstr, wchar_t, (width > 1024 ? 1024 : width));
|
||||
+ STRING_ARG (wstr, wchar_t, (width > 0 ? width : 1));
|
||||
|
||||
c = inchar ();
|
||||
if (__glibc_unlikely (c == EOF))
|
||||
@@ -1044,6 +1049,11 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
|
||||
if (!(flags & SUPPRESS))
|
||||
{
|
||||
+ /* If the buffer isn't completely filled, pad it with NULs. */
|
||||
+ if (flags & MALLOC)
|
||||
+ while (width-- > 0)
|
||||
+ *wstr++ = L'\0';
|
||||
+
|
||||
if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
|
||||
{
|
||||
wchar_t *cp = (wchar_t *) realloc (*strptr,
|
||||
@ -1,2 +1,2 @@
|
||||
381936891b4e421cd9a03b682bcb5a66039fd230
|
||||
ec99e297ec21a794af038ae0b8ad9eae6a5b7a54
|
||||
v1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user