import CS glibc-2.34-276.el9
This commit is contained in:
parent
e0b67080b6
commit
4c2db18501
24
SOURCES/glibc-RHEL-1018.patch
Normal file
24
SOURCES/glibc-RHEL-1018.patch
Normal file
@ -0,0 +1,24 @@
|
||||
commit fc72b6d7d818ab2868920af956d1542d03342a4d
|
||||
Author: Andreas Schwab <schwab@suse.de>
|
||||
Date: Tue Aug 1 17:01:37 2023 +0200
|
||||
|
||||
iconv: restore verbosity with unrecognized encoding names (bug 30694)
|
||||
|
||||
Commit 91927b7c76 ("Rewrite iconv option parsing [BZ #19519]") changed the
|
||||
iconv program to call __gconv_open directly instead of the iconv_open
|
||||
wrapper, but the former does not set errno. Update the caller to
|
||||
interpret the return codes like iconv_open does.
|
||||
|
||||
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
|
||||
index 08ea99d6adf6ea86..f199db6020284ad1 100644
|
||||
--- a/iconv/iconv_prog.c
|
||||
+++ b/iconv/iconv_prog.c
|
||||
@@ -201,7 +201,7 @@ main (int argc, char *argv[])
|
||||
|
||||
if (res != __GCONV_OK)
|
||||
{
|
||||
- if (errno == EINVAL)
|
||||
+ if (res == __GCONV_NOCONV || res == __GCONV_NODB)
|
||||
{
|
||||
/* Try to be nice with the user and tell her which of the
|
||||
two encoding names is wrong. This is possible because
|
||||
59
SOURCES/glibc-RHEL-140105.patch
Normal file
59
SOURCES/glibc-RHEL-140105.patch
Normal file
@ -0,0 +1,59 @@
|
||||
commit 559010e471acb3cb292615b71b248aba73e5c2fe
|
||||
Author: Dragan Stanojević (Nevidljivi) <neville.ravenwood@gmail.com>
|
||||
Date: Wed Feb 7 16:31:04 2024 +0100
|
||||
|
||||
localedata: hr_HR: change currency to EUR/€
|
||||
|
||||
Resolves: BZ # 29845
|
||||
|
||||
Conflicts:
|
||||
localedata/locales/hr_HR
|
||||
(locale definitions do not use UTF-8 downstream)
|
||||
|
||||
diff --git a/localedata/locales/hr_HR b/localedata/locales/hr_HR
|
||||
index 029a3794e2a17dcb..a13370461eede9c1 100644
|
||||
--- a/localedata/locales/hr_HR
|
||||
+++ b/localedata/locales/hr_HR
|
||||
@@ -24,8 +24,8 @@ tel ""
|
||||
fax ""
|
||||
language "Croatian"
|
||||
territory "Croatia"
|
||||
-revision "2.3"
|
||||
-date "2016-04-16"
|
||||
+revision "2.4"
|
||||
+date "2022-12-03"
|
||||
|
||||
category "i18n:2012";LC_IDENTIFICATION
|
||||
category "i18n:2012";LC_CTYPE
|
||||
@@ -171,8 +171,8 @@ nostr "ne"
|
||||
END LC_MESSAGES
|
||||
|
||||
LC_MONETARY
|
||||
-int_curr_symbol "HRK "
|
||||
-currency_symbol "kn"
|
||||
+int_curr_symbol "EUR "
|
||||
+currency_symbol "<U20AC>"
|
||||
mon_decimal_point ","
|
||||
mon_thousands_sep "."
|
||||
mon_grouping 3;3
|
||||
diff --git a/stdlib/tst-strfmon_l.c b/stdlib/tst-strfmon_l.c
|
||||
index 603d4b0c3d91818b..65313cd14b61dfe4 100644
|
||||
--- a/stdlib/tst-strfmon_l.c
|
||||
+++ b/stdlib/tst-strfmon_l.c
|
||||
@@ -181,12 +181,12 @@ static const struct locale_pair tests[] =
|
||||
"hr_HR.UTF-8",
|
||||
{
|
||||
{
|
||||
- "HRK 1.234.567,89", "1.234.567,89 kn",
|
||||
- "HRK 1234567,89", "1234567,89 kn"
|
||||
+ "EUR 1.234.567,89", "1.234.567,89 €",
|
||||
+ "EUR 1234567,89", "1234567,89 €"
|
||||
},
|
||||
{
|
||||
- "-HRK 1.234.567,89", "-1.234.567,89 kn",
|
||||
- "-HRK 1234567,89", "-1234567,89 kn"
|
||||
+ "-EUR 1.234.567,89", "-1.234.567,89 €",
|
||||
+ "-EUR 1234567,89", "-1234567,89 €"
|
||||
}
|
||||
}
|
||||
},
|
||||
46
SOURCES/glibc-RHEL-141072.patch
Normal file
46
SOURCES/glibc-RHEL-141072.patch
Normal file
@ -0,0 +1,46 @@
|
||||
commit 63716823dbad9482e09972907ae98e9cb00f9b86
|
||||
Author: Sunil K Pandey <sunil.k.pandey@intel.com>
|
||||
Date: Tue Dec 9 08:57:44 2025 -0800
|
||||
|
||||
nptl: Optimize trylock for high cache contention workloads (BZ #33704)
|
||||
|
||||
Check lock availability before acquisition to reduce cache line
|
||||
bouncing. Significantly improves trylock throughput on multi-core
|
||||
systems under heavy contention.
|
||||
|
||||
Tested on x86_64.
|
||||
|
||||
Fixes BZ #33704.
|
||||
|
||||
Co-authored-by: Alex M Wells <alex.m.wells@intel.com>
|
||||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||||
|
||||
Conflicts:
|
||||
nptl/pthread_mutex_trylock.c
|
||||
Updated for minor context difference
|
||||
|
||||
diff -Nrup a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
|
||||
--- a/nptl/pthread_mutex_trylock.c 2021-08-01 21:33:43.000000000 -0400
|
||||
+++ b/nptl/pthread_mutex_trylock.c 2026-02-06 13:29:01.508899356 -0500
|
||||
@@ -49,7 +49,8 @@ ___pthread_mutex_trylock (pthread_mutex_
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (lll_trylock (mutex->__data.__lock) == 0)
|
||||
+ if (atomic_load_relaxed (&(mutex->__data.__lock)) == 0
|
||||
+ && lll_trylock (mutex->__data.__lock) == 0)
|
||||
{
|
||||
/* Record the ownership. */
|
||||
mutex->__data.__owner = id;
|
||||
@@ -72,7 +73,10 @@ ___pthread_mutex_trylock (pthread_mutex_
|
||||
/*FALL THROUGH*/
|
||||
case PTHREAD_MUTEX_ADAPTIVE_NP:
|
||||
case PTHREAD_MUTEX_ERRORCHECK_NP:
|
||||
- if (lll_trylock (mutex->__data.__lock) != 0)
|
||||
+ /* Mutex type is already loaded, lock check overhead should
|
||||
+ be minimal. */
|
||||
+ if (atomic_load_relaxed (&(mutex->__data.__lock)) != 0
|
||||
+ || lll_trylock (mutex->__data.__lock) != 0)
|
||||
break;
|
||||
|
||||
/* Record the ownership. */
|
||||
52
SOURCES/glibc-RHEL-142196-1.patch
Normal file
52
SOURCES/glibc-RHEL-142196-1.patch
Normal file
@ -0,0 +1,52 @@
|
||||
commit 4a133885a7c8ae7ebe34e36fcdb353f8e94c810f
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Mon Nov 6 17:25:45 2023 -0300
|
||||
|
||||
elf: Ignore LD_PROFILE for setuid binaries
|
||||
|
||||
Loader does not ignore LD_PROFILE in secure-execution mode (different
|
||||
than man-page states [1]), rather it uses a different path
|
||||
(/var/profile) and ignore LD_PROFILE_OUTPUT.
|
||||
|
||||
Allowing secure-execution profiling is already a non good security
|
||||
boundary, since it enables different code paths and extra OS access by
|
||||
the process. But by ignoring LD_PROFILE_OUTPUT, the resulting profile
|
||||
file might also be acceded in a racy manner since the file name does not
|
||||
use any process-specific information (such as pid, timing, etc.).
|
||||
|
||||
Another side-effect is it forces lazy binding even on libraries that
|
||||
might be with DF_BIND_NOW.
|
||||
|
||||
[1] https://man7.org/linux/man-pages/man8/ld.so.8.html
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
elf/tst-env-setuid.c
|
||||
(test does not have LD_PROFILE support downstream)
|
||||
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index 1fbfc65a38e19110..44546e8e158e7b9c 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -2761,10 +2761,6 @@ process_envvars (struct dl_main_state *state)
|
||||
char *envline;
|
||||
char *debug_output = NULL;
|
||||
|
||||
- /* This is the default place for profiling data file. */
|
||||
- GLRO(dl_profile_output)
|
||||
- = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
|
||||
-
|
||||
while ((envline = _dl_next_ld_env_entry (&runp)) != NULL)
|
||||
{
|
||||
size_t len = 0;
|
||||
@@ -2813,7 +2809,8 @@ process_envvars (struct dl_main_state *state)
|
||||
}
|
||||
|
||||
/* Which shared object shall be profiled. */
|
||||
- if (memcmp (envline, "PROFILE", 7) == 0 && envline[8] != '\0')
|
||||
+ if (!__libc_enable_secure
|
||||
+ && memcmp (envline, "PROFILE", 7) == 0 && envline[8] != '\0')
|
||||
GLRO(dl_profile) = &envline[8];
|
||||
break;
|
||||
|
||||
243
SOURCES/glibc-RHEL-142196-2.patch
Normal file
243
SOURCES/glibc-RHEL-142196-2.patch
Normal file
@ -0,0 +1,243 @@
|
||||
commit 1e1ad714ee9a663eda0e2bffad1d9f258b00a4e9
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Mon May 6 13:18:47 2024 -0300
|
||||
|
||||
support: Add envp argument to support_capture_subprogram
|
||||
|
||||
So tests can specify a list of environment variables.
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
elf/tst-tunables.c
|
||||
elf/tst-tunables-enable_secure.c
|
||||
sysdeps/x86/tst-hwcap-tunables.c
|
||||
(files do not exist downstream)
|
||||
|
||||
diff --git a/elf/tst-audit18.c b/elf/tst-audit18.c
|
||||
index 841251dd7003aa7d..cec93e269ca0b4ef 100644
|
||||
--- a/elf/tst-audit18.c
|
||||
+++ b/elf/tst-audit18.c
|
||||
@@ -79,7 +79,7 @@ do_test (int argc, char *argv[])
|
||||
|
||||
setenv ("LD_AUDIT", "tst-auditmod18.so", 0);
|
||||
struct support_capture_subprocess result
|
||||
- = support_capture_subprogram (spargv[0], spargv);
|
||||
+ = support_capture_subprogram (spargv[0], spargv, NULL);
|
||||
support_capture_subprocess_check (&result, "tst-audit18", 0, sc_allow_stderr);
|
||||
|
||||
struct
|
||||
diff --git a/elf/tst-audit19b.c b/elf/tst-audit19b.c
|
||||
index 70bfe4eadf5ee845..88d99a416bbe93dd 100644
|
||||
--- a/elf/tst-audit19b.c
|
||||
+++ b/elf/tst-audit19b.c
|
||||
@@ -69,7 +69,7 @@ do_test (int argc, char *argv[])
|
||||
|
||||
setenv ("LD_AUDIT", "tst-auditmod18b.so", 0);
|
||||
struct support_capture_subprocess result
|
||||
- = support_capture_subprogram (spargv[0], spargv);
|
||||
+ = support_capture_subprogram (spargv[0], spargv, NULL);
|
||||
support_capture_subprocess_check (&result, "tst-audit18b", 0, sc_allow_stderr);
|
||||
|
||||
bool find_symbind = false;
|
||||
diff --git a/elf/tst-audit22.c b/elf/tst-audit22.c
|
||||
index 4e97be3be0c6a2e3..6aa18af948afa9c5 100644
|
||||
--- a/elf/tst-audit22.c
|
||||
+++ b/elf/tst-audit22.c
|
||||
@@ -83,7 +83,7 @@ do_test (int argc, char *argv[])
|
||||
|
||||
setenv ("LD_AUDIT", "tst-auditmod22.so", 0);
|
||||
struct support_capture_subprocess result
|
||||
- = support_capture_subprogram (spargv[0], spargv);
|
||||
+ = support_capture_subprogram (spargv[0], spargv, NULL);
|
||||
support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
|
||||
|
||||
/* The respawned process should always print the vDSO address (otherwise it
|
||||
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
|
||||
index 1b76336595fcd301..7786a74e648aeb6f 100644
|
||||
--- a/elf/tst-audit23.c
|
||||
+++ b/elf/tst-audit23.c
|
||||
@@ -87,7 +87,7 @@ do_one_test (int argc, char *argv[], bool pass_dlclose_flag)
|
||||
|
||||
setenv ("LD_AUDIT", "tst-auditmod23.so", 0);
|
||||
struct support_capture_subprocess result
|
||||
- = support_capture_subprogram (spargv[0], spargv);
|
||||
+ = support_capture_subprogram (spargv[0], spargv, NULL);
|
||||
support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
|
||||
|
||||
{
|
||||
diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c
|
||||
index b209ee820f2f2a02..cdd4f2ce2b54d622 100644
|
||||
--- a/elf/tst-audit25a.c
|
||||
+++ b/elf/tst-audit25a.c
|
||||
@@ -77,7 +77,7 @@ do_test (int argc, char *argv[])
|
||||
|
||||
{
|
||||
struct support_capture_subprocess result
|
||||
- = support_capture_subprogram (spargv[0], spargv);
|
||||
+ = support_capture_subprogram (spargv[0], spargv, NULL);
|
||||
support_capture_subprocess_check (&result, "tst-audit25a", 0,
|
||||
sc_allow_stderr);
|
||||
|
||||
@@ -102,7 +102,7 @@ do_test (int argc, char *argv[])
|
||||
{
|
||||
setenv ("LD_BIND_NOW", "1", 0);
|
||||
struct support_capture_subprocess result
|
||||
- = support_capture_subprogram (spargv[0], spargv);
|
||||
+ = support_capture_subprogram (spargv[0], spargv, NULL);
|
||||
support_capture_subprocess_check (&result, "tst-audit25a", 0,
|
||||
sc_allow_stderr);
|
||||
|
||||
diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c
|
||||
index 9b8665d5171b7c6b..939f4d6188368540 100644
|
||||
--- a/elf/tst-audit25b.c
|
||||
+++ b/elf/tst-audit25b.c
|
||||
@@ -76,7 +76,7 @@ do_test (int argc, char *argv[])
|
||||
|
||||
{
|
||||
struct support_capture_subprocess result
|
||||
- = support_capture_subprogram (spargv[0], spargv);
|
||||
+ = support_capture_subprogram (spargv[0], spargv, NULL);
|
||||
support_capture_subprocess_check (&result, "tst-audit25a", 0,
|
||||
sc_allow_stderr);
|
||||
|
||||
@@ -102,7 +102,7 @@ do_test (int argc, char *argv[])
|
||||
{
|
||||
setenv ("LD_BIND_NOW", "1", 0);
|
||||
struct support_capture_subprocess result
|
||||
- = support_capture_subprogram (spargv[0], spargv);
|
||||
+ = support_capture_subprogram (spargv[0], spargv, NULL);
|
||||
support_capture_subprocess_check (&result, "tst-audit25a", 0,
|
||||
sc_allow_stderr);
|
||||
|
||||
diff --git a/elf/tst-glibc-hwcaps-2-cache.c b/elf/tst-glibc-hwcaps-2-cache.c
|
||||
index 81ab44ff78ddbb57..af91476ccafeecff 100644
|
||||
--- a/elf/tst-glibc-hwcaps-2-cache.c
|
||||
+++ b/elf/tst-glibc-hwcaps-2-cache.c
|
||||
@@ -32,7 +32,7 @@ main (int argc, char **argv)
|
||||
/* Run ldconfig to populate the cache. */
|
||||
char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir);
|
||||
struct support_capture_subprocess result =
|
||||
- support_capture_subprogram (command, &((char *) { NULL }));
|
||||
+ support_capture_subprogram (command, &((char *) { NULL }), NULL);
|
||||
support_capture_subprocess_check (&result, "ldconfig", 0, sc_allow_none);
|
||||
free (command);
|
||||
|
||||
diff --git a/elf/tst-rtld-run-static.c b/elf/tst-rtld-run-static.c
|
||||
index b2650e85ffbcdc20..f05c00eb7b76958b 100644
|
||||
--- a/elf/tst-rtld-run-static.c
|
||||
+++ b/elf/tst-rtld-run-static.c
|
||||
@@ -30,7 +30,7 @@ do_test (void)
|
||||
{
|
||||
char *argv[] = { (char *) "ld.so", ldconfig_path, (char *) "--help", NULL };
|
||||
struct support_capture_subprocess cap
|
||||
- = support_capture_subprogram (support_objdir_elf_ldso, argv);
|
||||
+ = support_capture_subprogram (support_objdir_elf_ldso, argv, NULL);
|
||||
support_capture_subprocess_check (&cap, "no --argv0", 0, sc_allow_stdout);
|
||||
puts ("info: output without --argv0:");
|
||||
puts (cap.out.buffer);
|
||||
@@ -46,7 +46,7 @@ do_test (void)
|
||||
ldconfig_path, (char *) "--help", NULL
|
||||
};
|
||||
struct support_capture_subprocess cap
|
||||
- = support_capture_subprogram (support_objdir_elf_ldso, argv);
|
||||
+ = support_capture_subprogram (support_objdir_elf_ldso, argv, NULL);
|
||||
support_capture_subprocess_check (&cap, "with --argv0", 0, sc_allow_stdout);
|
||||
puts ("info: output with --argv0:");
|
||||
puts (cap.out.buffer);
|
||||
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
|
||||
index 8cbdca3b9dfb41ba..57bb941e7d1e5c84 100644
|
||||
--- a/support/capture_subprocess.h
|
||||
+++ b/support/capture_subprocess.h
|
||||
@@ -35,11 +35,12 @@ struct support_capture_subprocess
|
||||
struct support_capture_subprocess support_capture_subprocess
|
||||
(void (*callback) (void *), void *closure);
|
||||
|
||||
-/* Issue FILE with ARGV arguments by using posix_spawn and capture standard
|
||||
- output, standard error, and the exit status. The out.buffer and err.buffer
|
||||
- are handle as support_capture_subprocess. */
|
||||
+/* Issue FILE with ARGV arguments and ENVP environments by using posix_spawn
|
||||
+ and capture standard output, standard error, and the exit status. If
|
||||
+ ENVP is NULL the current environment variable is used. The out.buffer and
|
||||
+ err.buffer are handle by support_capture_subprocess. */
|
||||
struct support_capture_subprocess support_capture_subprogram
|
||||
- (const char *file, char *const argv[]);
|
||||
+ (const char *file, char *const argv[], char *const envp[]);
|
||||
|
||||
/* Copy the running program into a setgid binary and run it with
|
||||
CHILD_ID argument. If the program exits with a non-zero status,
|
||||
diff --git a/support/subprocess.h b/support/subprocess.h
|
||||
index 8fbb895353d61965..8274a2b22bb10296 100644
|
||||
--- a/support/subprocess.h
|
||||
+++ b/support/subprocess.h
|
||||
@@ -33,10 +33,11 @@ struct support_subprocess
|
||||
struct support_subprocess support_subprocess
|
||||
(void (*callback) (void *), void *closure);
|
||||
|
||||
-/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a
|
||||
- pipe redirected to STDOUT, and a pipe redirected to STDERR. */
|
||||
+/* Issue FILE with ARGV arguments and ENVP environments by using posix_spawn
|
||||
+ and return is PID, a pipe redirected to STDOUT, and a pipe redirected to
|
||||
+ STDERR. If ENVP is NULL the current environment variable is used. */
|
||||
struct support_subprocess support_subprogram
|
||||
- (const char *file, char *const argv[]);
|
||||
+ (const char *file, char *const argv[], char *const envp[]);
|
||||
|
||||
/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it
|
||||
to complete. Return program exit status. */
|
||||
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
|
||||
index 8dc95f8aa723b6bc..cbc695106483ab54 100644
|
||||
--- a/support/support_capture_subprocess.c
|
||||
+++ b/support/support_capture_subprocess.c
|
||||
@@ -98,13 +98,14 @@ support_capture_subprocess (void (*callback) (void *), void *closure)
|
||||
}
|
||||
|
||||
struct support_capture_subprocess
|
||||
-support_capture_subprogram (const char *file, char *const argv[])
|
||||
+support_capture_subprogram (const char *file, char *const argv[],
|
||||
+ char *const envp[])
|
||||
{
|
||||
struct support_capture_subprocess result;
|
||||
xopen_memstream (&result.out);
|
||||
xopen_memstream (&result.err);
|
||||
|
||||
- struct support_subprocess proc = support_subprogram (file, argv);
|
||||
+ struct support_subprocess proc = support_subprogram (file, argv, envp);
|
||||
|
||||
support_capture_poll (&result, &proc);
|
||||
return result;
|
||||
diff --git a/support/support_subprocess.c b/support/support_subprocess.c
|
||||
index a2fef394d42ea4f9..b692a7f8b178502d 100644
|
||||
--- a/support/support_subprocess.c
|
||||
+++ b/support/support_subprocess.c
|
||||
@@ -69,7 +69,7 @@ support_subprocess (void (*callback) (void *), void *closure)
|
||||
}
|
||||
|
||||
struct support_subprocess
|
||||
-support_subprogram (const char *file, char *const argv[])
|
||||
+support_subprogram (const char *file, char *const argv[], char *const envp[])
|
||||
{
|
||||
struct support_subprocess result = support_subprocess_init ();
|
||||
|
||||
@@ -84,7 +84,8 @@ support_subprogram (const char *file, char *const argv[])
|
||||
xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
|
||||
xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
|
||||
|
||||
- result.pid = xposix_spawn (file, &fa, NULL, argv, environ);
|
||||
+ result.pid = xposix_spawn (file, &fa, NULL, argv,
|
||||
+ envp == NULL ? environ : envp);
|
||||
|
||||
xclose (result.stdout_pipe[1]);
|
||||
xclose (result.stderr_pipe[1]);
|
||||
diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
|
||||
index 8145548982a935cb..756fb75d195cdf8a 100644
|
||||
--- a/support/tst-support_capture_subprocess.c
|
||||
+++ b/support/tst-support_capture_subprocess.c
|
||||
@@ -238,7 +238,7 @@ do_subprogram (const struct test *test)
|
||||
args[argc] = NULL;
|
||||
TEST_VERIFY (argc < argv_size);
|
||||
|
||||
- return support_capture_subprogram (args[0], args);
|
||||
+ return support_capture_subprogram (args[0], args, NULL);
|
||||
}
|
||||
|
||||
enum test_type
|
||||
56
SOURCES/glibc-RHEL-142196-3.patch
Normal file
56
SOURCES/glibc-RHEL-142196-3.patch
Normal file
@ -0,0 +1,56 @@
|
||||
commit 7b543dcdf97d07fd4346feb17916e08fe83ad0ae
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Jan 15 22:29:46 2026 +0100
|
||||
|
||||
elf: Ignore LD_PROFILE if LD_PROFILE_OUTPUT is not set (bug 33797)
|
||||
|
||||
The previous default for LD_PROFILE_OUTPUT, /var/tmp, is insecure
|
||||
because it's typically a 1777 directory, and other systems could
|
||||
place malicious files there which interfere with execution.
|
||||
|
||||
Requiring the user to specify a profiling directory mitigates
|
||||
the impact of bug 33797. Clear LD_PROFILE_OUTPUT alongside
|
||||
with LD_PROFILE.
|
||||
|
||||
Rework the test not to use predictable file names.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
elf/rtld.c
|
||||
(different implementation of environment variable filtering
|
||||
downstream)
|
||||
elf/tst-env-setuid.c
|
||||
(no LD_PROFILE test downstream)
|
||||
|
||||
diff -Nrup a/elf/rtld.c b/elf/rtld.c
|
||||
--- a/elf/rtld.c 2026-02-25 14:11:17.505620756 -0500
|
||||
+++ b/elf/rtld.c 2026-02-25 14:14:43.355916730 -0500
|
||||
@@ -2974,6 +2974,15 @@ process_envvars (struct dl_main_state *s
|
||||
/* We use standard output if opening the file failed. */
|
||||
GLRO(dl_debug_fd) = STDOUT_FILENO;
|
||||
}
|
||||
+
|
||||
+ /* There is no fixed, safe directory to store profiling data, so
|
||||
+ activate LD_PROFILE only if LD_PROFILE_OUTPUT is set as well. */
|
||||
+ if (GLRO(dl_profile) != NULL && GLRO(dl_profile_output) == NULL)
|
||||
+ {
|
||||
+ _dl_error_printf ("\
|
||||
+warning: LD_PROFILE ignored because LD_PROFILE_OUTPUT not specified\n");
|
||||
+ GLRO(dl_profile) = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
#if HP_TIMING_INLINE
|
||||
diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h
|
||||
index 5ea8a4a259ef753c..0b84642f71ae9351 100644
|
||||
--- a/sysdeps/generic/unsecvars.h
|
||||
+++ b/sysdeps/generic/unsecvars.h
|
||||
@@ -21,6 +21,7 @@
|
||||
"LD_ORIGIN_PATH\0" \
|
||||
"LD_PRELOAD\0" \
|
||||
"LD_PROFILE\0" \
|
||||
+ "LD_PROFILE_OUTPUT\0" \
|
||||
"LD_SHOW_AUXV\0" \
|
||||
"LD_USE_LOAD_BIAS\0" \
|
||||
"LOCALDOMAIN\0" \
|
||||
28
SOURCES/glibc-RHEL-142196-4.patch
Normal file
28
SOURCES/glibc-RHEL-142196-4.patch
Normal file
@ -0,0 +1,28 @@
|
||||
commit 34d98aea6c1eaf7750a992bae55b2bca24898eab
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Sat Jan 24 10:29:22 2026 +0100
|
||||
|
||||
support: Fix memory leaks in support_subprogram, support_subprogram_wait
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/support/support_subprocess.c b/support/support_subprocess.c
|
||||
index b692a7f8b178502d..ec0c069470a586ac 100644
|
||||
--- a/support/support_subprocess.c
|
||||
+++ b/support/support_subprocess.c
|
||||
@@ -86,6 +86,7 @@ support_subprogram (const char *file, char *const argv[], char *const envp[])
|
||||
|
||||
result.pid = xposix_spawn (file, &fa, NULL, argv,
|
||||
envp == NULL ? environ : envp);
|
||||
+ posix_spawn_file_actions_destroy (&fa);
|
||||
|
||||
xclose (result.stdout_pipe[1]);
|
||||
xclose (result.stderr_pipe[1]);
|
||||
@@ -102,6 +103,7 @@ support_subprogram_wait (const char *file, char *const argv[])
|
||||
struct support_subprocess res = support_subprocess_init ();
|
||||
|
||||
res.pid = xposix_spawn (file, &fa, NULL, argv, environ);
|
||||
+ posix_spawn_file_actions_destroy (&fa);
|
||||
|
||||
return support_process_wait (&res);
|
||||
}
|
||||
49
SOURCES/glibc-RHEL-142196-5.patch
Normal file
49
SOURCES/glibc-RHEL-142196-5.patch
Normal file
@ -0,0 +1,49 @@
|
||||
commit e8502182f09211663c1583960442eb6ff502a33e
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Sat Jan 24 10:29:22 2026 +0100
|
||||
|
||||
support: Add support_hardcoded_paths_in_test
|
||||
|
||||
It indicates whether glibc was configured with
|
||||
--enable-hardcoded-path-in-tests.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff -Nrup a/support/Makefile b/support/Makefile
|
||||
--- a/support/Makefile 2026-02-23 07:44:09.189237390 -0500
|
||||
+++ b/support/Makefile 2026-02-23 07:49:33.975521231 -0500
|
||||
@@ -252,6 +252,12 @@ CFLAGS-support_paths.c = \
|
||||
-DROOTSBINDIR_PATH=\"$(rootsbindir)\" \
|
||||
-DCOMPLOCALEDIR_PATH=\"$(complocaledir)\"
|
||||
|
||||
+ifeq ($(build-hardcoded-path-in-tests),yes)
|
||||
+CFLAGS-support_paths.c += -DHARDCODED_PATHS_IN_TEST=true
|
||||
+else
|
||||
+CFLAGS-support_paths.c += -DHARDCODED_PATHS_IN_TEST=false
|
||||
+endif
|
||||
+
|
||||
# In support_timespec_check_in_range we may be passed a very tight
|
||||
# range for which we should produce a correct result for expected
|
||||
# being withing the observed range. The code uses double internally
|
||||
diff -Nrup a/support/support.h b/support/support.h
|
||||
--- a/support/support.h 2026-02-23 07:44:09.127896391 -0500
|
||||
+++ b/support/support.h 2026-02-23 07:52:57.800614726 -0500
|
||||
@@ -144,6 +144,9 @@ extern const char support_install_rootsb
|
||||
/* Corresponds to the install's compiled locale directory. */
|
||||
extern const char support_complocaledir_prefix[];
|
||||
|
||||
+/* If true, glibc was configured with --enable-hardcoded-path-in-tests. */
|
||||
+extern const bool support_hardcoded_paths_in_test;
|
||||
+
|
||||
/* Copies the file at the path FROM to TO. If TO does not exist, it
|
||||
is created. If TO is a regular file, it is truncated before
|
||||
copying. The file mode is copied, but the permissions are not. */
|
||||
diff -Nrup a/support/support_paths.c b/support/support_paths.c
|
||||
--- a/support/support_paths.c 2021-08-01 21:33:43.000000000 -0400
|
||||
+++ b/support/support_paths.c 2026-02-23 07:56:12.231942401 -0500
|
||||
@@ -92,3 +92,5 @@ const char support_complocaledir_prefix[
|
||||
#else
|
||||
# error please -DCOMPLOCALEDIR_PATH=something in the Makefile
|
||||
#endif
|
||||
+
|
||||
+const bool support_hardcoded_paths_in_test = HARDCODED_PATHS_IN_TEST;
|
||||
40
SOURCES/glibc-RHEL-142196-6.patch
Normal file
40
SOURCES/glibc-RHEL-142196-6.patch
Normal file
@ -0,0 +1,40 @@
|
||||
commit 458a6a2b935f60a25a136846fe8b7a4723296dda
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Sat Jan 24 10:29:39 2026 +0100
|
||||
|
||||
support: Reinitialize containers if /etc is present
|
||||
|
||||
This prevents test failures because configuration file leftovers
|
||||
unexpectedly change glibc for future tests. Whether this
|
||||
triggers depends on test execution order.
|
||||
|
||||
Adding postclean.req files manually (before this change) appears
|
||||
too error-prone.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
diff --git a/support/test-container.c b/support/test-container.c
|
||||
index a9c9926c21f3a21e..f2853f6a71475420 100644
|
||||
--- a/support/test-container.c
|
||||
+++ b/support/test-container.c
|
||||
@@ -134,7 +134,9 @@ int verbose = 0;
|
||||
- 'mkdirp': A minimal "mkdir -p FILE" command.
|
||||
|
||||
* mytest.root/postclean.req causes fresh rsync (with delete) after
|
||||
- test if present
|
||||
+ test if present. If /etc is present, the testroot is cleaned,
|
||||
+ too. This prevents further tests from using special
|
||||
+ configurations in /etc from previous tests.
|
||||
|
||||
* mytest.root/ldconfig.run causes ldconfig to be issued prior
|
||||
test execution (to setup the initial ld.so.cache).
|
||||
@@ -868,7 +870,8 @@ main (int argc, char **argv)
|
||||
if (strrchr (so_base, '/') != NULL)
|
||||
strrchr (so_base, '/')[1] = 0;
|
||||
|
||||
- if (file_exists (concat (command_root, "/postclean.req", NULL)))
|
||||
+ if (file_exists (concat (command_root, "/postclean.req", NULL))
|
||||
+ || file_exists (concat (command_root, "/etc", NULL)))
|
||||
do_postclean = 1;
|
||||
|
||||
if (file_exists (concat (command_root, "/ldconfig.run", NULL)))
|
||||
505
SOURCES/glibc-RHEL-142196-7.patch
Normal file
505
SOURCES/glibc-RHEL-142196-7.patch
Normal file
@ -0,0 +1,505 @@
|
||||
commit 229f65f5f322609283c7104c80c8af6434dff628
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Feb 2 21:15:48 2026 +0100
|
||||
|
||||
support: Add support_spawn_wrap and related functionality
|
||||
|
||||
It allows us to write test cases in C that run tests with
|
||||
dynamic linker wrapping.
|
||||
|
||||
The iconv test case was auto-generated. The posix_spawn usage
|
||||
is mechanical, and the interface it tests is newly added in this
|
||||
commit, so this should be acceptable.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
support/Makefile
|
||||
(Remove duplicate entry for support_stack_alloc)
|
||||
|
||||
diff -Nrup a/support/Makefile b/support/Makefile
|
||||
--- a/support/Makefile 2026-02-23 11:21:06.705964233 -0500
|
||||
+++ b/support/Makefile 2026-02-23 11:46:54.560737380 -0500
|
||||
@@ -90,7 +90,7 @@ libsupport-routines = \
|
||||
support_shared_allocate \
|
||||
support_small_stack_thread_attribute \
|
||||
support_socket_so_timestamp_time64 \
|
||||
- support_stack_alloc \
|
||||
+ support_spawn_wrap \
|
||||
support_stack_alloc \
|
||||
support_stat_nanoseconds \
|
||||
support_subprocess \
|
||||
@@ -258,6 +258,11 @@ else
|
||||
CFLAGS-support_paths.c += -DHARDCODED_PATHS_IN_TEST=false
|
||||
endif
|
||||
|
||||
+CFLAGS-support_spawn_wrap.c += \
|
||||
+ '-DRUN_PROGRAM_ENV=$(patsubst %, ELEMENT ("%"), $(run-program-env))' \
|
||||
+ '-DRTLD_PREFIX=$(patsubst %, ELEMENT ("%"), $(rtld-prefix))' \
|
||||
+ # CFLAGS-support_spawn_wrap.c
|
||||
+
|
||||
# In support_timespec_check_in_range we may be passed a very tight
|
||||
# range for which we should produce a correct result for expected
|
||||
# being withing the observed range. The code uses double internally
|
||||
@@ -343,6 +348,7 @@ tests = \
|
||||
tst-support_quote_string \
|
||||
tst-support_readdir \
|
||||
tst-support_record_failure \
|
||||
+ tst-support_spawn_wrap \
|
||||
tst-test_compare \
|
||||
tst-test_compare_blob \
|
||||
tst-test_compare_string \
|
||||
diff -Nrup a/support/subprocess.h b/support/subprocess.h
|
||||
--- a/support/subprocess.h 2021-08-01 21:33:43.000000000 -0400
|
||||
+++ b/support/subprocess.h 2026-02-23 11:22:26.578465391 -0500
|
||||
@@ -51,4 +51,36 @@ int support_process_wait (struct support
|
||||
then with a SIGKILL. Return the status as for waitpid call. */
|
||||
int support_process_terminate (struct support_subprocess *proc);
|
||||
|
||||
+/* Arguments to pass to posix_spawn and related functions to run a
|
||||
+ process under the built glibc. This overrides the dynamic linker,
|
||||
+ its search path, and other search paths, such as for locales. */
|
||||
+struct support_spawn_wrapped
|
||||
+{
|
||||
+ const char *path;
|
||||
+ char *const *argv;
|
||||
+ char *const *envp;
|
||||
+};
|
||||
+
|
||||
+enum support_spawn_wrap_flags
|
||||
+ {
|
||||
+ /* Always wrap the invocation, even if test binaries are linked
|
||||
+ with overridden the default paths to point into the build tree
|
||||
+ (--enable-hardcoded-path-in-tests). Can be used to run
|
||||
+ non-test binaries. */
|
||||
+ support_spawn_wrap_force = 1 << 0,
|
||||
+ };
|
||||
+
|
||||
+/* Wrap the invocation for invoking testing. PATH is the program
|
||||
+ path. If ARGV is null, no arguments are passed. If ENVP is null,
|
||||
+ environ is used instead. The result must not be modified. It is a
|
||||
+ deep copy of the inputs. */
|
||||
+struct support_spawn_wrapped *support_spawn_wrap (const char *path,
|
||||
+ char *const argv[],
|
||||
+ char *const envp[],
|
||||
+ enum
|
||||
+ support_spawn_wrap_flags);
|
||||
+
|
||||
+/* Deallocate the result of support_spawn_wrap. */
|
||||
+void support_spawn_wrapped_free (struct support_spawn_wrapped *);
|
||||
+
|
||||
#endif
|
||||
diff -Nrup a/support/support_spawn_wrap.c b/support/support_spawn_wrap.c
|
||||
--- a/support/support_spawn_wrap.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/support/support_spawn_wrap.c 2026-02-23 11:22:26.578713214 -0500
|
||||
@@ -0,0 +1,171 @@
|
||||
+/* Wrap a subprocess invocation with an ld.so invocation.
|
||||
+ 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 <array_length.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/subprocess.h>
|
||||
+#include <support/support.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+#define ELEMENT(s) s,
|
||||
+static const char *const rtld_prefix[] = { RTLD_PREFIX "--argv0" };
|
||||
+static const char *const run_program_env[] = { RUN_PROGRAM_ENV };
|
||||
+#undef ELEMENT
|
||||
+
|
||||
+/* Return a newly allocated argument vector, with ld.so wrapping per
|
||||
+ rtld_prefix applied if WRAP is true. */
|
||||
+static char *const *
|
||||
+rewrite_argv (const char *path, char *const argv[], bool wrap)
|
||||
+{
|
||||
+ char *const substitute[] = { (char *) path, NULL};
|
||||
+ if (argv == NULL)
|
||||
+ argv = substitute;
|
||||
+ TEST_VERIFY (argv[0] != NULL);
|
||||
+
|
||||
+ size_t length;
|
||||
+ for (length = 0; argv[length] != 0; ++length)
|
||||
+ ;
|
||||
+ /* Potential wrapping, injected path, and null terminator. */
|
||||
+ length += array_length (rtld_prefix) + 1 + 1;
|
||||
+
|
||||
+ char **result = xcalloc (length, sizeof (result));
|
||||
+
|
||||
+ size_t inpos = 0;
|
||||
+ size_t outpos = 0;
|
||||
+ if (wrap)
|
||||
+ {
|
||||
+ for (size_t i = 0; i < array_length (rtld_prefix); ++i)
|
||||
+ {
|
||||
+ TEST_VERIFY (outpos < length);
|
||||
+ result[outpos++] = xstrdup (rtld_prefix[i]);
|
||||
+ }
|
||||
+
|
||||
+ /* --argv0 argument. */
|
||||
+ TEST_VERIFY (outpos < length);
|
||||
+ result[outpos++] = xstrdup (argv[0]);
|
||||
+ inpos = 1;
|
||||
+
|
||||
+ /* Path to program as used by ld.so. */
|
||||
+ TEST_VERIFY (outpos < length);
|
||||
+ result[outpos++] = xstrdup (path);
|
||||
+ }
|
||||
+
|
||||
+ for (; argv[inpos] != NULL; ++inpos)
|
||||
+ {
|
||||
+ TEST_VERIFY (outpos < length);
|
||||
+ result[outpos++] = xstrdup (argv[inpos]);
|
||||
+ }
|
||||
+
|
||||
+ TEST_VERIFY (outpos < length);
|
||||
+ return result;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+/* Return a newly allocated, rewritten environment, with the settings
|
||||
+ from run_program_env. */
|
||||
+static char *const *
|
||||
+rewrite_env (char *const envp[])
|
||||
+{
|
||||
+ if (envp == NULL)
|
||||
+ envp = environ;
|
||||
+
|
||||
+ size_t length;
|
||||
+ for (length = 0; envp[length] != 0; ++length)
|
||||
+ ;
|
||||
+ length += array_length (run_program_env) + 1;
|
||||
+
|
||||
+ /* Set to true if an element of run_program_env is copied. This is
|
||||
+ used to avoid adding it again. */
|
||||
+ bool copied[array_length (run_program_env)] = { false, };
|
||||
+
|
||||
+ char **result = xcalloc (length, sizeof (result));
|
||||
+ size_t outpos = 0;
|
||||
+ for (size_t inpos = 0; envp[inpos] != NULL; ++inpos)
|
||||
+ {
|
||||
+ const char *to_copy = envp[inpos];
|
||||
+ /* If there is no assignment operator, this environment string
|
||||
+ cannot be overridden. */
|
||||
+ const char *envp_assign = strchr (to_copy, '=');
|
||||
+ if (envp_assign != NULL)
|
||||
+ {
|
||||
+ size_t length_with_assign = envp_assign - to_copy + 1;
|
||||
+ for (size_t i = 0; i < array_length (run_program_env); ++i)
|
||||
+ {
|
||||
+ if (strncmp (to_copy, run_program_env[i], length_with_assign)
|
||||
+ == 0 && !copied[i])
|
||||
+ {
|
||||
+ to_copy = run_program_env[i];
|
||||
+ copied[i] = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ TEST_VERIFY (outpos < length);
|
||||
+ result[outpos++] = xstrdup (to_copy);
|
||||
+ }
|
||||
+
|
||||
+ for (size_t i = 0; i < array_length (run_program_env); ++i)
|
||||
+ {
|
||||
+ TEST_VERIFY (strchr (run_program_env[i], '=') != 0);
|
||||
+ if (!copied[i])
|
||||
+ {
|
||||
+ TEST_VERIFY (outpos < length);
|
||||
+ result[outpos++] = xstrdup (run_program_env[i]);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ TEST_VERIFY (outpos < length);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+struct support_spawn_wrapped *
|
||||
+support_spawn_wrap (const char *path,
|
||||
+ char *const argv[],
|
||||
+ char *const envp[],
|
||||
+ enum support_spawn_wrap_flags flags)
|
||||
+{
|
||||
+ if (flags != 0)
|
||||
+ TEST_COMPARE (flags, support_spawn_wrap_force);
|
||||
+ bool force = flags & support_spawn_wrap_force;
|
||||
+ bool wrap = force || !support_hardcoded_paths_in_test;
|
||||
+
|
||||
+ struct support_spawn_wrapped *result = xmalloc (sizeof (*result));
|
||||
+ if (wrap)
|
||||
+ result->path = xstrdup (support_objdir_elf_ldso);
|
||||
+ else
|
||||
+ result->path = xstrdup (path);
|
||||
+ result->argv = rewrite_argv (path, argv, wrap);
|
||||
+ result->envp = rewrite_env (envp);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+support_spawn_wrapped_free (struct support_spawn_wrapped *wrapped)
|
||||
+{
|
||||
+ free ((char *) wrapped->path);
|
||||
+ for (size_t i = 0; wrapped->argv[i] != NULL; ++i)
|
||||
+ free (wrapped->argv[i]);
|
||||
+ free ((char **) wrapped->argv);
|
||||
+ for (size_t i = 0; wrapped->envp[i] != NULL; ++i)
|
||||
+ free (wrapped->envp[i]);
|
||||
+ free ((char **) wrapped->envp);
|
||||
+ free (wrapped);
|
||||
+}
|
||||
diff -Nrup a/support/tst-support_spawn_wrap.c b/support/tst-support_spawn_wrap.c
|
||||
--- a/support/tst-support_spawn_wrap.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/support/tst-support_spawn_wrap.c 2026-02-23 11:22:26.578942243 -0500
|
||||
@@ -0,0 +1,235 @@
|
||||
+/* Tests for support_spawn_wrap.
|
||||
+ 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 <getopt.h>
|
||||
+#include <spawn.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/capture_subprocess.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/subprocess.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/xspawn.h>
|
||||
+#include <support/xunistd.h>
|
||||
+#include <sys/wait.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Return true if running via an explicit ld.so invocation. */
|
||||
+static bool
|
||||
+running_via_ldso (void)
|
||||
+{
|
||||
+ char *self = realpath ("/proc/self/exe", NULL);
|
||||
+ if (self == NULL)
|
||||
+ FAIL_UNSUPPORTED ("/proc/self/exe not available");
|
||||
+ char *ldso = realpath (support_objdir_elf_ldso, NULL);
|
||||
+ TEST_VERIFY_EXIT (ldso != NULL);
|
||||
+ bool result = strcmp (self, ldso) == 0;
|
||||
+ free (ldso);
|
||||
+ free (self);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_subprocess (int argc, char **argv)
|
||||
+{
|
||||
+ {
|
||||
+ char *argc_env = getenv ("argc");
|
||||
+ if (argc_env != NULL)
|
||||
+ {
|
||||
+ char *argc_arg = xasprintf ("%d", argc);
|
||||
+ TEST_COMPARE_STRING (argc_arg, argc_env);
|
||||
+ free (argc_arg);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (argc >= 2 && strcmp (argv[1], "alpha") == 0)
|
||||
+ {
|
||||
+ TEST_COMPARE (argc, 4);
|
||||
+ TEST_COMPARE_STRING (argv[0], "program");
|
||||
+ TEST_COMPARE_STRING (argv[2], "beta");
|
||||
+ TEST_COMPARE_STRING (argv[3], "gamma");
|
||||
+ TEST_COMPARE_STRING (argv[4], NULL);
|
||||
+ }
|
||||
+ else if (argc >= 2 && strcmp (argv[1], "check-env") == 0)
|
||||
+ printf ("%d %s\n", argc, getenv ("extra"));
|
||||
+ else if (argc >= 2 && strcmp (argv[1], "check-ld.so") == 0)
|
||||
+ TEST_VERIFY (running_via_ldso ());
|
||||
+}
|
||||
+
|
||||
+/* The "recurse" environment variable and the --recurse option
|
||||
+ indicate recursive invocation. */
|
||||
+static int flag_recurse;
|
||||
+#define CMDLINE_OPTIONS \
|
||||
+ { "recurse", no_argument, &flag_recurse, 1 }, \
|
||||
+ /* CMDLINE_OPTION */
|
||||
+
|
||||
+static void
|
||||
+prepare (int argc, char **argv)
|
||||
+{
|
||||
+ if (getenv ("recurse") != NULL || flag_recurse)
|
||||
+ {
|
||||
+ test_subprocess (argc, argv);
|
||||
+ support_record_failure_barrier ();
|
||||
+ exit (0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#define PREPARE prepare
|
||||
+
|
||||
+/* Test wrapping of a non-test program (iconv). This uses posix_spawn
|
||||
+ directly, mainly for illustrative purposes. */
|
||||
+void
|
||||
+test_iconv (void)
|
||||
+{
|
||||
+ char *iconv_prog = xasprintf ("%s/iconv/iconv_prog", support_objdir_root);
|
||||
+ char *argv[] = { (char *) "iconv", (char *) "-f", (char *) "UTF-8",
|
||||
+ (char *) "-t", (char *) "ISO-8859-1", NULL };
|
||||
+ struct support_spawn_wrapped *w
|
||||
+ = support_spawn_wrap (iconv_prog, argv, NULL, support_spawn_wrap_force);
|
||||
+
|
||||
+ /* Set up pipes for stdin, stdout, and stderr. */
|
||||
+ int stdin_pipe[2];
|
||||
+ xpipe (stdin_pipe);
|
||||
+ int stdout_pipe[2];
|
||||
+ xpipe (stdout_pipe);
|
||||
+ int stderr_pipe[2];
|
||||
+ xpipe (stderr_pipe);
|
||||
+
|
||||
+ posix_spawn_file_actions_t fa;
|
||||
+ posix_spawn_file_actions_init (&fa);
|
||||
+ xposix_spawn_file_actions_adddup2 (&fa, stdin_pipe[0], STDIN_FILENO);
|
||||
+ xposix_spawn_file_actions_addclose (&fa, stdin_pipe[0]);
|
||||
+ xposix_spawn_file_actions_addclose (&fa, stdin_pipe[1]);
|
||||
+ xposix_spawn_file_actions_adddup2 (&fa, stdout_pipe[1], STDOUT_FILENO);
|
||||
+ xposix_spawn_file_actions_addclose (&fa, stdout_pipe[0]);
|
||||
+ xposix_spawn_file_actions_addclose (&fa, stdout_pipe[1]);
|
||||
+ xposix_spawn_file_actions_adddup2 (&fa, stderr_pipe[1], STDERR_FILENO);
|
||||
+ xposix_spawn_file_actions_addclose (&fa, stderr_pipe[0]);
|
||||
+ xposix_spawn_file_actions_addclose (&fa, stderr_pipe[1]);
|
||||
+
|
||||
+ pid_t pid = xposix_spawn (w->path, &fa, NULL, w->argv, w->envp);
|
||||
+ posix_spawn_file_actions_destroy (&fa);
|
||||
+
|
||||
+ xclose (stdin_pipe[0]);
|
||||
+ xclose (stdout_pipe[1]);
|
||||
+ xclose (stderr_pipe[1]);
|
||||
+
|
||||
+ /* Write UTF-8 encoding of "äöü\n" to stdin. */
|
||||
+ xwrite (stdin_pipe[1], "\xc3\xa4\xc3\xb6\xc3\xbc\n", 7);
|
||||
+ xclose (stdin_pipe[1]);
|
||||
+
|
||||
+ /* Read the converted output from the pipe. */
|
||||
+ char buf[16];
|
||||
+ ssize_t ret = read (stdout_pipe[0], buf, sizeof (buf));
|
||||
+ xclose (stdout_pipe[0]);
|
||||
+
|
||||
+ /* ISO-8859-1 encoding of "äöü\n". */
|
||||
+ TEST_COMPARE_BLOB (buf, ret, "\xe4\xf6\xfc\n", 4);
|
||||
+
|
||||
+ int status;
|
||||
+ xwaitpid (pid, &status, 0);
|
||||
+ TEST_COMPARE (status, 0);
|
||||
+
|
||||
+ /* Check that nothing has been written to stderr. */
|
||||
+ ret = read (stderr_pipe[0], buf, sizeof (buf));
|
||||
+ TEST_COMPARE (ret, 0);
|
||||
+ xclose (stderr_pipe[0]);
|
||||
+
|
||||
+ support_spawn_wrapped_free (w);
|
||||
+ free (iconv_prog);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ char *program = xasprintf ("%s/support/tst-support_spawn_wrap",
|
||||
+ support_objdir_root);
|
||||
+
|
||||
+ {
|
||||
+ char *env[] = { (char *) "recurse=", (char *) "argc=1", NULL };
|
||||
+ struct support_spawn_wrapped *w
|
||||
+ = support_spawn_wrap (program, NULL, env, 0);
|
||||
+ struct support_capture_subprocess proc
|
||||
+ = support_capture_subprogram (w->path, w->argv, w->envp);
|
||||
+ support_capture_subprocess_check (&proc, "no arguments", 0, sc_allow_none);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+ support_spawn_wrapped_free (w);
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ char *argv[] = { (char *) "program", (char *) "--recurse", NULL };
|
||||
+ struct support_spawn_wrapped *w
|
||||
+ = support_spawn_wrap (program, argv, NULL, 0);
|
||||
+ struct support_capture_subprocess proc
|
||||
+ = support_capture_subprogram (w->path, w->argv, w->envp);
|
||||
+ support_capture_subprocess_check (&proc, "default envvironment", 0,
|
||||
+ sc_allow_none);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+ support_spawn_wrapped_free (w);
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ char *argv[] = { (char *) "program", (char *) "alpha", (char *) "beta",
|
||||
+ (char *) "gamma", NULL };
|
||||
+ char *env[] = { (char *) "recurse=", (char *) "argc=4", NULL };
|
||||
+ struct support_spawn_wrapped *w
|
||||
+ = support_spawn_wrap (program, argv, env, 0);
|
||||
+ struct support_capture_subprocess proc
|
||||
+ = support_capture_subprogram (w->path, w->argv, w->envp);
|
||||
+ support_capture_subprocess_check (&proc, "3 arguments", 0, sc_allow_none);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+ support_spawn_wrapped_free (w);
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ char *argv[] = { (char *) "program", (char *) "check-env", NULL };
|
||||
+ char *env[] = { (char *) "recurse=", (char *) "argc=2",
|
||||
+ (char *) "extra=17", NULL };
|
||||
+ struct support_spawn_wrapped *w
|
||||
+ = support_spawn_wrap (program, argv, env, 0);
|
||||
+ struct support_capture_subprocess proc
|
||||
+ = support_capture_subprogram (w->path, w->argv, w->envp);
|
||||
+ TEST_COMPARE_STRING (proc.out.buffer, "2 17\n");
|
||||
+ support_capture_subprocess_check (&proc, "check-env", 0, sc_allow_stdout);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+ support_spawn_wrapped_free (w);
|
||||
+ }
|
||||
+
|
||||
+ test_iconv ();
|
||||
+
|
||||
+ /* This may trigger EXIT_UNSUPPORTED, so run this before the tests
|
||||
+ that rely on running_via_ldso. */
|
||||
+ TEST_COMPARE (!running_via_ldso (), support_hardcoded_paths_in_test);
|
||||
+
|
||||
+ {
|
||||
+ char *argv[] = { (char *) "program", (char *) "check-ld.so", NULL };
|
||||
+ char *env[] = { (char *) "recurse=", NULL };
|
||||
+ struct support_spawn_wrapped *w
|
||||
+ = support_spawn_wrap (program, argv, env, support_spawn_wrap_force);
|
||||
+ struct support_capture_subprocess proc
|
||||
+ = support_capture_subprogram (w->path, w->argv, w->envp);
|
||||
+ support_capture_subprocess_check (&proc, "check-ld.so", 0, sc_allow_none);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+ support_spawn_wrapped_free (w);
|
||||
+ }
|
||||
+
|
||||
+ free (program);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
168
SOURCES/glibc-RHEL-142196-8.patch
Normal file
168
SOURCES/glibc-RHEL-142196-8.patch
Normal file
@ -0,0 +1,168 @@
|
||||
commit 364426a59ee30ee3e528e5b5cae36b5dee045320
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Feb 2 21:15:48 2026 +0100
|
||||
|
||||
elf: Add test case for LD_PROFILE/LD_PROFILE_OUTPUT interaction
|
||||
|
||||
This verifies that LD_PROFILE is correctly ignored if LD_PROFILE_OUTPUT
|
||||
is not set.
|
||||
|
||||
The test was initially auto-generated, then heavily edited and re-edited
|
||||
for brevity and clarity. The test uses glibc-specific interfaces
|
||||
(including one that did not exist at all a couple of hours ago), so
|
||||
this should be unproblematic.
|
||||
|
||||
diff -Nrup a/elf/Makefile b/elf/Makefile
|
||||
--- a/elf/Makefile 2026-02-23 12:26:54.652168428 -0500
|
||||
+++ b/elf/Makefile 2026-02-23 12:30:15.356267040 -0500
|
||||
@@ -442,6 +442,7 @@ tests += \
|
||||
tst-initorder \
|
||||
tst-initorder2 \
|
||||
tst-latepthread \
|
||||
+ tst-ld_profile \
|
||||
tst-main1 \
|
||||
tst-nodelete2 \
|
||||
tst-nodelete-dlclose \
|
||||
diff -Nrup a/elf/tst-ld_profile.c b/elf/tst-ld_profile.c
|
||||
--- a/elf/tst-ld_profile.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/elf/tst-ld_profile.c 2026-02-23 12:27:49.770154596 -0500
|
||||
@@ -0,0 +1,139 @@
|
||||
+/* Test LD_PROFILE/LD_PROFILE_OUTPUT interaction (bug 33797).
|
||||
+ 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 <gnu/lib-names.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/capture_subprocess.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/subprocess.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Expected profile file path (based on LD_PROFILE_OUTPUT and LIBC_SO). */
|
||||
+static char *profile_file_path;
|
||||
+
|
||||
+/* Path to this test program for recursive invocation. */
|
||||
+static char *program;
|
||||
+
|
||||
+/* LD_PROFILE_OUTPUT environment variable setting. */
|
||||
+static char *ld_profile_output_env;
|
||||
+
|
||||
+/* Run the test program with the specified environment array. */
|
||||
+static struct support_capture_subprocess
|
||||
+run_test_program (char *env[])
|
||||
+{
|
||||
+ /* Make sure the the potential output file does not exist. */
|
||||
+ unlink (profile_file_path);
|
||||
+
|
||||
+/* Command line arguments for recursive invocation. This turns the
|
||||
+ test program in a no-op (with LD_PROFILE output the only side effect). */
|
||||
+ static char *recurse_argv[] =
|
||||
+ {
|
||||
+ (char *) "tst-ld_profile", (char *) "recurse", NULL
|
||||
+ };
|
||||
+ struct support_spawn_wrapped *w
|
||||
+ = support_spawn_wrap (program, recurse_argv, env, 0);
|
||||
+ struct support_capture_subprocess proc
|
||||
+ = support_capture_subprogram (w->path, w->argv, w->envp);
|
||||
+ support_spawn_wrapped_free (w);
|
||||
+
|
||||
+ return proc;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_profile_without_output (void)
|
||||
+{
|
||||
+ char *env[] = { (char *) "LD_PROFILE=" LIBC_SO, NULL };
|
||||
+ struct support_capture_subprocess proc = run_test_program (env);
|
||||
+ const char *expected_warning =
|
||||
+ "warning: LD_PROFILE ignored because LD_PROFILE_OUTPUT not specified\n";
|
||||
+ TEST_COMPARE_STRING (proc.err.buffer, expected_warning);
|
||||
+ support_capture_subprocess_check (&proc,
|
||||
+ "LD_PROFILE without LD_PROFILE_OUTPUT",
|
||||
+ 0, sc_allow_stderr);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+
|
||||
+ TEST_VERIFY (access (profile_file_path, F_OK) != 0);
|
||||
+ /* Also check the old /var/tmp path. */
|
||||
+ TEST_VERIFY (access ("/var/tmp/" LIBC_SO ".profile", F_OK) != 0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_profile_with_output (void)
|
||||
+{
|
||||
+ char *env[] = { (char *) "LD_PROFILE=" LIBC_SO, ld_profile_output_env, NULL };
|
||||
+ struct support_capture_subprocess proc = run_test_program (env);
|
||||
+ support_capture_subprocess_check (&proc, "LD_PROFILE with LD_PROFILE_OUTPUT",
|
||||
+ 0, sc_allow_none);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+
|
||||
+ /* This asserts that the file was created. */
|
||||
+ TEST_COMPARE (unlink (profile_file_path), 0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_output_without_profile (void)
|
||||
+{
|
||||
+ char *env[] = { ld_profile_output_env, NULL };
|
||||
+ struct support_capture_subprocess proc = run_test_program (env);
|
||||
+ support_capture_subprocess_check (&proc,
|
||||
+ "LD_PROFILE_OUTPUT without LD_PROFILE",
|
||||
+ 0, sc_allow_none);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+
|
||||
+ TEST_VERIFY (access (profile_file_path, F_OK) != 0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+prepare (int argc, char **argv)
|
||||
+{
|
||||
+ /* Do nothing on recursive invocation. */
|
||||
+ if (argc >= 2 && strcmp (argv[1], "recurse") == 0)
|
||||
+ exit (0);
|
||||
+}
|
||||
+
|
||||
+#define PREPARE prepare
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ if (access ("/var/tmp/" LIBC_SO ".profile", F_OK) == 0)
|
||||
+ FAIL_UNSUPPORTED ("/var/tmp/" LIBC_SO ".profile exists");
|
||||
+
|
||||
+ /* Temporary directory for the profile output. */
|
||||
+ char *profile_output_dir = support_create_temp_directory ("tst-ld_profile");
|
||||
+ profile_file_path = xasprintf ("%s/%s.profile", profile_output_dir, LIBC_SO);
|
||||
+ ld_profile_output_env = xasprintf ("LD_PROFILE_OUTPUT=%s",
|
||||
+ profile_output_dir);
|
||||
+ program = xasprintf ("%s/elf/tst-ld_profile", support_objdir_root);
|
||||
+
|
||||
+ test_profile_without_output ();
|
||||
+ test_profile_with_output ();
|
||||
+ test_output_without_profile ();
|
||||
+
|
||||
+ free (program);
|
||||
+ free (ld_profile_output_env);
|
||||
+ free (profile_file_path);
|
||||
+ free (profile_output_dir);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
52
SOURCES/glibc-RHEL-142209.patch
Normal file
52
SOURCES/glibc-RHEL-142209.patch
Normal file
@ -0,0 +1,52 @@
|
||||
commit 55e85c1e48c2aae71c0b5907fd22a3e9b978b6e8
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Fri Jul 18 17:03:04 2025 -0700
|
||||
|
||||
io/tst-stat.c: Use a temporary directory for symlink test
|
||||
|
||||
Call support_create_temp_directory to create a temporary directory for
|
||||
symlink test, instead of a fixed file in the glibc source tree, to avoid
|
||||
the race condition when there are more than one glibc tests running at the
|
||||
same time with the same glibc source tree. This fixes BZ #33178.
|
||||
|
||||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
Reviewed-by: Andreas K. Huettel <dilfridge@gentoo.org>
|
||||
|
||||
diff --git a/io/tst-stat.c b/io/tst-stat.c
|
||||
index 269c62d29e7e93fa..af31b4b39d3d65a8 100644
|
||||
--- a/io/tst-stat.c
|
||||
+++ b/io/tst-stat.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <sys/sysmacros.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
+#include <stdlib.h>
|
||||
|
||||
static void
|
||||
stat_check (int fd, const char *path, struct stat *st)
|
||||
@@ -78,7 +79,8 @@ static int
|
||||
do_test (void)
|
||||
{
|
||||
char *path;
|
||||
- const char *linkame = "tst-fstat.linkname";
|
||||
+ char *tempdir = support_create_temp_directory ("tst-stat-");
|
||||
+ char *linkname = xasprintf ("%s/tst-fstat.linkname", tempdir);
|
||||
int fd = create_temp_file ("tst-fstat.", &path);
|
||||
TEST_VERIFY_EXIT (fd >= 0);
|
||||
support_write_file_string (path, "abc");
|
||||
@@ -122,9 +124,12 @@ do_test (void)
|
||||
}
|
||||
}
|
||||
|
||||
- TEST_COMPARE (symlink ("tst-fstat.target", linkame), 0);
|
||||
- add_temp_file (linkame);
|
||||
- fstatat_link (linkame, &st);
|
||||
+ TEST_COMPARE (symlink ("tst-fstat.target", linkname), 0);
|
||||
+ add_temp_file (linkname);
|
||||
+ fstatat_link (linkname, &st);
|
||||
+
|
||||
+ free (linkname);
|
||||
+ free (tempdir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
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>
|
||||
25
SOURCES/glibc-RHEL-150269-1.patch
Normal file
25
SOURCES/glibc-RHEL-150269-1.patch
Normal file
@ -0,0 +1,25 @@
|
||||
commit 0d83b349fa7340475406b2fe933c7467e4584091
|
||||
Author: Andreas Schwab <schwab@suse.de>
|
||||
Date: Wed Mar 15 11:44:24 2023 +0100
|
||||
|
||||
getlogin_r: fix missing fallback if loginuid is unset (bug 30235)
|
||||
|
||||
When /proc/self/loginuid is not set, we should still fall back to using
|
||||
the traditional utmp lookup, instead of failing right away.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/getlogin_r.c b/sysdeps/unix/sysv/linux/getlogin_r.c
|
||||
index dc0ca388b20d42c3..ff60fbbc726d7e7a 100644
|
||||
--- a/sysdeps/unix/sysv/linux/getlogin_r.c
|
||||
+++ b/sysdeps/unix/sysv/linux/getlogin_r.c
|
||||
@@ -59,10 +59,7 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||||
value of, (uid_t) -1, so check if that value is set and return early to
|
||||
avoid making unneeded nss lookups. */
|
||||
if (uid == (uid_t) -1)
|
||||
- {
|
||||
- __set_errno (ENXIO);
|
||||
- return ENXIO;
|
||||
- }
|
||||
+ return -1;
|
||||
|
||||
struct passwd pwd;
|
||||
struct passwd *tpwd;
|
||||
112
SOURCES/glibc-RHEL-150269-2.patch
Normal file
112
SOURCES/glibc-RHEL-150269-2.patch
Normal file
@ -0,0 +1,112 @@
|
||||
commit 7bb859f4198d0be19c31a9937eae4f6c2c9a079e
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Feb 13 09:02:07 2026 +0100
|
||||
|
||||
nss: Introduce dedicated struct nss_database_for_fork type
|
||||
|
||||
The initialized field in struct nss_database_data is rather confusing
|
||||
because it is not used by the regular NSS code, only by the fork
|
||||
state synchronization code. Introduce a separate type and place
|
||||
the initialized field there.
|
||||
|
||||
Reviewed-by: Sam James <sam@gentoo.org>
|
||||
|
||||
diff --git a/nss/nss_database.c b/nss/nss_database.c
|
||||
index e807e9d84ca03680..293e8457d70c00ba 100644
|
||||
--- a/nss/nss_database.c
|
||||
+++ b/nss/nss_database.c
|
||||
@@ -56,7 +56,6 @@ global_state_allocate (void *closure)
|
||||
{
|
||||
result->data.nsswitch_conf.size = -1; /* Force reload. */
|
||||
memset (result->data.services, 0, sizeof (result->data.services));
|
||||
- result->data.initialized = true;
|
||||
result->data.reload_disabled = false;
|
||||
__libc_lock_init (result->lock);
|
||||
result->root_ino = 0;
|
||||
@@ -451,8 +450,8 @@ nss_database_check_reload_and_get (struct nss_database_state *local,
|
||||
/* Avoid overwriting the global configuration until we have loaded
|
||||
everything successfully. Otherwise, if the file change
|
||||
information changes back to what is in the global configuration,
|
||||
- the lookups would use the partially-written configuration. */
|
||||
- struct nss_database_data staging = { .initialized = true, };
|
||||
+ the lookups would use the partially-written configuration. */
|
||||
+ struct nss_database_data staging = { };
|
||||
|
||||
bool ok = nss_database_reload (&staging, &initial);
|
||||
|
||||
@@ -503,7 +502,7 @@ __nss_database_freeres (void)
|
||||
}
|
||||
|
||||
void
|
||||
-__nss_database_fork_prepare_parent (struct nss_database_data *data)
|
||||
+__nss_database_fork_prepare_parent (struct nss_database_for_fork *data)
|
||||
{
|
||||
/* Do not use allocate_once to trigger loading unnecessarily. */
|
||||
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
|
||||
@@ -515,20 +514,21 @@ __nss_database_fork_prepare_parent (struct nss_database_data *data)
|
||||
because it avoids acquiring the lock during the actual
|
||||
fork. */
|
||||
__libc_lock_lock (local->lock);
|
||||
- *data = local->data;
|
||||
+ data->data = local->data;
|
||||
__libc_lock_unlock (local->lock);
|
||||
+ data->initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
-__nss_database_fork_subprocess (struct nss_database_data *data)
|
||||
+__nss_database_fork_subprocess (struct nss_database_for_fork *data)
|
||||
{
|
||||
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
|
||||
if (data->initialized)
|
||||
{
|
||||
/* Restore the state at the point of the fork. */
|
||||
assert (local != NULL);
|
||||
- local->data = *data;
|
||||
+ local->data = data->data;
|
||||
__libc_lock_init (local->lock);
|
||||
}
|
||||
else if (local != NULL)
|
||||
diff --git a/nss/nss_database.h b/nss/nss_database.h
|
||||
index d4b23b5295110c1c..349a793a6ef011e4 100644
|
||||
--- a/nss/nss_database.h
|
||||
+++ b/nss/nss_database.h
|
||||
@@ -73,15 +73,21 @@ struct nss_database_data
|
||||
struct file_change_detection nsswitch_conf;
|
||||
nss_action_list services[NSS_DATABASE_COUNT];
|
||||
int reload_disabled; /* Actually bool; int for atomic access. */
|
||||
- bool initialized;
|
||||
+};
|
||||
+
|
||||
+/* Use to store a consistent state snapshot across fork. */
|
||||
+struct nss_database_for_fork
|
||||
+{
|
||||
+ bool initialized; /* Set to true if the data field below is initialized. */
|
||||
+ struct nss_database_data data;
|
||||
};
|
||||
|
||||
/* Called by fork in the parent process, before forking. */
|
||||
-void __nss_database_fork_prepare_parent (struct nss_database_data *data)
|
||||
+void __nss_database_fork_prepare_parent (struct nss_database_for_fork *)
|
||||
attribute_hidden;
|
||||
|
||||
/* Called by fork in the new subprocess, after forking. */
|
||||
-void __nss_database_fork_subprocess (struct nss_database_data *data)
|
||||
+void __nss_database_fork_subprocess (struct nss_database_for_fork *)
|
||||
attribute_hidden;
|
||||
|
||||
#endif /* _NSS_DATABASE_H */
|
||||
diff --git a/posix/fork.c b/posix/fork.c
|
||||
index 5a5baf63aa971b43..b996f4c63acc4e4b 100644
|
||||
--- a/posix/fork.c
|
||||
+++ b/posix/fork.c
|
||||
@@ -50,7 +50,7 @@ __libc_fork (void)
|
||||
|
||||
lastrun = __run_prefork_handlers (multiple_threads);
|
||||
|
||||
- struct nss_database_data nss_database_data;
|
||||
+ struct nss_database_for_fork nss_database_data;
|
||||
|
||||
/* If we are not running multiple threads, we do not have to
|
||||
preserve lock state. If fork runs from a signal handler, only
|
||||
71
SOURCES/glibc-RHEL-150269-3.patch
Normal file
71
SOURCES/glibc-RHEL-150269-3.patch
Normal file
@ -0,0 +1,71 @@
|
||||
commit 28660f4b45afa8921c2faebaec2846f95f670ba0
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Feb 13 09:02:07 2026 +0100
|
||||
|
||||
Linux: In getlogin_r, use utmp fallback only for specific errors
|
||||
|
||||
Most importantly, if getwpuid_r fails, it does not make sense to retry
|
||||
via utmp because the user ID obtained from there is less reliable than
|
||||
the one from /proc/self/loginuid.
|
||||
|
||||
Reviewed-by: Sam James <sam@gentoo.org>
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/getlogin_r.c b/sysdeps/unix/sysv/linux/getlogin_r.c
|
||||
index ff60fbbc726d7e7a..85e54b3879ff986a 100644
|
||||
--- a/sysdeps/unix/sysv/linux/getlogin_r.c
|
||||
+++ b/sysdeps/unix/sysv/linux/getlogin_r.c
|
||||
@@ -37,7 +37,12 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||||
{
|
||||
int fd = __open_nocancel ("/proc/self/loginuid", O_RDONLY);
|
||||
if (fd == -1)
|
||||
- return -1;
|
||||
+ {
|
||||
+ if (errno == ENOENT)
|
||||
+ /* Trigger utmp fallback. */
|
||||
+ return -1;
|
||||
+ return errno;
|
||||
+ }
|
||||
|
||||
/* We are reading a 32-bit number. 12 bytes are enough for the text
|
||||
representation. If not, something is wrong. */
|
||||
@@ -45,6 +50,8 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||||
ssize_t n = TEMP_FAILURE_RETRY (__read_nocancel (fd, uidbuf,
|
||||
sizeof (uidbuf)));
|
||||
__close_nocancel_nostatus (fd);
|
||||
+ if (n < 0)
|
||||
+ return errno;
|
||||
|
||||
uid_t uid;
|
||||
char *endp;
|
||||
@@ -53,12 +60,13 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||||
|| (uidbuf[n] = '\0',
|
||||
uid = strtoul (uidbuf, &endp, 10),
|
||||
endp == uidbuf || *endp != '\0'))
|
||||
- return -1;
|
||||
+ return EINVAL;
|
||||
|
||||
/* If there is no login uid, linux sets /proc/self/loginid to the sentinel
|
||||
value of, (uid_t) -1, so check if that value is set and return early to
|
||||
avoid making unneeded nss lookups. */
|
||||
if (uid == (uid_t) -1)
|
||||
+ /* Trigger utmp fallback. */
|
||||
return -1;
|
||||
|
||||
struct passwd pwd;
|
||||
@@ -78,9 +86,14 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||||
}
|
||||
}
|
||||
|
||||
- if (res != 0 || tpwd == NULL)
|
||||
+ if (res != 0)
|
||||
+ {
|
||||
+ result = res;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (tpwd == NULL)
|
||||
{
|
||||
- result = -1;
|
||||
+ result = ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
405
SOURCES/glibc-RHEL-150269-4.patch
Normal file
405
SOURCES/glibc-RHEL-150269-4.patch
Normal file
@ -0,0 +1,405 @@
|
||||
commit 5b713b49443eb6a4e54e50e2f0147105f86dab02
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Feb 13 09:02:07 2026 +0100
|
||||
|
||||
nss: Missing checks in __nss_configure_lookup, __nss_database_get (bug 28940)
|
||||
|
||||
This avoids a null pointer dereference in the
|
||||
nss_database_check_reload_and_get function, and assertion failures.
|
||||
|
||||
Reviewed-by: Sam James <sam@gentoo.org>
|
||||
|
||||
Conflicts:
|
||||
nss/Makefile
|
||||
(fixup context)
|
||||
|
||||
diff --git a/nss/Makefile b/nss/Makefile
|
||||
index dbdba5bf815136ef..4d128da0a366301f 100644
|
||||
--- a/nss/Makefile
|
||||
+++ b/nss/Makefile
|
||||
@@ -62,6 +62,7 @@ tests := \
|
||||
test-digits-dots \
|
||||
test-netdb \
|
||||
tst-nss-getpwent \
|
||||
+ tst-nss-malloc-failure-getlogin_r \
|
||||
tst-nss-test1 \
|
||||
tst-nss-test2 \
|
||||
tst-nss-test4 \
|
||||
diff --git a/nss/nss_database.c b/nss/nss_database.c
|
||||
index 293e8457d70c00ba..251e47fdcf1ecf54 100644
|
||||
--- a/nss/nss_database.c
|
||||
+++ b/nss/nss_database.c
|
||||
@@ -250,9 +250,12 @@ __nss_configure_lookup (const char *dbname, const char *service_line)
|
||||
|
||||
/* Force any load/cache/read whatever to happen, so we can override
|
||||
it. */
|
||||
- __nss_database_get (db, &result);
|
||||
+ if (!__nss_database_get (db, &result))
|
||||
+ return -1;
|
||||
|
||||
local = nss_database_state_get ();
|
||||
+ if (local == NULL)
|
||||
+ return -1;
|
||||
|
||||
result = __nss_action_parse (service_line);
|
||||
if (result == NULL)
|
||||
@@ -477,6 +480,8 @@ bool
|
||||
__nss_database_get (enum nss_database db, nss_action_list *actions)
|
||||
{
|
||||
struct nss_database_state *local = nss_database_state_get ();
|
||||
+ if (local == NULL)
|
||||
+ return false;
|
||||
return nss_database_check_reload_and_get (local, actions, db);
|
||||
}
|
||||
libc_hidden_def (__nss_database_get)
|
||||
diff --git a/nss/tst-nss-malloc-failure-getlogin_r.c b/nss/tst-nss-malloc-failure-getlogin_r.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..0e2985ad57b07fce
|
||||
--- /dev/null
|
||||
+++ b/nss/tst-nss-malloc-failure-getlogin_r.c
|
||||
@@ -0,0 +1,345 @@
|
||||
+/* Test NSS/getlogin_r with injected allocation failures (bug 28940).
|
||||
+ 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 <errno.h>
|
||||
+#include <getopt.h>
|
||||
+#include <malloc.h>
|
||||
+#include <netdb.h>
|
||||
+#include <nss.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/namespace.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/xstdio.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* This test calls getpwuid_r via getlogin_r (on Linux).
|
||||
+
|
||||
+ This test uses the NSS system configuration to exercise that code
|
||||
+ path. It means that it can fail (crash) if malloc failure is not
|
||||
+ handled by NSS modules for the passwd database. */
|
||||
+
|
||||
+/* Data structure allocated via MAP_SHARED, so that writes from the
|
||||
+ subprocess are visible. */
|
||||
+struct shared_data
|
||||
+{
|
||||
+ /* Number of tracked allocations performed so far. */
|
||||
+ volatile unsigned int allocation_count;
|
||||
+
|
||||
+ /* If this number is reached, one allocation fails. */
|
||||
+ volatile unsigned int failing_allocation;
|
||||
+
|
||||
+ /* The number of allocations performed during initialization
|
||||
+ (before the actual getlogin_r call). */
|
||||
+ volatile unsigned int init_allocation_count;
|
||||
+
|
||||
+ /* Error code of an expected getlogin_r failure. */
|
||||
+ volatile int expected_failure;
|
||||
+
|
||||
+ /* The subprocess stores the expected name here. */
|
||||
+ char name[100];
|
||||
+};
|
||||
+
|
||||
+/* Allocation count in shared mapping. */
|
||||
+static struct shared_data *shared;
|
||||
+
|
||||
+/* Returns true if a failure should be injected for this allocation. */
|
||||
+static bool
|
||||
+fail_this_allocation (void)
|
||||
+{
|
||||
+ if (shared != NULL)
|
||||
+ {
|
||||
+ unsigned int count = shared->allocation_count;
|
||||
+ shared->allocation_count = count + 1;
|
||||
+ return count == shared->failing_allocation;
|
||||
+ }
|
||||
+ else
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+/* Failure-injecting wrappers for allocation functions used by glibc. */
|
||||
+
|
||||
+void *
|
||||
+malloc (size_t size)
|
||||
+{
|
||||
+ if (fail_this_allocation ())
|
||||
+ {
|
||||
+ errno = ENOMEM;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ extern __typeof (malloc) __libc_malloc;
|
||||
+ return __libc_malloc (size);
|
||||
+}
|
||||
+
|
||||
+void *
|
||||
+calloc (size_t a, size_t b)
|
||||
+{
|
||||
+ if (fail_this_allocation ())
|
||||
+ {
|
||||
+ errno = ENOMEM;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ extern __typeof (calloc) __libc_calloc;
|
||||
+ return __libc_calloc (a, b);
|
||||
+}
|
||||
+
|
||||
+void *
|
||||
+realloc (void *ptr, size_t size)
|
||||
+{
|
||||
+ if (fail_this_allocation ())
|
||||
+ {
|
||||
+ errno = ENOMEM;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ extern __typeof (realloc) __libc_realloc;
|
||||
+ return __libc_realloc (ptr, size);
|
||||
+}
|
||||
+
|
||||
+/* No-op subprocess to verify that support_isolate_in_subprocess does
|
||||
+ not perform any heap allocations. */
|
||||
+static void
|
||||
+no_op (void *ignored)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+/* Perform a getlogin_r call in a subprocess, to obtain the number of
|
||||
+ allocations used and the expected result of a successful call. */
|
||||
+static void
|
||||
+initialize (void *configure_lookup)
|
||||
+{
|
||||
+ shared->init_allocation_count = 0;
|
||||
+ if (configure_lookup != NULL)
|
||||
+ {
|
||||
+ TEST_COMPARE (__nss_configure_lookup ("passwd", configure_lookup), 0);
|
||||
+ shared->init_allocation_count = shared->allocation_count;
|
||||
+ }
|
||||
+
|
||||
+ shared->name[0] = '\0';
|
||||
+ int ret = getlogin_r (shared->name, sizeof (shared->name));
|
||||
+ if (ret != 0)
|
||||
+ {
|
||||
+ printf ("info: getlogin_r failed: %s (%d)\n",
|
||||
+ strerrorname_np (ret), ret);
|
||||
+ shared->expected_failure = ret;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ shared->expected_failure = 0;
|
||||
+ if (shared->name[0] == '\0')
|
||||
+ FAIL ("error: getlogin_r succeeded without result\n");
|
||||
+ else
|
||||
+ printf ("info: getlogin_r: \"%s\"\n", shared->name);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Perform getlogin_r in a subprocess with fault injection. */
|
||||
+static void
|
||||
+test_in_subprocess (void *configure_lookup)
|
||||
+{
|
||||
+ if (configure_lookup != NULL
|
||||
+ && __nss_configure_lookup ("passwd", configure_lookup) < 0)
|
||||
+ {
|
||||
+ printf ("info: __nss_configure_lookup failed: %s (%d)\n",
|
||||
+ strerrorname_np (errno), errno);
|
||||
+ TEST_COMPARE (errno, ENOMEM);
|
||||
+ TEST_VERIFY (shared->allocation_count <= shared->init_allocation_count);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ unsigned int inject_at = shared->failing_allocation;
|
||||
+ char name[sizeof (shared->name)] = "name not set";
|
||||
+ int ret = getlogin_r (name, sizeof (name));
|
||||
+ shared->failing_allocation = ~0U;
|
||||
+
|
||||
+ if (ret == 0)
|
||||
+ {
|
||||
+ TEST_COMPARE (shared->expected_failure, 0);
|
||||
+ TEST_COMPARE_STRING (name, shared->name);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ printf ("info: allocation %u failure results in error %s (%d)\n",
|
||||
+ inject_at, strerrorname_np (ret), ret);
|
||||
+
|
||||
+ if (ret != ENOMEM)
|
||||
+ {
|
||||
+ if (shared->expected_failure != 0)
|
||||
+ TEST_COMPARE (ret, shared->expected_failure);
|
||||
+ else if (configure_lookup == NULL)
|
||||
+ /* The ENOENT failure can happen due to an issue related
|
||||
+ to bug 22041: dlopen failure does not result in ENOMEM. */
|
||||
+ TEST_COMPARE (ret, ENOENT);
|
||||
+ else
|
||||
+ FAIL ("unexpected getlogin_r error");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (shared->expected_failure == 0)
|
||||
+ {
|
||||
+ /* The second call should succeed. */
|
||||
+ puts ("info: about to perform second getlogin_r call");
|
||||
+ ret = getlogin_r (name, sizeof (name));
|
||||
+ if (configure_lookup == NULL)
|
||||
+ {
|
||||
+ /* This check can fail due to bug 22041 if the malloc error
|
||||
+ injection causes a failure internally in dlopen. */
|
||||
+ if (ret != 0)
|
||||
+ {
|
||||
+ printf ("warning: second getlogin_r call failed with %s (%d)\n",
|
||||
+ strerrorname_np (ret), ret);
|
||||
+ TEST_COMPARE (ret, ENOENT);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ /* If __nss_configure_lookup has been called, the error caching
|
||||
+ bug does not happen because nss_files is built-in, and the
|
||||
+ second getlogin_r is expected to succeed. */
|
||||
+ TEST_COMPARE (ret, 0);
|
||||
+ if (ret == 0)
|
||||
+ TEST_COMPARE_STRING (name, shared->name);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Set by the --failing-allocation command line option. Together with
|
||||
+ --direct, this can be used to trigger an allocation failure in the
|
||||
+ original process, which may help with debugging. */
|
||||
+static int option_failing_allocation = -1;
|
||||
+
|
||||
+/* Set by --override, to be used with --failing-allocation. Turns on
|
||||
+ the __nss_configure_lookup call for passwd/files, which is disabled
|
||||
+ by default. */
|
||||
+static int option_override = 0;
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ char files[] = "files";
|
||||
+
|
||||
+ if (option_failing_allocation >= 0)
|
||||
+ {
|
||||
+ /* The test was invoked with --failing-allocation. Perform just
|
||||
+ one test, using the original nsswitch.conf. This is a
|
||||
+ condensed version of the probing/testing loop below. */
|
||||
+ printf ("info: testing with failing allocation %d\n",
|
||||
+ option_failing_allocation);
|
||||
+ shared = support_shared_allocate (sizeof (*shared));
|
||||
+ shared->failing_allocation = ~0U;
|
||||
+ char *configure_lookup = option_override ? files : NULL;
|
||||
+ support_isolate_in_subprocess (initialize, configure_lookup);
|
||||
+ shared->allocation_count = 0;
|
||||
+ shared->failing_allocation = option_failing_allocation;
|
||||
+ test_in_subprocess (configure_lookup); /* No subprocess. */
|
||||
+ support_shared_free (shared);
|
||||
+ shared = NULL;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ bool any_success = false;
|
||||
+
|
||||
+ for (int do_configure_lookup = 0; do_configure_lookup < 2;
|
||||
+ ++do_configure_lookup)
|
||||
+ {
|
||||
+ if (do_configure_lookup)
|
||||
+ puts ("info: testing with nsswitch.conf override");
|
||||
+ else
|
||||
+ puts ("info: testing with original nsswitch.conf");
|
||||
+
|
||||
+ char *configure_lookup = do_configure_lookup ? files : NULL;
|
||||
+
|
||||
+ shared = support_shared_allocate (sizeof (*shared));
|
||||
+
|
||||
+ /* Disable fault injection. */
|
||||
+ shared->failing_allocation = ~0U;
|
||||
+
|
||||
+ support_isolate_in_subprocess (no_op, NULL);
|
||||
+ TEST_COMPARE (shared->allocation_count, 0);
|
||||
+
|
||||
+ support_isolate_in_subprocess (initialize, configure_lookup);
|
||||
+
|
||||
+ if (shared->name[0] != '\0')
|
||||
+ any_success = true;
|
||||
+
|
||||
+ /* The number of allocations in the successful case. Once the
|
||||
+ number of expected allocations is exceeded, injecting further
|
||||
+ failures does not make a difference (assuming that the number
|
||||
+ of malloc calls is deterministic). */
|
||||
+ unsigned int maximum_allocation_count = shared->allocation_count;
|
||||
+ printf ("info: initial getlogin_r performed %u allocations\n",
|
||||
+ maximum_allocation_count);
|
||||
+
|
||||
+ for (unsigned int inject_at = 0; inject_at <= maximum_allocation_count;
|
||||
+ ++inject_at)
|
||||
+ {
|
||||
+ printf ("info: running fault injection at allocation %u\n",
|
||||
+ inject_at);
|
||||
+ shared->allocation_count = 0;
|
||||
+ shared->failing_allocation = inject_at;
|
||||
+ support_isolate_in_subprocess (test_in_subprocess, configure_lookup);
|
||||
+ }
|
||||
+
|
||||
+ support_shared_free (shared);
|
||||
+ shared = NULL;
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ FILE *fp = fopen (_PATH_NSSWITCH_CONF, "r");
|
||||
+ if (fp == NULL)
|
||||
+ printf ("info: no %s file\n", _PATH_NSSWITCH_CONF);
|
||||
+ else
|
||||
+ {
|
||||
+ printf ("info: %s contents follows\n", _PATH_NSSWITCH_CONF);
|
||||
+ int last_ch = '\n';
|
||||
+ while (true)
|
||||
+ {
|
||||
+ int ch = fgetc (fp);
|
||||
+ if (ch == EOF)
|
||||
+ break;
|
||||
+ putchar (ch);
|
||||
+ last_ch = ch;
|
||||
+ }
|
||||
+ if (last_ch != '\n')
|
||||
+ putchar ('\n');
|
||||
+ printf ("(end of %s contents)\n", _PATH_NSSWITCH_CONF);
|
||||
+ xfclose (fp);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ support_record_failure_barrier ();
|
||||
+
|
||||
+ if (!any_success)
|
||||
+ FAIL_UNSUPPORTED ("no successful getlogin_r calls");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+cmdline_process (int c)
|
||||
+{
|
||||
+ if (c == 'F')
|
||||
+ option_failing_allocation = atoi (optarg);
|
||||
+}
|
||||
+
|
||||
+#define CMDLINE_OPTIONS \
|
||||
+ { "failing-allocation", required_argument, NULL, 'F' }, \
|
||||
+ { "override", no_argument, &option_override, 1 },
|
||||
+
|
||||
+#define CMDLINE_PROCESS cmdline_process
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
249
SOURCES/glibc-RHEL-153056-1.patch
Normal file
249
SOURCES/glibc-RHEL-153056-1.patch
Normal file
@ -0,0 +1,249 @@
|
||||
commit 8ca2fe7e96c0ccf04d32d7002d7a6d9edcb9f8ee
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
Date: Fri Oct 10 17:15:27 2025 +0200
|
||||
|
||||
resolv: Add tests for getaddrinfo returning EAI_AGAIN [BZ #16849]
|
||||
|
||||
This patch adds two tests that verify correct behavior of getaddrinfo
|
||||
when DNS resolution fails with a temporary error. Both tests ensure
|
||||
that getaddrinfo returns EAI_AGAIN in cases where no valid address can
|
||||
be resolved due to network or resolver failure.
|
||||
|
||||
* tst-getaddrinfo-eai-again.c
|
||||
Runs inside the glibc test-container without any DNS server
|
||||
configured. The test performs queries using AF_INET, AF_INET6,
|
||||
and AF_UNSPEC and verifies that getaddrinfo returns EAI_AGAIN
|
||||
when resolution fails.
|
||||
|
||||
* tst-getaddrinfo-eai-again-timeout.c
|
||||
Runs outside of the container but uses the resolv_test framework
|
||||
to simulate network failures. The test covers two failure modes:
|
||||
- No response from the server (resolv_response_drop)
|
||||
- Zero-length reply from the server
|
||||
In both cases, getaddrinfo is expected to return EAI_AGAIN.
|
||||
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||||
index f3f5c260d0b7471f..cb1ff182dfdd4572 100644
|
||||
--- a/resolv/Makefile
|
||||
+++ b/resolv/Makefile
|
||||
@@ -80,7 +80,10 @@ routines_no_fortify += \
|
||||
# routines_no_fortify
|
||||
|
||||
tests = tst-aton tst-leaks tst-inet_ntop
|
||||
-tests-container = tst-leaks2
|
||||
+tests-container += \
|
||||
+ tst-getaddrinfo-eai-again \
|
||||
+ tst-leaks2 \
|
||||
+ # tests-container
|
||||
|
||||
tests-internal += tst-inet_aton_exact
|
||||
|
||||
@@ -136,6 +139,7 @@ tests-static += tst-ns_rr_cursor
|
||||
# These tests need libdl.
|
||||
ifeq (yes,$(build-shared))
|
||||
tests += \
|
||||
+ tst-getaddrinfo-eai-again-timeout \
|
||||
tst-resolv-ai_idn \
|
||||
tst-resolv-ai_idn-latin1 \
|
||||
tst-resolv-ai_idn-nolibidn2 \
|
||||
@@ -268,6 +272,8 @@ $(objpfx)mtrace-tst-resolv-res_ninit.out: $(objpfx)tst-resolv-res_ninit.out
|
||||
|
||||
$(objpfx)tst-bug18665-tcp: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-bug18665: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
+$(objpfx)tst-getaddrinfo-eai-again-timeout: \
|
||||
+ $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-ai_idn: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-ai_idn-latin1: \
|
||||
$(objpfx)libresolv.so $(shared-thread-library)
|
||||
diff --git a/resolv/tst-getaddrinfo-eai-again-timeout.c b/resolv/tst-getaddrinfo-eai-again-timeout.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..ec4a6563b7b5ae51
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-getaddrinfo-eai-again-timeout.c
|
||||
@@ -0,0 +1,122 @@
|
||||
+/* Test for BZ #16849. Verify that getaddrinfo correctly returns
|
||||
+ EAI_AGAIN when DNS resolution fails due to timeout or malformed
|
||||
+ responses.
|
||||
+
|
||||
+ This test uses two simulated failure modes:
|
||||
+ - The DNS server does not respond at all (resolv_response_drop).
|
||||
+ - The DNS server responds with a zero-length packet.
|
||||
+
|
||||
+ 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 <netdb.h>
|
||||
+#include <resolv.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/resolv_test.h>
|
||||
+
|
||||
+/* Track whether the callbacks were actually invoked. */
|
||||
+static volatile bool response_called_drop = false;
|
||||
+static volatile bool response_called_zero_len = false;
|
||||
+
|
||||
+/* Simulate a DNS server that sends a zero-length response. */
|
||||
+static void
|
||||
+response_zero_len (const struct resolv_response_context *ctx,
|
||||
+ struct resolv_response_builder *b,
|
||||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
+{
|
||||
+ response_called_zero_len = true;
|
||||
+ /* Do nothing — zero-length reply. */
|
||||
+}
|
||||
+
|
||||
+/* Simulate a DNS server that drops the request. */
|
||||
+static void
|
||||
+response_drop (const struct resolv_response_context *ctx,
|
||||
+ struct resolv_response_builder *b,
|
||||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
+{
|
||||
+ response_called_drop = true;
|
||||
+ resolv_response_drop (b);
|
||||
+}
|
||||
+
|
||||
+/* Query getaddrinfo for multiple families and expect EAI_AGAIN. */
|
||||
+static void
|
||||
+query_host (const char *host_name)
|
||||
+{
|
||||
+ int family[] = { AF_INET, AF_INET6, AF_UNSPEC };
|
||||
+ const char *family_names[] = { "AF_INET", "AF_INET6", "AF_UNSPEC" };
|
||||
+
|
||||
+ for (int i = 0; i < 3; i++)
|
||||
+ {
|
||||
+ struct addrinfo hints =
|
||||
+ {
|
||||
+ .ai_socktype = 0,
|
||||
+ .ai_protocol = 0,
|
||||
+ .ai_family = family[i],
|
||||
+ .ai_flags = 0,
|
||||
+ };
|
||||
+ struct addrinfo *result;
|
||||
+ int res = getaddrinfo (host_name, NULL, &hints, &result);
|
||||
+ if (res != EAI_AGAIN)
|
||||
+ FAIL_EXIT1 ("getaddrinfo (%s, %s) returned %s, expected EAI_AGAIN",
|
||||
+ host_name, family_names[i], gai_strerror (res));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Simulate DNS server dropping all queries. */
|
||||
+static void
|
||||
+test_drop (void)
|
||||
+{
|
||||
+ struct resolv_test *aux = resolv_test_start
|
||||
+ ((struct resolv_redirect_config)
|
||||
+ {
|
||||
+ .response_callback = response_drop,
|
||||
+ });
|
||||
+ /* Reduce default timeout to make the test run faster. */
|
||||
+ _res.retrans = 1;
|
||||
+ _res.retry = 1;
|
||||
+ query_host ("site.example");
|
||||
+ resolv_test_end (aux);
|
||||
+}
|
||||
+
|
||||
+/* Simulate DNS server sending zero-length responses. */
|
||||
+static void
|
||||
+test_zero_len_packet (void)
|
||||
+{
|
||||
+ struct resolv_test *aux = resolv_test_start
|
||||
+ ((struct resolv_redirect_config)
|
||||
+ {
|
||||
+ .response_callback = response_zero_len,
|
||||
+ });
|
||||
+ query_host ("site.example");
|
||||
+ resolv_test_end (aux);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ test_drop ();
|
||||
+ test_zero_len_packet ();
|
||||
+
|
||||
+ if (!response_called_drop)
|
||||
+ FAIL_EXIT1 ("response_drop callback was not called");
|
||||
+ if (!response_called_zero_len)
|
||||
+ FAIL_EXIT1 ("response_zero_len callback was not called");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/resolv/tst-getaddrinfo-eai-again.c b/resolv/tst-getaddrinfo-eai-again.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..21daa6c1682d1156
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-getaddrinfo-eai-again.c
|
||||
@@ -0,0 +1,56 @@
|
||||
+/* Test for BZ #16849. Verify that getaddrinfo correctly returns
|
||||
+ EAI_AGAIN error code if DNS query fails due to a network failure.
|
||||
+
|
||||
+ 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 <netdb.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+/* Query getaddrinfo with various address families and verify that
|
||||
+ it returns EAI_AGAIN when DNS resolution fails. */
|
||||
+static void
|
||||
+query_host (const char *host_name)
|
||||
+{
|
||||
+ int family[] = { AF_INET, AF_INET6, AF_UNSPEC };
|
||||
+ const char *family_names[] = { "AF_INET", "AF_INET6", "AF_UNSPEC" };
|
||||
+
|
||||
+ for (int i = 0; i < 3; i++)
|
||||
+ {
|
||||
+ struct addrinfo hints =
|
||||
+ {
|
||||
+ .ai_socktype = 0,
|
||||
+ .ai_protocol = 0,
|
||||
+ .ai_family = family[i],
|
||||
+ .ai_flags = 0,
|
||||
+ };
|
||||
+ struct addrinfo *result;
|
||||
+ int res = getaddrinfo (host_name, NULL, &hints, &result);
|
||||
+ if (res != EAI_AGAIN)
|
||||
+ FAIL_EXIT1 ("getaddrinfo (%s, %s) returned %s, expected EAI_AGAIN",
|
||||
+ host_name, family_names[i], gai_strerror (res));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ query_host ("site.example");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
258
SOURCES/glibc-RHEL-153056-2.patch
Normal file
258
SOURCES/glibc-RHEL-153056-2.patch
Normal file
@ -0,0 +1,258 @@
|
||||
commit c995686e2cbe2a3ab2a11877a61c14a2e1fc35cb
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Mar 3 18:48:47 2026 +0100
|
||||
|
||||
support: no_override_resolv_conf_search flag for resolver test framework
|
||||
|
||||
It is required to test "search ." in /etc/resolv.conf files. The
|
||||
default is to override the search path isolate from unexpected
|
||||
settings in the test execution environment.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
resolv/Makefile
|
||||
(tst-resolv-invalid-cname dependencies were added
|
||||
in a different place on the 2.34 upstream branch)
|
||||
|
||||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||||
index cb1ff182dfdd4572..116ab6a1574eb1ff 100644
|
||||
--- a/resolv/Makefile
|
||||
+++ b/resolv/Makefile
|
||||
@@ -83,6 +83,7 @@ tests = tst-aton tst-leaks tst-inet_ntop
|
||||
tests-container += \
|
||||
tst-getaddrinfo-eai-again \
|
||||
tst-leaks2 \
|
||||
+ tst-resolv-no-search \
|
||||
# tests-container
|
||||
|
||||
tests-internal += tst-inet_aton_exact
|
||||
@@ -294,10 +295,11 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
$(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
-$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
-$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
+$(objpfx)tst-resolv-no-search: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
+$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
+$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
diff --git a/resolv/tst-resolv-no-search.c b/resolv/tst-resolv-no-search.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..29701d4772507507
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-resolv-no-search.c
|
||||
@@ -0,0 +1,174 @@
|
||||
+/* Test using "search ." in /etc/resolv.conf.
|
||||
+ 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 <netdb.h>
|
||||
+#include <resolv.h>
|
||||
+
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/check_nss.h>
|
||||
+#include <support/namespace.h>
|
||||
+#include <support/resolv_test.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+/* Check that plain res_init loads the configuration as expected. */
|
||||
+static void
|
||||
+test_res_init (void *ignored)
|
||||
+{
|
||||
+ res_init ();
|
||||
+ TEST_COMPARE_STRING (_res.dnsrch[0], ".");
|
||||
+ TEST_COMPARE_STRING (_res.dnsrch[1], NULL);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+response (const struct resolv_response_context *ctx,
|
||||
+ struct resolv_response_builder *b,
|
||||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
+{
|
||||
+ TEST_VERIFY_EXIT (qclass == C_IN);
|
||||
+ TEST_COMPARE (ctx->server_index, 0);
|
||||
+
|
||||
+ if (strncmp (qname, "does-not-exist", strlen ("does-not-exist")) == 0)
|
||||
+ {
|
||||
+ resolv_response_init (b, (struct resolv_response_flags)
|
||||
+ { .rcode = ns_r_nxdomain });
|
||||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ resolv_response_init (b, (struct resolv_response_flags) { });
|
||||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||||
+ resolv_response_section (b, ns_s_an);
|
||||
+
|
||||
+ resolv_response_open_record (b, qname, qclass, qtype, 0);
|
||||
+ switch (qtype)
|
||||
+ {
|
||||
+ case T_A:
|
||||
+ {
|
||||
+ char ipv4[4] = {192, 0, 2, 17};
|
||||
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
|
||||
+ }
|
||||
+ break;
|
||||
+ case T_AAAA:
|
||||
+ {
|
||||
+ char ipv6[16]
|
||||
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
+ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ resolv_response_close_record (b);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+check_h (const char *name, int family, const char *expected)
|
||||
+{
|
||||
+ if (family == AF_INET)
|
||||
+ {
|
||||
+ char *query = xasprintf ("gethostbyname (\"%s\")", name);
|
||||
+ check_hostent (query, gethostbyname (name), expected);
|
||||
+ free (query);
|
||||
+ }
|
||||
+ {
|
||||
+ char *query = xasprintf ("gethostbyname2 (\"%s\", %d)", name, family);
|
||||
+ check_hostent (query, gethostbyname2 (name, family), expected);
|
||||
+ free (query);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+check_ai (const char *name, int family, const char *expected)
|
||||
+{
|
||||
+ struct addrinfo hints = { .ai_family = family, .ai_socktype = SOCK_STREAM, };
|
||||
+ struct addrinfo *ai;
|
||||
+ char *query = xasprintf ("%s:80 [%d]", name, hints.ai_family);
|
||||
+ int ret = getaddrinfo (name, "80", &hints, &ai);
|
||||
+ check_addrinfo (query, ai, ret, expected);
|
||||
+ if (ret == 0)
|
||||
+ freeaddrinfo (ai);
|
||||
+ free (query);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ support_isolate_in_subprocess (test_res_init, NULL);
|
||||
+
|
||||
+ struct resolv_test *aux = resolv_test_start
|
||||
+ ((struct resolv_redirect_config)
|
||||
+ {
|
||||
+ .response_callback = response,
|
||||
+ .no_override_resolv_conf_search = true,
|
||||
+ });
|
||||
+
|
||||
+ check_h ("www.example", AF_INET,
|
||||
+ "name: www.example\n"
|
||||
+ "address: 192.0.2.17\n");
|
||||
+ check_h ("www.example", AF_INET6,
|
||||
+ "name: www.example\n"
|
||||
+ "address: 2001:db8::1\n");
|
||||
+ check_ai ("www.example", AF_UNSPEC,
|
||||
+ "address: STREAM/TCP 192.0.2.17 80\n"
|
||||
+ "address: STREAM/TCP 2001:db8::1 80\n");
|
||||
+ check_ai ("www.example", AF_INET,
|
||||
+ "address: STREAM/TCP 192.0.2.17 80\n");
|
||||
+ check_ai ("www.example", AF_INET6,
|
||||
+ "address: STREAM/TCP 2001:db8::1 80\n");
|
||||
+ check_h ("does-not-exist.example", AF_INET,
|
||||
+ "error: HOST_NOT_FOUND\n");
|
||||
+ check_h ("does-not-exist.example", AF_INET6,
|
||||
+ "error: HOST_NOT_FOUND\n");
|
||||
+ check_ai ("does-not-exist.example", AF_UNSPEC,
|
||||
+ "error: Name or service not known\n");
|
||||
+ check_ai ("does-not-exist.example", AF_INET,
|
||||
+ "error: Name or service not known\n");
|
||||
+ check_ai ("does-not-exist.example", AF_INET6,
|
||||
+ "error: Name or service not known\n");
|
||||
+
|
||||
+ /* With trailing dot. */
|
||||
+ check_h ("www.example.", AF_INET,
|
||||
+ "name: www.example\n"
|
||||
+ "address: 192.0.2.17\n");
|
||||
+ check_h ("www.example.", AF_INET6,
|
||||
+ "name: www.example\n"
|
||||
+ "address: 2001:db8::1\n");
|
||||
+ check_ai ("www.example.", AF_UNSPEC,
|
||||
+ "address: STREAM/TCP 192.0.2.17 80\n"
|
||||
+ "address: STREAM/TCP 2001:db8::1 80\n");
|
||||
+ check_ai ("www.example.", AF_INET,
|
||||
+ "address: STREAM/TCP 192.0.2.17 80\n");
|
||||
+ check_ai ("www.example.", AF_INET6,
|
||||
+ "address: STREAM/TCP 2001:db8::1 80\n");
|
||||
+ check_h ("does-not-exist.example.", AF_INET,
|
||||
+ "error: HOST_NOT_FOUND\n");
|
||||
+ check_h ("does-not-exist.example.", AF_INET6,
|
||||
+ "error: HOST_NOT_FOUND\n");
|
||||
+ check_ai ("does-not-exist.example.", AF_UNSPEC,
|
||||
+ "error: Name or service not known\n");
|
||||
+ check_ai ("does-not-exist.example.", AF_INET,
|
||||
+ "error: Name or service not known\n");
|
||||
+ check_ai ("does-not-exist.example.", AF_INET6,
|
||||
+ "error: Name or service not known\n");
|
||||
+
|
||||
+ resolv_test_end (aux);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/resolv/tst-resolv-no-search.root/etc/resolv.conf b/resolv/tst-resolv-no-search.root/etc/resolv.conf
|
||||
new file mode 100644
|
||||
index 0000000000000000..5ace648869a31edb
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-resolv-no-search.root/etc/resolv.conf
|
||||
@@ -0,0 +1 @@
|
||||
+search .
|
||||
diff --git a/support/resolv_test.c b/support/resolv_test.c
|
||||
index 73d20572f3b843c7..7272334b78fc85f1 100644
|
||||
--- a/support/resolv_test.c
|
||||
+++ b/support/resolv_test.c
|
||||
@@ -1098,6 +1098,9 @@ resolv_test_init (void)
|
||||
static void
|
||||
set_search_path (struct resolv_redirect_config config)
|
||||
{
|
||||
+ if (config.no_override_resolv_conf_search)
|
||||
+ return;
|
||||
+
|
||||
memset (_res.defdname, 0, sizeof (_res.defdname));
|
||||
memset (_res.dnsrch, 0, sizeof (_res.dnsrch));
|
||||
|
||||
diff --git a/support/resolv_test.h b/support/resolv_test.h
|
||||
index ddf967449e398710..e0a17ebf23c34880 100644
|
||||
--- a/support/resolv_test.h
|
||||
+++ b/support/resolv_test.h
|
||||
@@ -96,6 +96,9 @@ struct resolv_redirect_config
|
||||
domain name as well. */
|
||||
const char *search[7];
|
||||
|
||||
+ /* If true, do not override the search path loaded from /etc/resolv.conf. */
|
||||
+ bool no_override_resolv_conf_search;
|
||||
+
|
||||
/* Number of servers to activate in resolv. 0 means the default,
|
||||
resolv_max_test_servers. */
|
||||
int nscount;
|
||||
98
SOURCES/glibc-RHEL-153056-3.patch
Normal file
98
SOURCES/glibc-RHEL-153056-3.patch
Normal file
@ -0,0 +1,98 @@
|
||||
commit dc9ca785a5fe2059a9b04ab336520d463d9a715b
|
||||
Author: Carlos Peón Costa <carlospeon@gmail.com>
|
||||
Date: Tue Mar 3 18:48:47 2026 +0100
|
||||
|
||||
resolv: Avoid duplicate query if search list contains '.' (bug 33804)
|
||||
|
||||
Co-authored-by: Florian Weimer <fweimer@redhat.com>
|
||||
Signed-off-by: Florian Weimer <fweimer@redhat.com>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/resolv/res_query.c b/resolv/res_query.c
|
||||
index 1d2c81737bc889c9..bae7b3c23d778a7d 100644
|
||||
--- a/resolv/res_query.c
|
||||
+++ b/resolv/res_query.c
|
||||
@@ -358,7 +358,7 @@ __res_context_search (struct resolv_context *ctx,
|
||||
char tmp[NS_MAXDNAME];
|
||||
u_int dots;
|
||||
int trailing_dot, ret, saved_herrno;
|
||||
- int got_nodata = 0, got_servfail = 0, root_on_list = 0;
|
||||
+ int got_nodata = 0, got_servfail = 0;
|
||||
int tried_as_is = 0;
|
||||
int searched = 0;
|
||||
|
||||
@@ -437,8 +437,11 @@ __res_context_search (struct resolv_context *ctx,
|
||||
domain. */
|
||||
if (dname[0] == '.')
|
||||
dname++;
|
||||
- if (dname[0] == '\0')
|
||||
- root_on_list++;
|
||||
+ if (dname[0] == '\0') {
|
||||
+ if (tried_as_is)
|
||||
+ continue;
|
||||
+ tried_as_is++;
|
||||
+ }
|
||||
|
||||
ret = __res_context_querydomain
|
||||
(ctx, name, dname, class, type,
|
||||
@@ -510,7 +513,7 @@ __res_context_search (struct resolv_context *ctx,
|
||||
* unless RES_NOTLDQUERY is set and there were no dots.
|
||||
*/
|
||||
if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
|
||||
- && !(tried_as_is || root_on_list)) {
|
||||
+ && !tried_as_is) {
|
||||
ret = __res_context_querydomain
|
||||
(ctx, name, NULL, class, type,
|
||||
answer, anslen, answerp, answerp2, nanswerp2,
|
||||
diff --git a/resolv/tst-resolv-no-search.c b/resolv/tst-resolv-no-search.c
|
||||
index 29701d4772507507..7d78d4044cf50e48 100644
|
||||
--- a/resolv/tst-resolv-no-search.c
|
||||
+++ b/resolv/tst-resolv-no-search.c
|
||||
@@ -27,6 +27,11 @@
|
||||
#include <support/resolv_test.h>
|
||||
#include <support/support.h>
|
||||
|
||||
+/* Used to check for duplicated queries (bug 33804). POSIX does not
|
||||
+ explicitly say that socket calls (as used in the resolver tests)
|
||||
+ provide synchronization. */
|
||||
+static _Atomic unsigned int query_count;
|
||||
+
|
||||
/* Check that plain res_init loads the configuration as expected. */
|
||||
static void
|
||||
test_res_init (void *ignored)
|
||||
@@ -43,6 +48,7 @@ response (const struct resolv_response_context *ctx,
|
||||
{
|
||||
TEST_VERIFY_EXIT (qclass == C_IN);
|
||||
TEST_COMPARE (ctx->server_index, 0);
|
||||
+ ++query_count;
|
||||
|
||||
if (strncmp (qname, "does-not-exist", strlen ("does-not-exist")) == 0)
|
||||
{
|
||||
@@ -82,12 +88,16 @@ check_h (const char *name, int family, const char *expected)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
char *query = xasprintf ("gethostbyname (\"%s\")", name);
|
||||
+ query_count = 0;
|
||||
check_hostent (query, gethostbyname (name), expected);
|
||||
+ TEST_COMPARE (query_count, 1);
|
||||
free (query);
|
||||
}
|
||||
{
|
||||
char *query = xasprintf ("gethostbyname2 (\"%s\", %d)", name, family);
|
||||
+ query_count = 0;
|
||||
check_hostent (query, gethostbyname2 (name, family), expected);
|
||||
+ TEST_COMPARE (query_count, 1);
|
||||
free (query);
|
||||
}
|
||||
}
|
||||
@@ -98,8 +108,10 @@ check_ai (const char *name, int family, const char *expected)
|
||||
struct addrinfo hints = { .ai_family = family, .ai_socktype = SOCK_STREAM, };
|
||||
struct addrinfo *ai;
|
||||
char *query = xasprintf ("%s:80 [%d]", name, hints.ai_family);
|
||||
+ query_count = 0;
|
||||
int ret = getaddrinfo (name, "80", &hints, &ai);
|
||||
check_addrinfo (query, ai, ret, expected);
|
||||
+ TEST_COMPARE (query_count, family == AF_UNSPEC ? 2 : 1);
|
||||
if (ret == 0)
|
||||
freeaddrinfo (ai);
|
||||
free (query);
|
||||
369
SOURCES/glibc-RHEL-162901-1.patch
Normal file
369
SOURCES/glibc-RHEL-162901-1.patch
Normal file
@ -0,0 +1,369 @@
|
||||
commit 5729e0e9af590807df66a3db688008f9547bce9f
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Fri Feb 10 14:09:10 2023 -0300
|
||||
|
||||
iconv: Remove _STRING_ARCH_unaligned usage for get/set macros
|
||||
|
||||
And use a packed structure instead. The compiler generates optimized
|
||||
unaligned code if the architecture supports it.
|
||||
|
||||
Checked on x86_64-linux-gnu and i686-linux-gnu.
|
||||
|
||||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||||
|
||||
diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h
|
||||
index 499bc6bfa54fe37d..360924cc0394d86b 100644
|
||||
--- a/iconv/gconv_int.h
|
||||
+++ b/iconv/gconv_int.h
|
||||
@@ -27,6 +27,34 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
+/* We have to provide support for machines which are not able to handled
|
||||
+ unaligned memory accesses. Some of the character encodings have
|
||||
+ representations with a fixed width of 2 or 4 bytes. */
|
||||
+#define get16(addr) \
|
||||
+({ \
|
||||
+ const struct { uint16_t r; } __attribute__ ((__packed__)) *__ptr \
|
||||
+ = (__typeof(__ptr))(addr); \
|
||||
+ __ptr->r; \
|
||||
+})
|
||||
+#define get32(addr) \
|
||||
+({ \
|
||||
+ const struct { uint32_t r; } __attribute__ ((__packed__)) *__ptr \
|
||||
+ = (__typeof(__ptr))(addr); \
|
||||
+ __ptr->r; \
|
||||
+})
|
||||
+
|
||||
+#define put16(addr, val) \
|
||||
+do { \
|
||||
+ struct { uint16_t r; } __attribute__ ((__packed__)) *__ptr \
|
||||
+ = (__typeof(__ptr))(addr); \
|
||||
+ __ptr->r = val; \
|
||||
+} while (0)
|
||||
+#define put32(addr, val) \
|
||||
+do { \
|
||||
+ struct { uint32_t r; } __attribute__ ((__packed__)) *__ptr \
|
||||
+ = (__typeof(__ptr))(addr); \
|
||||
+ __ptr->r = val; \
|
||||
+} while (0)
|
||||
|
||||
/* Structure for alias definition. Simply two strings. */
|
||||
struct gconv_alias
|
||||
diff --git a/iconv/loop.c b/iconv/loop.c
|
||||
index 7193e8f20104bf84..851caa9d42d45a47 100644
|
||||
--- a/iconv/loop.c
|
||||
+++ b/iconv/loop.c
|
||||
@@ -58,75 +58,10 @@
|
||||
#include <stddef.h>
|
||||
#include <libc-diag.h>
|
||||
|
||||
-/* We have to provide support for machines which are not able to handled
|
||||
- unaligned memory accesses. Some of the character encodings have
|
||||
- representations with a fixed width of 2 or 4 bytes. But if we cannot
|
||||
- access unaligned memory we still have to read byte-wise. */
|
||||
#undef FCTNAME2
|
||||
#if _STRING_ARCH_unaligned || !defined DEFINE_UNALIGNED
|
||||
-/* We can handle unaligned memory access. */
|
||||
-# define get16(addr) *((const uint16_t *) (addr))
|
||||
-# define get32(addr) *((const uint32_t *) (addr))
|
||||
-
|
||||
-/* We need no special support for writing values either. */
|
||||
-# define put16(addr, val) *((uint16_t *) (addr)) = (val)
|
||||
-# define put32(addr, val) *((uint32_t *) (addr)) = (val)
|
||||
-
|
||||
# define FCTNAME2(name) name
|
||||
#else
|
||||
-/* Distinguish between big endian and little endian. */
|
||||
-# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
-# define get16(addr) \
|
||||
- (((const unsigned char *) (addr))[1] << 8 \
|
||||
- | ((const unsigned char *) (addr))[0])
|
||||
-# define get32(addr) \
|
||||
- (((((const unsigned char *) (addr))[3] << 8 \
|
||||
- | ((const unsigned char *) (addr))[2]) << 8 \
|
||||
- | ((const unsigned char *) (addr))[1]) << 8 \
|
||||
- | ((const unsigned char *) (addr))[0])
|
||||
-
|
||||
-# define put16(addr, val) \
|
||||
- ({ uint16_t __val = (val); \
|
||||
- ((unsigned char *) (addr))[0] = __val; \
|
||||
- ((unsigned char *) (addr))[1] = __val >> 8; \
|
||||
- (void) 0; })
|
||||
-# define put32(addr, val) \
|
||||
- ({ uint32_t __val = (val); \
|
||||
- ((unsigned char *) (addr))[0] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[1] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[2] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[3] = __val; \
|
||||
- (void) 0; })
|
||||
-# else
|
||||
-# define get16(addr) \
|
||||
- (((const unsigned char *) (addr))[0] << 8 \
|
||||
- | ((const unsigned char *) (addr))[1])
|
||||
-# define get32(addr) \
|
||||
- (((((const unsigned char *) (addr))[0] << 8 \
|
||||
- | ((const unsigned char *) (addr))[1]) << 8 \
|
||||
- | ((const unsigned char *) (addr))[2]) << 8 \
|
||||
- | ((const unsigned char *) (addr))[3])
|
||||
-
|
||||
-# define put16(addr, val) \
|
||||
- ({ uint16_t __val = (val); \
|
||||
- ((unsigned char *) (addr))[1] = __val; \
|
||||
- ((unsigned char *) (addr))[0] = __val >> 8; \
|
||||
- (void) 0; })
|
||||
-# define put32(addr, val) \
|
||||
- ({ uint32_t __val = (val); \
|
||||
- ((unsigned char *) (addr))[3] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[2] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[1] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[0] = __val; \
|
||||
- (void) 0; })
|
||||
-# endif
|
||||
-
|
||||
# define FCTNAME2(name) name##_unaligned
|
||||
#endif
|
||||
#define FCTNAME(name) FCTNAME2(name)
|
||||
@@ -352,10 +287,6 @@ FCTNAME (LOOPFCT) (struct __gconv_step *step,
|
||||
#if !defined DEFINE_UNALIGNED && !_STRING_ARCH_unaligned \
|
||||
&& MIN_NEEDED_INPUT != 1 && MAX_NEEDED_INPUT % MIN_NEEDED_INPUT == 0 \
|
||||
&& MIN_NEEDED_OUTPUT != 1 && MAX_NEEDED_OUTPUT % MIN_NEEDED_OUTPUT == 0
|
||||
-# undef get16
|
||||
-# undef get32
|
||||
-# undef put16
|
||||
-# undef put32
|
||||
# undef unaligned
|
||||
|
||||
# define DEFINE_UNALIGNED
|
||||
@@ -537,8 +468,4 @@ gconv_btowc (struct __gconv_step *step, unsigned char c)
|
||||
#undef LOOP_NEED_STATE
|
||||
#undef LOOP_NEED_FLAGS
|
||||
#undef LOOP_NEED_DATA
|
||||
-#undef get16
|
||||
-#undef get32
|
||||
-#undef put16
|
||||
-#undef put32
|
||||
#undef unaligned
|
||||
diff --git a/iconv/skeleton.c b/iconv/skeleton.c
|
||||
index 0ddc16ad1d7e0184..6992701808079ec2 100644
|
||||
--- a/iconv/skeleton.c
|
||||
+++ b/iconv/skeleton.c
|
||||
@@ -205,73 +205,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
-/* Define macros which can access unaligned buffers. These macros are
|
||||
- supposed to be used only in code outside the inner loops. For the inner
|
||||
- loops we have other definitions which allow optimized access. */
|
||||
-#if _STRING_ARCH_unaligned
|
||||
-/* We can handle unaligned memory access. */
|
||||
-# define get16u(addr) *((const uint16_t *) (addr))
|
||||
-# define get32u(addr) *((const uint32_t *) (addr))
|
||||
-
|
||||
-/* We need no special support for writing values either. */
|
||||
-# define put16u(addr, val) *((uint16_t *) (addr)) = (val)
|
||||
-# define put32u(addr, val) *((uint32_t *) (addr)) = (val)
|
||||
-#else
|
||||
-/* Distinguish between big endian and little endian. */
|
||||
-# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
-# define get16u(addr) \
|
||||
- (((const unsigned char *) (addr))[1] << 8 \
|
||||
- | ((const unsigned char *) (addr))[0])
|
||||
-# define get32u(addr) \
|
||||
- (((((const unsigned char *) (addr))[3] << 8 \
|
||||
- | ((const unsigned char *) (addr))[2]) << 8 \
|
||||
- | ((const unsigned char *) (addr))[1]) << 8 \
|
||||
- | ((const unsigned char *) (addr))[0])
|
||||
-
|
||||
-# define put16u(addr, val) \
|
||||
- ({ uint16_t __val = (val); \
|
||||
- ((unsigned char *) (addr))[0] = __val; \
|
||||
- ((unsigned char *) (addr))[1] = __val >> 8; \
|
||||
- (void) 0; })
|
||||
-# define put32u(addr, val) \
|
||||
- ({ uint32_t __val = (val); \
|
||||
- ((unsigned char *) (addr))[0] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[1] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[2] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[3] = __val; \
|
||||
- (void) 0; })
|
||||
-# else
|
||||
-# define get16u(addr) \
|
||||
- (((const unsigned char *) (addr))[0] << 8 \
|
||||
- | ((const unsigned char *) (addr))[1])
|
||||
-# define get32u(addr) \
|
||||
- (((((const unsigned char *) (addr))[0] << 8 \
|
||||
- | ((const unsigned char *) (addr))[1]) << 8 \
|
||||
- | ((const unsigned char *) (addr))[2]) << 8 \
|
||||
- | ((const unsigned char *) (addr))[3])
|
||||
-
|
||||
-# define put16u(addr, val) \
|
||||
- ({ uint16_t __val = (val); \
|
||||
- ((unsigned char *) (addr))[1] = __val; \
|
||||
- ((unsigned char *) (addr))[0] = __val >> 8; \
|
||||
- (void) 0; })
|
||||
-# define put32u(addr, val) \
|
||||
- ({ uint32_t __val = (val); \
|
||||
- ((unsigned char *) (addr))[3] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[2] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[1] = __val; \
|
||||
- __val >>= 8; \
|
||||
- ((unsigned char *) (addr))[0] = __val; \
|
||||
- (void) 0; })
|
||||
-# endif
|
||||
-#endif
|
||||
-
|
||||
-
|
||||
/* For conversions from a fixed width character set to another fixed width
|
||||
character set we can define RESET_INPUT_BUFFER in a very fast way. */
|
||||
#if !defined RESET_INPUT_BUFFER && !defined SAVE_RESET_STATE
|
||||
diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c
|
||||
index 220d8d1cf174fdd7..97e735c755ab8093 100644
|
||||
--- a/iconvdata/iso-2022-jp-3.c
|
||||
+++ b/iconvdata/iso-2022-jp-3.c
|
||||
@@ -93,7 +93,7 @@ enum
|
||||
if (__glibc_likely (outbuf + 4 <= outend)) \
|
||||
{ \
|
||||
/* Write out the last character. */ \
|
||||
- put32u (outbuf, ch); \
|
||||
+ put32 (outbuf, ch); \
|
||||
outbuf += 4; \
|
||||
data->__statep->__count &= 7; \
|
||||
data->__statep->__count |= ASCII_set; \
|
||||
diff --git a/iconvdata/unicode.c b/iconvdata/unicode.c
|
||||
index 525abe48b94118e5..ee19b2041c7d4fc5 100644
|
||||
--- a/iconvdata/unicode.c
|
||||
+++ b/iconvdata/unicode.c
|
||||
@@ -52,10 +52,10 @@
|
||||
return (inptr == inend \
|
||||
? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); \
|
||||
\
|
||||
- if (get16u (inptr) == BOM) \
|
||||
+ if (get16 (inptr) == BOM) \
|
||||
/* Simply ignore the BOM character. */ \
|
||||
*inptrp = inptr += 2; \
|
||||
- else if (get16u (inptr) == BOM_OE) \
|
||||
+ else if (get16 (inptr) == BOM_OE) \
|
||||
{ \
|
||||
data->__flags |= __GCONV_SWAP; \
|
||||
*inptrp = inptr += 2; \
|
||||
@@ -68,7 +68,7 @@
|
||||
if (__glibc_unlikely (outbuf + 2 > outend)) \
|
||||
return __GCONV_FULL_OUTPUT; \
|
||||
\
|
||||
- put16u (outbuf, BOM); \
|
||||
+ put16 (outbuf, BOM); \
|
||||
outbuf += 2; \
|
||||
} \
|
||||
swap = data->__flags & __GCONV_SWAP;
|
||||
diff --git a/iconvdata/utf-16.c b/iconvdata/utf-16.c
|
||||
index 63cf43a09b4abf5d..87c59e9ecf1602ac 100644
|
||||
--- a/iconvdata/utf-16.c
|
||||
+++ b/iconvdata/utf-16.c
|
||||
@@ -56,10 +56,10 @@
|
||||
return (inptr == inend \
|
||||
? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); \
|
||||
\
|
||||
- if (get16u (inptr) == BOM) \
|
||||
+ if (get16 (inptr) == BOM) \
|
||||
/* Simply ignore the BOM character. */ \
|
||||
*inptrp = inptr += 2; \
|
||||
- else if (get16u (inptr) == BOM_OE) \
|
||||
+ else if (get16 (inptr) == BOM_OE) \
|
||||
{ \
|
||||
data->__flags |= __GCONV_SWAP; \
|
||||
*inptrp = inptr += 2; \
|
||||
@@ -71,7 +71,7 @@
|
||||
if (__glibc_unlikely (outbuf + 2 > outend)) \
|
||||
return __GCONV_FULL_OUTPUT; \
|
||||
\
|
||||
- put16u (outbuf, BOM); \
|
||||
+ put16 (outbuf, BOM); \
|
||||
outbuf += 2; \
|
||||
} \
|
||||
} \
|
||||
diff --git a/iconvdata/utf-32.c b/iconvdata/utf-32.c
|
||||
index 4fbd7bc18fa2d0c9..060f77230b0101fe 100644
|
||||
--- a/iconvdata/utf-32.c
|
||||
+++ b/iconvdata/utf-32.c
|
||||
@@ -52,10 +52,10 @@
|
||||
return (inptr == inend \
|
||||
? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); \
|
||||
\
|
||||
- if (get32u (inptr) == BOM) \
|
||||
+ if (get32 (inptr) == BOM) \
|
||||
/* Simply ignore the BOM character. */ \
|
||||
*inptrp = inptr += 4; \
|
||||
- else if (get32u (inptr) == BOM_OE) \
|
||||
+ else if (get32 (inptr) == BOM_OE) \
|
||||
{ \
|
||||
data->__flags |= __GCONV_SWAP; \
|
||||
*inptrp = inptr += 4; \
|
||||
@@ -69,7 +69,7 @@
|
||||
if (__glibc_unlikely (outbuf + 4 > outend)) \
|
||||
return __GCONV_FULL_OUTPUT; \
|
||||
\
|
||||
- put32u (outbuf, BOM); \
|
||||
+ put32 (outbuf, BOM); \
|
||||
outbuf += 4; \
|
||||
} \
|
||||
else if (__builtin_expect (data->__invocation_counter == 0, 0) \
|
||||
diff --git a/sysdeps/s390/utf16-utf32-z9.c b/sysdeps/s390/utf16-utf32-z9.c
|
||||
index 93895f9db8004f72..7d3de99f440a8ab4 100644
|
||||
--- a/sysdeps/s390/utf16-utf32-z9.c
|
||||
+++ b/sysdeps/s390/utf16-utf32-z9.c
|
||||
@@ -177,7 +177,7 @@ gconv_end (struct __gconv_step *data)
|
||||
if (__glibc_unlikely (outbuf + 2 > outend)) \
|
||||
return __GCONV_FULL_OUTPUT; \
|
||||
\
|
||||
- put16u (outbuf, BOM_UTF16); \
|
||||
+ put16 (outbuf, BOM_UTF16); \
|
||||
outbuf += 2; \
|
||||
} \
|
||||
else \
|
||||
@@ -186,7 +186,7 @@ gconv_end (struct __gconv_step *data)
|
||||
if (__glibc_unlikely (outbuf + 4 > outend)) \
|
||||
return __GCONV_FULL_OUTPUT; \
|
||||
\
|
||||
- put32u (outbuf, BOM_UTF32); \
|
||||
+ put32 (outbuf, BOM_UTF32); \
|
||||
outbuf += 4; \
|
||||
} \
|
||||
}
|
||||
diff --git a/sysdeps/s390/utf8-utf16-z9.c b/sysdeps/s390/utf8-utf16-z9.c
|
||||
index 1ff16b5bec4c10fd..615ebaac13a4c0a7 100644
|
||||
--- a/sysdeps/s390/utf8-utf16-z9.c
|
||||
+++ b/sysdeps/s390/utf8-utf16-z9.c
|
||||
@@ -217,7 +217,7 @@ gconv_end (struct __gconv_step *data)
|
||||
if (__glibc_unlikely (outbuf + 2 > outend)) \
|
||||
return __GCONV_FULL_OUTPUT; \
|
||||
\
|
||||
- put16u (outbuf, BOM_UTF16); \
|
||||
+ put16 (outbuf, BOM_UTF16); \
|
||||
outbuf += 2; \
|
||||
}
|
||||
|
||||
diff --git a/sysdeps/s390/utf8-utf32-z9.c b/sysdeps/s390/utf8-utf32-z9.c
|
||||
index f1f4d3c89e6469c1..364558c0e2bed517 100644
|
||||
--- a/sysdeps/s390/utf8-utf32-z9.c
|
||||
+++ b/sysdeps/s390/utf8-utf32-z9.c
|
||||
@@ -217,7 +217,7 @@ gconv_end (struct __gconv_step *data)
|
||||
if (__glibc_unlikely (outbuf + 4 > outend)) \
|
||||
return __GCONV_FULL_OUTPUT; \
|
||||
\
|
||||
- put32u (outbuf, BOM); \
|
||||
+ put32 (outbuf, BOM); \
|
||||
outbuf += 4; \
|
||||
}
|
||||
|
||||
694
SOURCES/glibc-RHEL-162901-2.patch
Normal file
694
SOURCES/glibc-RHEL-162901-2.patch
Normal file
@ -0,0 +1,694 @@
|
||||
commit 3e20ddade31d9c392d8ccf7ec902172f4bb01c2b
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Fri Feb 10 16:37:36 2023 -0300
|
||||
|
||||
iconv: Remove _STRING_ARCH_unaligned usage
|
||||
|
||||
Use put/get macros __builtin_bswap32 instead. It allows to remove
|
||||
the unaligned routines, the compiler will generate unaligned access
|
||||
if the ABI allows it.
|
||||
|
||||
Checked on x86_64-linux-gnu and i686-linux-gnu.
|
||||
|
||||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||||
|
||||
diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c
|
||||
index 882d3642e445b107..d368284411c79282 100644
|
||||
--- a/iconv/gconv_simple.c
|
||||
+++ b/iconv/gconv_simple.c
|
||||
@@ -87,69 +87,22 @@ internal_ucs4_loop (struct __gconv_step *step,
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
/* Sigh, we have to do some real work. */
|
||||
size_t cnt;
|
||||
- uint32_t *outptr32 = (uint32_t *) outptr;
|
||||
-
|
||||
- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
- *outptr32++ = bswap_32 (*(const uint32_t *) inptr);
|
||||
-
|
||||
- *inptrp = inptr;
|
||||
- *outptrp = (unsigned char *) outptr32;
|
||||
-#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
- /* Simply copy the data. */
|
||||
- *inptrp = inptr + n_convert * 4;
|
||||
- *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
|
||||
-#else
|
||||
-# error "This endianness is not supported."
|
||||
-#endif
|
||||
-
|
||||
- /* Determine the status. */
|
||||
- if (*inptrp == inend)
|
||||
- result = __GCONV_EMPTY_INPUT;
|
||||
- else if (*outptrp + 4 > outend)
|
||||
- result = __GCONV_FULL_OUTPUT;
|
||||
- else
|
||||
- result = __GCONV_INCOMPLETE_INPUT;
|
||||
-
|
||||
- return result;
|
||||
-}
|
||||
-
|
||||
-#if !_STRING_ARCH_unaligned
|
||||
-static inline int
|
||||
-__attribute ((always_inline))
|
||||
-internal_ucs4_loop_unaligned (struct __gconv_step *step,
|
||||
- struct __gconv_step_data *step_data,
|
||||
- const unsigned char **inptrp,
|
||||
- const unsigned char *inend,
|
||||
- unsigned char **outptrp,
|
||||
- const unsigned char *outend,
|
||||
- size_t *irreversible)
|
||||
-{
|
||||
- const unsigned char *inptr = *inptrp;
|
||||
- unsigned char *outptr = *outptrp;
|
||||
- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
- int result;
|
||||
-
|
||||
-# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
- /* Sigh, we have to do some real work. */
|
||||
- size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4)
|
||||
{
|
||||
- outptr[0] = inptr[3];
|
||||
- outptr[1] = inptr[2];
|
||||
- outptr[2] = inptr[1];
|
||||
- outptr[3] = inptr[0];
|
||||
+ uint32_t val = get32 (inptr);
|
||||
+ put32 (outptr, __builtin_bswap32 (val));
|
||||
}
|
||||
|
||||
*inptrp = inptr;
|
||||
*outptrp = outptr;
|
||||
-# elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
+#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
/* Simply copy the data. */
|
||||
*inptrp = inptr + n_convert * 4;
|
||||
*outptrp = __mempcpy (outptr, inptr, n_convert * 4);
|
||||
-# else
|
||||
-# error "This endianess is not supported."
|
||||
-# endif
|
||||
+#else
|
||||
+# error "This endianness is not supported."
|
||||
+#endif
|
||||
|
||||
/* Determine the status. */
|
||||
if (*inptrp == inend)
|
||||
@@ -161,7 +114,6 @@ internal_ucs4_loop_unaligned (struct __gconv_step *step,
|
||||
|
||||
return result;
|
||||
}
|
||||
-#endif
|
||||
|
||||
|
||||
static inline int
|
||||
@@ -243,12 +195,9 @@ ucs4_internal_loop (struct __gconv_step *step,
|
||||
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
- uint32_t inval;
|
||||
-
|
||||
+ uint32_t inval = get32 (inptr);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
- inval = bswap_32 (*(const uint32_t *) inptr);
|
||||
-#else
|
||||
- inval = *(const uint32_t *) inptr;
|
||||
+ inval = __builtin_bswap32 (inval);
|
||||
#endif
|
||||
|
||||
if (__glibc_unlikely (inval > 0x7fffffff))
|
||||
@@ -273,7 +222,7 @@ ucs4_internal_loop (struct __gconv_step *step,
|
||||
return __gconv_mark_illegal_input (step_data);
|
||||
}
|
||||
|
||||
- *((uint32_t *) outptr) = inval;
|
||||
+ put32 (outptr, inval);
|
||||
outptr += sizeof (uint32_t);
|
||||
}
|
||||
|
||||
@@ -291,75 +240,6 @@ ucs4_internal_loop (struct __gconv_step *step,
|
||||
return result;
|
||||
}
|
||||
|
||||
-#if !_STRING_ARCH_unaligned
|
||||
-static inline int
|
||||
-__attribute ((always_inline))
|
||||
-ucs4_internal_loop_unaligned (struct __gconv_step *step,
|
||||
- struct __gconv_step_data *step_data,
|
||||
- const unsigned char **inptrp,
|
||||
- const unsigned char *inend,
|
||||
- unsigned char **outptrp,
|
||||
- const unsigned char *outend,
|
||||
- size_t *irreversible)
|
||||
-{
|
||||
- int flags = step_data->__flags;
|
||||
- const unsigned char *inptr = *inptrp;
|
||||
- unsigned char *outptr = *outptrp;
|
||||
- int result;
|
||||
-
|
||||
- for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
- {
|
||||
- if (__glibc_unlikely (inptr[0] > 0x80))
|
||||
- {
|
||||
- /* The value is too large. We don't try transliteration here since
|
||||
- this is not an error because of the lack of possibilities to
|
||||
- represent the result. This is a genuine bug in the input since
|
||||
- UCS4 does not allow such values. */
|
||||
- if (irreversible == NULL)
|
||||
- /* We are transliterating, don't try to correct anything. */
|
||||
- return __GCONV_ILLEGAL_INPUT;
|
||||
-
|
||||
- if (flags & __GCONV_IGNORE_ERRORS)
|
||||
- {
|
||||
- /* Just ignore this character. */
|
||||
- ++*irreversible;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- *inptrp = inptr;
|
||||
- *outptrp = outptr;
|
||||
- return __GCONV_ILLEGAL_INPUT;
|
||||
- }
|
||||
-
|
||||
-# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
- outptr[3] = inptr[0];
|
||||
- outptr[2] = inptr[1];
|
||||
- outptr[1] = inptr[2];
|
||||
- outptr[0] = inptr[3];
|
||||
-# else
|
||||
- outptr[0] = inptr[0];
|
||||
- outptr[1] = inptr[1];
|
||||
- outptr[2] = inptr[2];
|
||||
- outptr[3] = inptr[3];
|
||||
-# endif
|
||||
- outptr += 4;
|
||||
- }
|
||||
-
|
||||
- *inptrp = inptr;
|
||||
- *outptrp = outptr;
|
||||
-
|
||||
- /* Determine the status. */
|
||||
- if (*inptrp == inend)
|
||||
- result = __GCONV_EMPTY_INPUT;
|
||||
- else if (*outptrp + 4 > outend)
|
||||
- result = __GCONV_FULL_OUTPUT;
|
||||
- else
|
||||
- result = __GCONV_INCOMPLETE_INPUT;
|
||||
-
|
||||
- return result;
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
|
||||
static inline int
|
||||
__attribute ((always_inline))
|
||||
@@ -454,11 +334,12 @@ internal_ucs4le_loop (struct __gconv_step *step,
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
/* Sigh, we have to do some real work. */
|
||||
size_t cnt;
|
||||
- uint32_t *outptr32 = (uint32_t *) outptr;
|
||||
|
||||
- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
- *outptr32++ = bswap_32 (*(const uint32_t *) inptr);
|
||||
- outptr = (unsigned char *) outptr32;
|
||||
+ for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4)
|
||||
+ {
|
||||
+ uint32_t val = get32 (inptr);
|
||||
+ put32 (outptr, __builtin_bswap32 (val));
|
||||
+ }
|
||||
|
||||
*inptrp = inptr;
|
||||
*outptrp = outptr;
|
||||
@@ -481,59 +362,6 @@ internal_ucs4le_loop (struct __gconv_step *step,
|
||||
return result;
|
||||
}
|
||||
|
||||
-#if !_STRING_ARCH_unaligned
|
||||
-static inline int
|
||||
-__attribute ((always_inline))
|
||||
-internal_ucs4le_loop_unaligned (struct __gconv_step *step,
|
||||
- struct __gconv_step_data *step_data,
|
||||
- const unsigned char **inptrp,
|
||||
- const unsigned char *inend,
|
||||
- unsigned char **outptrp,
|
||||
- const unsigned char *outend,
|
||||
- size_t *irreversible)
|
||||
-{
|
||||
- const unsigned char *inptr = *inptrp;
|
||||
- unsigned char *outptr = *outptrp;
|
||||
- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
- int result;
|
||||
-
|
||||
-# if __BYTE_ORDER == __BIG_ENDIAN
|
||||
- /* Sigh, we have to do some real work. */
|
||||
- size_t cnt;
|
||||
-
|
||||
- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4)
|
||||
- {
|
||||
- outptr[0] = inptr[3];
|
||||
- outptr[1] = inptr[2];
|
||||
- outptr[2] = inptr[1];
|
||||
- outptr[3] = inptr[0];
|
||||
- }
|
||||
-
|
||||
- *inptrp = inptr;
|
||||
- *outptrp = outptr;
|
||||
-# elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
- /* Simply copy the data. */
|
||||
- *inptrp = inptr + n_convert * 4;
|
||||
- *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
|
||||
-# else
|
||||
-# error "This endianess is not supported."
|
||||
-# endif
|
||||
-
|
||||
- /* Determine the status. */
|
||||
- if (*inptrp == inend)
|
||||
- result = __GCONV_EMPTY_INPUT;
|
||||
- else if (*inptrp + 4 > inend)
|
||||
- result = __GCONV_INCOMPLETE_INPUT;
|
||||
- else
|
||||
- {
|
||||
- assert (*outptrp + 4 > outend);
|
||||
- result = __GCONV_FULL_OUTPUT;
|
||||
- }
|
||||
-
|
||||
- return result;
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
|
||||
static inline int
|
||||
__attribute ((always_inline))
|
||||
@@ -613,12 +441,9 @@ ucs4le_internal_loop (struct __gconv_step *step,
|
||||
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
- uint32_t inval;
|
||||
-
|
||||
+ uint32_t inval = get32 (inptr);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
- inval = bswap_32 (*(const uint32_t *) inptr);
|
||||
-#else
|
||||
- inval = *(const uint32_t *) inptr;
|
||||
+ inval = __builtin_bswap32 (inval);
|
||||
#endif
|
||||
|
||||
if (__glibc_unlikely (inval > 0x7fffffff))
|
||||
@@ -643,7 +468,7 @@ ucs4le_internal_loop (struct __gconv_step *step,
|
||||
return __gconv_mark_illegal_input (step_data);
|
||||
}
|
||||
|
||||
- *((uint32_t *) outptr) = inval;
|
||||
+ put32 (outptr, inval);
|
||||
outptr += sizeof (uint32_t);
|
||||
}
|
||||
|
||||
@@ -664,79 +489,6 @@ ucs4le_internal_loop (struct __gconv_step *step,
|
||||
return result;
|
||||
}
|
||||
|
||||
-#if !_STRING_ARCH_unaligned
|
||||
-static inline int
|
||||
-__attribute ((always_inline))
|
||||
-ucs4le_internal_loop_unaligned (struct __gconv_step *step,
|
||||
- struct __gconv_step_data *step_data,
|
||||
- const unsigned char **inptrp,
|
||||
- const unsigned char *inend,
|
||||
- unsigned char **outptrp,
|
||||
- const unsigned char *outend,
|
||||
- size_t *irreversible)
|
||||
-{
|
||||
- int flags = step_data->__flags;
|
||||
- const unsigned char *inptr = *inptrp;
|
||||
- unsigned char *outptr = *outptrp;
|
||||
- int result;
|
||||
-
|
||||
- for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
- {
|
||||
- if (__glibc_unlikely (inptr[3] > 0x80))
|
||||
- {
|
||||
- /* The value is too large. We don't try transliteration here since
|
||||
- this is not an error because of the lack of possibilities to
|
||||
- represent the result. This is a genuine bug in the input since
|
||||
- UCS4 does not allow such values. */
|
||||
- if (irreversible == NULL)
|
||||
- /* We are transliterating, don't try to correct anything. */
|
||||
- return __GCONV_ILLEGAL_INPUT;
|
||||
-
|
||||
- if (flags & __GCONV_IGNORE_ERRORS)
|
||||
- {
|
||||
- /* Just ignore this character. */
|
||||
- ++*irreversible;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- *inptrp = inptr;
|
||||
- *outptrp = outptr;
|
||||
- return __GCONV_ILLEGAL_INPUT;
|
||||
- }
|
||||
-
|
||||
-# if __BYTE_ORDER == __BIG_ENDIAN
|
||||
- outptr[3] = inptr[0];
|
||||
- outptr[2] = inptr[1];
|
||||
- outptr[1] = inptr[2];
|
||||
- outptr[0] = inptr[3];
|
||||
-# else
|
||||
- outptr[0] = inptr[0];
|
||||
- outptr[1] = inptr[1];
|
||||
- outptr[2] = inptr[2];
|
||||
- outptr[3] = inptr[3];
|
||||
-# endif
|
||||
-
|
||||
- outptr += 4;
|
||||
- }
|
||||
-
|
||||
- *inptrp = inptr;
|
||||
- *outptrp = outptr;
|
||||
-
|
||||
- /* Determine the status. */
|
||||
- if (*inptrp == inend)
|
||||
- result = __GCONV_EMPTY_INPUT;
|
||||
- else if (*inptrp + 4 > inend)
|
||||
- result = __GCONV_INCOMPLETE_INPUT;
|
||||
- else
|
||||
- {
|
||||
- assert (*outptrp + 4 > outend);
|
||||
- result = __GCONV_FULL_OUTPUT;
|
||||
- }
|
||||
-
|
||||
- return result;
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
|
||||
static inline int
|
||||
__attribute ((always_inline))
|
||||
diff --git a/iconv/loop.c b/iconv/loop.c
|
||||
index 851caa9d42d45a47..696caa212aaec4bd 100644
|
||||
--- a/iconv/loop.c
|
||||
+++ b/iconv/loop.c
|
||||
@@ -59,12 +59,7 @@
|
||||
#include <libc-diag.h>
|
||||
|
||||
#undef FCTNAME2
|
||||
-#if _STRING_ARCH_unaligned || !defined DEFINE_UNALIGNED
|
||||
-# define FCTNAME2(name) name
|
||||
-#else
|
||||
-# define FCTNAME2(name) name##_unaligned
|
||||
-#endif
|
||||
-#define FCTNAME(name) FCTNAME2(name)
|
||||
+#define FCTNAME(name) name
|
||||
|
||||
|
||||
/* We need at least one byte for the next round. */
|
||||
@@ -282,20 +277,9 @@ FCTNAME (LOOPFCT) (struct __gconv_step *step,
|
||||
}
|
||||
|
||||
|
||||
-/* Include the file a second time to define the function to handle
|
||||
- unaligned access. */
|
||||
-#if !defined DEFINE_UNALIGNED && !_STRING_ARCH_unaligned \
|
||||
- && MIN_NEEDED_INPUT != 1 && MAX_NEEDED_INPUT % MIN_NEEDED_INPUT == 0 \
|
||||
- && MIN_NEEDED_OUTPUT != 1 && MAX_NEEDED_OUTPUT % MIN_NEEDED_OUTPUT == 0
|
||||
-# undef unaligned
|
||||
-
|
||||
-# define DEFINE_UNALIGNED
|
||||
-# include "loop.c"
|
||||
-# undef DEFINE_UNALIGNED
|
||||
-#else
|
||||
-# if MAX_NEEDED_INPUT > 1
|
||||
-# define SINGLE(fct) SINGLE2 (fct)
|
||||
-# define SINGLE2(fct) fct##_single
|
||||
+#if MAX_NEEDED_INPUT > 1
|
||||
+# define SINGLE(fct) SINGLE2 (fct)
|
||||
+# define SINGLE2(fct) fct##_single
|
||||
static inline int
|
||||
__attribute ((always_inline))
|
||||
SINGLE(LOOPFCT) (struct __gconv_step *step,
|
||||
@@ -305,37 +289,37 @@ SINGLE(LOOPFCT) (struct __gconv_step *step,
|
||||
size_t *irreversible EXTRA_LOOP_DECLS)
|
||||
{
|
||||
mbstate_t *state = step_data->__statep;
|
||||
-# ifdef LOOP_NEED_FLAGS
|
||||
+# ifdef LOOP_NEED_FLAGS
|
||||
int flags = step_data->__flags;
|
||||
-# endif
|
||||
-# ifdef LOOP_NEED_DATA
|
||||
+# endif
|
||||
+# ifdef LOOP_NEED_DATA
|
||||
void *data = step->__data;
|
||||
-# endif
|
||||
+# endif
|
||||
int result = __GCONV_OK;
|
||||
unsigned char bytebuf[MAX_NEEDED_INPUT];
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t inlen;
|
||||
|
||||
-# ifdef INIT_PARAMS
|
||||
+# ifdef INIT_PARAMS
|
||||
INIT_PARAMS;
|
||||
-# endif
|
||||
+# endif
|
||||
|
||||
-# ifdef UNPACK_BYTES
|
||||
+# ifdef UNPACK_BYTES
|
||||
UNPACK_BYTES
|
||||
-# else
|
||||
+# else
|
||||
/* Add the bytes from the state to the input buffer. */
|
||||
assert ((state->__count & 7) <= sizeof (state->__value));
|
||||
for (inlen = 0; inlen < (size_t) (state->__count & 7); ++inlen)
|
||||
bytebuf[inlen] = state->__value.__wchb[inlen];
|
||||
-# endif
|
||||
+# endif
|
||||
|
||||
/* Are there enough bytes in the input buffer? */
|
||||
if (MIN_NEEDED_INPUT > 1
|
||||
&& __builtin_expect (inptr + (MIN_NEEDED_INPUT - inlen) > inend, 0))
|
||||
{
|
||||
*inptrp = inend;
|
||||
-# ifdef STORE_REST
|
||||
+# ifdef STORE_REST
|
||||
|
||||
/* Building with -O3 GCC emits a `array subscript is above array
|
||||
bounds' warning. GCC BZ #64739 has been opened for this. */
|
||||
@@ -350,14 +334,14 @@ SINGLE(LOOPFCT) (struct __gconv_step *step,
|
||||
inend = &bytebuf[inlen];
|
||||
|
||||
STORE_REST
|
||||
-# else
|
||||
+# else
|
||||
/* We don't have enough input for another complete input
|
||||
character. */
|
||||
size_t inlen_after = inlen + (inend - inptr);
|
||||
assert (inlen_after <= sizeof (state->__value.__wchb));
|
||||
for (; inlen < inlen_after; inlen++)
|
||||
state->__value.__wchb[inlen] = *inptr++;
|
||||
-# endif
|
||||
+# endif
|
||||
|
||||
return __GCONV_INCOMPLETE_INPUT;
|
||||
}
|
||||
@@ -403,11 +387,11 @@ SINGLE(LOOPFCT) (struct __gconv_step *step,
|
||||
result = __GCONV_OK;
|
||||
|
||||
/* Clear the state buffer. */
|
||||
-# ifdef CLEAR_STATE
|
||||
+# ifdef CLEAR_STATE
|
||||
CLEAR_STATE;
|
||||
-# else
|
||||
+# else
|
||||
state->__count &= ~7;
|
||||
-# endif
|
||||
+# endif
|
||||
}
|
||||
else if (result == __GCONV_INCOMPLETE_INPUT)
|
||||
{
|
||||
@@ -416,11 +400,11 @@ SINGLE(LOOPFCT) (struct __gconv_step *step,
|
||||
assert (inend != &bytebuf[MAX_NEEDED_INPUT]);
|
||||
|
||||
*inptrp += inend - bytebuf - (state->__count & 7);
|
||||
-# ifdef STORE_REST
|
||||
+# ifdef STORE_REST
|
||||
inptrp = &inptr;
|
||||
|
||||
STORE_REST
|
||||
-# else
|
||||
+# else
|
||||
/* We don't have enough input for another complete input
|
||||
character. */
|
||||
assert (inend - inptr > (state->__count & ~7));
|
||||
@@ -429,14 +413,13 @@ SINGLE(LOOPFCT) (struct __gconv_step *step,
|
||||
for (inlen = 0; inlen < inend - inptr; inlen++)
|
||||
state->__value.__wchb[inlen] = inptr[inlen];
|
||||
inptr = inend;
|
||||
-# endif
|
||||
+# endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
-# undef SINGLE
|
||||
-# undef SINGLE2
|
||||
-# endif
|
||||
+# undef SINGLE
|
||||
+# undef SINGLE2
|
||||
|
||||
|
||||
# ifdef ONEBYTE_BODY
|
||||
@@ -468,4 +451,3 @@ gconv_btowc (struct __gconv_step *step, unsigned char c)
|
||||
#undef LOOP_NEED_STATE
|
||||
#undef LOOP_NEED_FLAGS
|
||||
#undef LOOP_NEED_DATA
|
||||
-#undef unaligned
|
||||
diff --git a/iconv/skeleton.c b/iconv/skeleton.c
|
||||
index 6992701808079ec2..e7933ae333a5eae5 100644
|
||||
--- a/iconv/skeleton.c
|
||||
+++ b/iconv/skeleton.c
|
||||
@@ -451,33 +451,6 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
size_t lirreversible = 0;
|
||||
size_t *lirreversiblep = irreversible ? &lirreversible : NULL;
|
||||
|
||||
- /* The following assumes that encodings, which have a variable length
|
||||
- what might unalign a buffer even though it is an aligned in the
|
||||
- beginning, either don't have the minimal number of bytes as a divisor
|
||||
- of the maximum length or have a minimum length of 1. This is true
|
||||
- for all known and supported encodings.
|
||||
- We use && instead of || to combine the subexpression for the FROM
|
||||
- encoding and for the TO encoding, because usually one of them is
|
||||
- INTERNAL, for which the subexpression evaluates to 1, but INTERNAL
|
||||
- buffers are always aligned correctly. */
|
||||
-#define POSSIBLY_UNALIGNED \
|
||||
- (!_STRING_ARCH_unaligned \
|
||||
- && (((FROM_LOOP_MIN_NEEDED_FROM != 1 \
|
||||
- && FROM_LOOP_MAX_NEEDED_FROM % FROM_LOOP_MIN_NEEDED_FROM == 0) \
|
||||
- && (FROM_LOOP_MIN_NEEDED_TO != 1 \
|
||||
- && FROM_LOOP_MAX_NEEDED_TO % FROM_LOOP_MIN_NEEDED_TO == 0)) \
|
||||
- || ((TO_LOOP_MIN_NEEDED_FROM != 1 \
|
||||
- && TO_LOOP_MAX_NEEDED_FROM % TO_LOOP_MIN_NEEDED_FROM == 0) \
|
||||
- && (TO_LOOP_MIN_NEEDED_TO != 1 \
|
||||
- && TO_LOOP_MAX_NEEDED_TO % TO_LOOP_MIN_NEEDED_TO == 0))))
|
||||
-#if POSSIBLY_UNALIGNED
|
||||
- int unaligned;
|
||||
-# define GEN_unaligned(name) GEN_unaligned2 (name)
|
||||
-# define GEN_unaligned2(name) name##_unaligned
|
||||
-#else
|
||||
-# define unaligned 0
|
||||
-#endif
|
||||
-
|
||||
#ifdef PREPARE_LOOP
|
||||
PREPARE_LOOP
|
||||
#endif
|
||||
@@ -517,18 +490,6 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
}
|
||||
#endif
|
||||
|
||||
-#if POSSIBLY_UNALIGNED
|
||||
- unaligned =
|
||||
- ((FROM_DIRECTION
|
||||
- && ((uintptr_t) inptr % FROM_LOOP_MIN_NEEDED_FROM != 0
|
||||
- || ((data->__flags & __GCONV_IS_LAST)
|
||||
- && (uintptr_t) outbuf % FROM_LOOP_MIN_NEEDED_TO != 0)))
|
||||
- || (!FROM_DIRECTION
|
||||
- && (((data->__flags & __GCONV_IS_LAST)
|
||||
- && (uintptr_t) outbuf % TO_LOOP_MIN_NEEDED_TO != 0)
|
||||
- || (uintptr_t) inptr % TO_LOOP_MIN_NEEDED_FROM != 0)));
|
||||
-#endif
|
||||
-
|
||||
while (1)
|
||||
{
|
||||
/* Remember the start value for this round. */
|
||||
@@ -546,34 +507,14 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
SAVE_RESET_STATE (1);
|
||||
#endif
|
||||
|
||||
- if (__glibc_likely (!unaligned))
|
||||
- {
|
||||
- if (FROM_DIRECTION)
|
||||
- /* Run the conversion loop. */
|
||||
- status = FROM_LOOP (step, data, inptrp, inend, &outbuf, outend,
|
||||
- lirreversiblep EXTRA_LOOP_ARGS);
|
||||
- else
|
||||
- /* Run the conversion loop. */
|
||||
- status = TO_LOOP (step, data, inptrp, inend, &outbuf, outend,
|
||||
- lirreversiblep EXTRA_LOOP_ARGS);
|
||||
- }
|
||||
-#if POSSIBLY_UNALIGNED
|
||||
+ if (FROM_DIRECTION)
|
||||
+ /* Run the conversion loop. */
|
||||
+ status = FROM_LOOP (step, data, inptrp, inend, &outbuf, outend,
|
||||
+ lirreversiblep EXTRA_LOOP_ARGS);
|
||||
else
|
||||
- {
|
||||
- if (FROM_DIRECTION)
|
||||
- /* Run the conversion loop. */
|
||||
- status = GEN_unaligned (FROM_LOOP) (step, data, inptrp, inend,
|
||||
- &outbuf, outend,
|
||||
- lirreversiblep
|
||||
- EXTRA_LOOP_ARGS);
|
||||
- else
|
||||
- /* Run the conversion loop. */
|
||||
- status = GEN_unaligned (TO_LOOP) (step, data, inptrp, inend,
|
||||
- &outbuf, outend,
|
||||
- lirreversiblep
|
||||
- EXTRA_LOOP_ARGS);
|
||||
- }
|
||||
-#endif
|
||||
+ /* Run the conversion loop. */
|
||||
+ status = TO_LOOP (step, data, inptrp, inend, &outbuf, outend,
|
||||
+ lirreversiblep EXTRA_LOOP_ARGS);
|
||||
|
||||
/* If we were called as part of an error handling module we
|
||||
don't do anything else here. */
|
||||
@@ -638,41 +579,18 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
SAVE_RESET_STATE (0);
|
||||
#endif
|
||||
|
||||
- if (__glibc_likely (!unaligned))
|
||||
- {
|
||||
- if (FROM_DIRECTION)
|
||||
- /* Run the conversion loop. */
|
||||
- nstatus = FROM_LOOP (step, data, inptrp, inend,
|
||||
- &outbuf, outerr,
|
||||
- lirreversiblep
|
||||
- EXTRA_LOOP_ARGS);
|
||||
- else
|
||||
- /* Run the conversion loop. */
|
||||
- nstatus = TO_LOOP (step, data, inptrp, inend,
|
||||
- &outbuf, outerr,
|
||||
- lirreversiblep
|
||||
- EXTRA_LOOP_ARGS);
|
||||
- }
|
||||
-#if POSSIBLY_UNALIGNED
|
||||
+ if (FROM_DIRECTION)
|
||||
+ /* Run the conversion loop. */
|
||||
+ nstatus = FROM_LOOP (step, data, inptrp, inend,
|
||||
+ &outbuf, outerr,
|
||||
+ lirreversiblep
|
||||
+ EXTRA_LOOP_ARGS);
|
||||
else
|
||||
- {
|
||||
- if (FROM_DIRECTION)
|
||||
- /* Run the conversion loop. */
|
||||
- nstatus = GEN_unaligned (FROM_LOOP) (step, data,
|
||||
- inptrp, inend,
|
||||
- &outbuf,
|
||||
- outerr,
|
||||
- lirreversiblep
|
||||
- EXTRA_LOOP_ARGS);
|
||||
- else
|
||||
- /* Run the conversion loop. */
|
||||
- nstatus = GEN_unaligned (TO_LOOP) (step, data,
|
||||
- inptrp, inend,
|
||||
- &outbuf, outerr,
|
||||
- lirreversiblep
|
||||
- EXTRA_LOOP_ARGS);
|
||||
- }
|
||||
-#endif
|
||||
+ /* Run the conversion loop. */
|
||||
+ nstatus = TO_LOOP (step, data, inptrp, inend,
|
||||
+ &outbuf, outerr,
|
||||
+ lirreversiblep
|
||||
+ EXTRA_LOOP_ARGS);
|
||||
|
||||
/* We must run out of output buffer space in this
|
||||
rerun. */
|
||||
326
SOURCES/glibc-RHEL-162901-3.patch
Normal file
326
SOURCES/glibc-RHEL-162901-3.patch
Normal file
@ -0,0 +1,326 @@
|
||||
commit d6f08d1cf027f4eb2ba289a6cc66853722d4badc
|
||||
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>
|
||||
|
||||
Conflicts:
|
||||
iconvdata/Makefile
|
||||
(fixup context)
|
||||
|
||||
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
|
||||
index 25bd004e7f92a994..798f9be86d376aeb 100644
|
||||
--- a/iconvdata/Makefile
|
||||
+++ b/iconvdata/Makefile
|
||||
@@ -75,7 +75,8 @@ ifeq (yes,$(build-shared))
|
||||
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
|
||||
+ bug-iconv13 bug-iconv14 bug-iconv15 \
|
||||
+ tst-iconv-iso-2022-cn-ext tst-bug33980
|
||||
ifeq ($(have-thread-library),yes)
|
||||
tests += bug-iconv3
|
||||
endif
|
||||
@@ -332,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 18f1aa4f6da4b021..c3e9b7c881eaa1d9 100644
|
||||
--- a/iconvdata/ibm1364.c
|
||||
+++ b/iconvdata/ibm1364.c
|
||||
@@ -68,12 +68,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 \
|
||||
@@ -100,11 +117,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. */
|
||||
};
|
||||
|
||||
|
||||
@@ -120,21 +139,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
|
||||
@@ -154,7 +181,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 0000000000000000..c9693e0efebe4eae
|
||||
--- /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>
|
||||
184
SOURCES/glibc-RHEL-168096.patch
Normal file
184
SOURCES/glibc-RHEL-168096.patch
Normal file
@ -0,0 +1,184 @@
|
||||
commit d8997716a1ca22cf038eac86ed286830ba9818cc
|
||||
Author: DJ Delorie <dj@redhat.com>
|
||||
Date: Wed Apr 1 17:52:25 2026 -0400
|
||||
|
||||
nss: fix __get_default_domain logic
|
||||
|
||||
Fix logic bug in __nss_get_default_domain that prevents
|
||||
proper initialization.
|
||||
|
||||
Because this function is not exposed, the test case must link
|
||||
against the object directly.
|
||||
|
||||
Bug origin commit: 64d1e08ea822bf47cb2796ad0f727136227f983c
|
||||
|
||||
Co-authored-by: Florian Weimer <fweimer@redhat.com>
|
||||
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
nss/Makefile
|
||||
(fixup context)
|
||||
|
||||
diff --git a/nss/Makefile b/nss/Makefile
|
||||
index 4d128da0a366301f..4d22ef2661fb9b27 100644
|
||||
--- a/nss/Makefile
|
||||
+++ b/nss/Makefile
|
||||
@@ -61,6 +61,7 @@ tests := \
|
||||
bug17079 \
|
||||
test-digits-dots \
|
||||
test-netdb \
|
||||
+ tst-default-domain \
|
||||
tst-nss-getpwent \
|
||||
tst-nss-malloc-failure-getlogin_r \
|
||||
tst-nss-test1 \
|
||||
@@ -226,6 +227,8 @@ endif
|
||||
$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)libnss_files.so
|
||||
$(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)libnss_files.so
|
||||
|
||||
+$(objpfx)tst-default-domain: $(objpfx)nisdomain.os
|
||||
+
|
||||
tst-nss-gai-hv2-canonname-ENV = \
|
||||
MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \
|
||||
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
|
||||
diff --git a/nss/nss_compat/nisdomain.c b/nss/nss_compat/nisdomain.c
|
||||
index 838fd95820a47767..899b323f63d90076 100644
|
||||
--- a/nss/nss_compat/nisdomain.c
|
||||
+++ b/nss/nss_compat/nisdomain.c
|
||||
@@ -36,7 +36,7 @@ __nss_get_default_domain (char **outdomain)
|
||||
|
||||
__libc_lock_lock (domainname_lock);
|
||||
|
||||
- if (domainname[0] != '\0')
|
||||
+ if (domainname[0] == '\0')
|
||||
{
|
||||
if (getdomainname (domainname, MAXDOMAINNAMELEN) < 0)
|
||||
result = errno;
|
||||
diff --git a/nss/tst-default-domain.c b/nss/tst-default-domain.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..2fa9153d8802d4c3
|
||||
--- /dev/null
|
||||
+++ b/nss/tst-default-domain.c
|
||||
@@ -0,0 +1,123 @@
|
||||
+/* Basic test of __nss_get_default_domain
|
||||
+ 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 <unistd.h>
|
||||
+#include <string.h>
|
||||
+#include <dlfcn.h>
|
||||
+
|
||||
+#include "nss_compat/nisdomain.h"
|
||||
+
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/namespace.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+char unset_domain[] = "unset_domain";
|
||||
+char new_domain[] = "new_domain";
|
||||
+
|
||||
+/* This function checks the __nss_get_default_domain() function in
|
||||
+ nss_compat/nssdomain.c. Because this is an internal function to
|
||||
+ libnss_compat.so, the Makefile will link that object to this test
|
||||
+ case directly. */
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ char *domain_name;
|
||||
+ char buf[1024];
|
||||
+
|
||||
+ /* We need to be in a network namespace so we can change the domain
|
||||
+ name without interfering with the host system. */
|
||||
+ support_become_root ();
|
||||
+ support_enter_network_namespace ();
|
||||
+ if (!support_in_uts_namespace ())
|
||||
+ return EXIT_UNSUPPORTED;
|
||||
+
|
||||
+ /* First pass: set an empty domain and make sure it's returned
|
||||
+ correctly. This should not be cached. */
|
||||
+
|
||||
+ /* Set the domain name to a known value. */
|
||||
+ TEST_VERIFY (setdomainname ("", 0) == 0);
|
||||
+
|
||||
+ /* Make sure it got set. */
|
||||
+ TEST_VERIFY (getdomainname (buf, sizeof(buf)) == 0);
|
||||
+ TEST_COMPARE_STRING (buf, "");
|
||||
+
|
||||
+ /* Set this to a known "unknown" value so we can detect if it's not
|
||||
+ changed. */
|
||||
+ domain_name = unset_domain;
|
||||
+
|
||||
+ /* This is the function we're testing. */
|
||||
+ TEST_VERIFY (__nss_get_default_domain (& domain_name) == 0);
|
||||
+
|
||||
+ /* Make sure the correct domain name is returned. */
|
||||
+ TEST_VERIFY (domain_name != NULL);
|
||||
+ TEST_COMPARE_STRING (domain_name, "");
|
||||
+
|
||||
+ /* Second pass: set a non-empty domain and make sure it's returned
|
||||
+ correctly. This works because the empty domain is not
|
||||
+ cached. */
|
||||
+
|
||||
+ /* Set the domain name to a known value. */
|
||||
+ TEST_VERIFY (setdomainname (new_domain, strlen (new_domain)) == 0);
|
||||
+
|
||||
+ /* Make sure it got set. */
|
||||
+ TEST_VERIFY (getdomainname (buf, sizeof(buf)) == 0);
|
||||
+ TEST_COMPARE_STRING (buf, new_domain);
|
||||
+
|
||||
+ /* Set this to a known "unknown" value so we can detect if it's not
|
||||
+ changed. */
|
||||
+ domain_name = unset_domain;
|
||||
+
|
||||
+ /* This is the function we're testing. */
|
||||
+ TEST_VERIFY (__nss_get_default_domain (& domain_name) == 0);
|
||||
+
|
||||
+ /* Make sure the correct domain name is returned. */
|
||||
+ TEST_VERIFY (domain_name != NULL);
|
||||
+ TEST_COMPARE_STRING (domain_name, new_domain);
|
||||
+
|
||||
+ /* The function caches the name, so check it twice. */
|
||||
+ TEST_VERIFY (__nss_get_default_domain (& domain_name) == 0);
|
||||
+
|
||||
+ TEST_VERIFY (domain_name != NULL);
|
||||
+ TEST_COMPARE_STRING (domain_name, new_domain);
|
||||
+
|
||||
+ /* Third pass: set an empty domain again but expect the cached
|
||||
+ value. */
|
||||
+
|
||||
+ /* Set the domain name to a known value. */
|
||||
+ TEST_VERIFY (setdomainname ("", 0) == 0);
|
||||
+
|
||||
+ /* Make sure it got set. */
|
||||
+ TEST_VERIFY (getdomainname (buf, sizeof(buf)) == 0);
|
||||
+ TEST_COMPARE_STRING (buf, "");
|
||||
+
|
||||
+ /* Set this to a known "unknown" value so we can detect if it's not
|
||||
+ changed. */
|
||||
+ domain_name = unset_domain;
|
||||
+
|
||||
+ /* This is the function we're testing. */
|
||||
+ TEST_VERIFY (__nss_get_default_domain (& domain_name) == 0);
|
||||
+
|
||||
+ TEST_VERIFY (domain_name != NULL);
|
||||
+ TEST_COMPARE_STRING (domain_name, new_domain);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
234
SOURCES/glibc-RHEL-168851.patch
Normal file
234
SOURCES/glibc-RHEL-168851.patch
Normal file
@ -0,0 +1,234 @@
|
||||
commit 5663ab0b833df187b15e7bb4b18173e22beb8bd1
|
||||
Author: Carlos O'Donell <carlos@redhat.com>
|
||||
Date: Fri Mar 20 16:43:33 2026 -0400
|
||||
|
||||
resolv: Count records correctly (CVE-2026-4437)
|
||||
|
||||
The answer section boundary was previously ignored, and the code in
|
||||
getanswer_ptr would iterate past the last resource record, but not
|
||||
beyond the end of the returned data. This could lead to subsequent data
|
||||
being interpreted as answer records, thus violating the DNS
|
||||
specification. Such resource records could be maliciously crafted and
|
||||
hidden from other tooling, but processed by the glibc stub resolver and
|
||||
acted upon by the application. While we trust the data returned by the
|
||||
configured recursive resolvers, we should not trust its format and
|
||||
should validate it as required. It is a security issue to incorrectly
|
||||
process the DNS protocol.
|
||||
|
||||
A regression test is added for response section crossing.
|
||||
|
||||
No regressions on x86_64-linux-gnu.
|
||||
|
||||
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
|
||||
(cherry picked from commit 9f5f18aab40ec6b61fa49a007615e6077e9a979b)
|
||||
|
||||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||||
index 116ab6a1574eb1ff..649c1254c30d40c6 100644
|
||||
--- a/resolv/Makefile
|
||||
+++ b/resolv/Makefile
|
||||
@@ -108,6 +108,7 @@ tests += \
|
||||
tst-resolv-basic \
|
||||
tst-resolv-binary \
|
||||
tst-resolv-byaddr \
|
||||
+ tst-resolv-dns-section \
|
||||
tst-resolv-edns \
|
||||
tst-resolv-invalid-cname \
|
||||
tst-resolv-network \
|
||||
@@ -119,6 +120,7 @@ tests += \
|
||||
tst-resolv-semi-failure \
|
||||
tst-resolv-short-response \
|
||||
tst-resolv-trailing \
|
||||
+ # tests
|
||||
|
||||
# This test calls __res_context_send directly, which is not exported
|
||||
# from libresolv.
|
||||
@@ -288,6 +290,8 @@ $(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
+$(objpfx)tst-resolv-dns-section: $(objpfx)libresolv.so \
|
||||
+ $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so
|
||||
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
|
||||
index 3d261b6810bba5c9..54d6e2822d3454ca 100644
|
||||
--- a/resolv/nss_dns/dns-host.c
|
||||
+++ b/resolv/nss_dns/dns-host.c
|
||||
@@ -821,7 +821,7 @@ getanswer_ptr (unsigned char *packet, size_t packetlen,
|
||||
/* expected_name may be updated to point into this buffer. */
|
||||
unsigned char name_buffer[NS_MAXCDNAME];
|
||||
|
||||
- while (ancount > 0)
|
||||
+ for (; ancount > 0; --ancount)
|
||||
{
|
||||
struct ns_rr_wire rr;
|
||||
if (!__ns_rr_cursor_next (&c, &rr))
|
||||
diff --git a/resolv/tst-resolv-dns-section.c b/resolv/tst-resolv-dns-section.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..1171baef51e3cc36
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-resolv-dns-section.c
|
||||
@@ -0,0 +1,162 @@
|
||||
+/* Test handling of invalid section transitions (bug 34014).
|
||||
+ Copyright (C) 2022-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 <array_length.h>
|
||||
+#include <errno.h>
|
||||
+#include <netdb.h>
|
||||
+#include <resolv.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/format_nss.h>
|
||||
+#include <support/resolv_test.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+/* Name of test, and the second section type. */
|
||||
+struct item {
|
||||
+ const char *test;
|
||||
+ int ns_section;
|
||||
+};
|
||||
+
|
||||
+static const struct item test_items[] =
|
||||
+ {
|
||||
+ { "Test crossing from ns_s_an to ns_s_ar.", ns_s_ar },
|
||||
+ { "Test crossing from ns_s_an to ns_s_an.", ns_s_ns },
|
||||
+
|
||||
+ { NULL, 0 },
|
||||
+ };
|
||||
+
|
||||
+/* The response is designed to contain the following:
|
||||
+ - An Answer section with one T_PTR record that is skipped.
|
||||
+ - A second section with a semantically invalid T_PTR record.
|
||||
+ The original defect is that the response parsing would cross
|
||||
+ section boundaries and handle the additional section T_PTR
|
||||
+ as if it were an answer. A conforming implementation would
|
||||
+ stop as soon as it reaches the end of the section. */
|
||||
+static void
|
||||
+response (const struct resolv_response_context *ctx,
|
||||
+ struct resolv_response_builder *b,
|
||||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
+{
|
||||
+ TEST_COMPARE (qclass, C_IN);
|
||||
+
|
||||
+ /* We only test PTR. */
|
||||
+ TEST_COMPARE (qtype, T_PTR);
|
||||
+
|
||||
+ unsigned int count;
|
||||
+ char *tail = NULL;
|
||||
+
|
||||
+ if (strstr (qname, "in-addr.arpa") != NULL
|
||||
+ && sscanf (qname, "%u.%ms", &count, &tail) == 2)
|
||||
+ TEST_COMPARE_STRING (tail, "0.168.192.in-addr.arpa");
|
||||
+ else if (sscanf (qname, "%x.%ms", &count, &tail) == 2)
|
||||
+ {
|
||||
+ TEST_COMPARE_STRING (tail, "\
|
||||
+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
|
||||
+ }
|
||||
+ else
|
||||
+ FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
|
||||
+ free (tail);
|
||||
+
|
||||
+ /* We have a bounded number of possible tests. */
|
||||
+ TEST_VERIFY (count >= 0);
|
||||
+ TEST_VERIFY (count <= 15);
|
||||
+
|
||||
+ struct resolv_response_flags flags = {};
|
||||
+ resolv_response_init (b, flags);
|
||||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||||
+ resolv_response_section (b, ns_s_an);
|
||||
+
|
||||
+ /* Actual answer record, but the wrong name (skipped). */
|
||||
+ resolv_response_open_record (b, "1.0.0.10.in-addr.arpa", qclass, qtype, 60);
|
||||
+
|
||||
+ /* Record the answer. */
|
||||
+ resolv_response_add_name (b, "test.ptr.example.net");
|
||||
+ resolv_response_close_record (b);
|
||||
+
|
||||
+ /* Add a second section to test section boundary crossing. */
|
||||
+ resolv_response_section (b, test_items[count].ns_section);
|
||||
+ /* Semantically incorrect, but hide a T_PTR entry. */
|
||||
+ resolv_response_open_record (b, qname, qclass, qtype, 60);
|
||||
+ resolv_response_add_name (b, "wrong.ptr.example.net");
|
||||
+ resolv_response_close_record (b);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* Perform one check using a reverse lookup. */
|
||||
+static void
|
||||
+check_reverse (int af, int count)
|
||||
+{
|
||||
+ TEST_VERIFY (af == AF_INET || af == AF_INET6);
|
||||
+ TEST_VERIFY (count < array_length (test_items));
|
||||
+
|
||||
+ char addr[sizeof (struct in6_addr)] = { 0 };
|
||||
+ socklen_t addrlen;
|
||||
+ if (af == AF_INET)
|
||||
+ {
|
||||
+ addr[0] = (char) 192;
|
||||
+ addr[1] = (char) 168;
|
||||
+ addr[2] = (char) 0;
|
||||
+ addr[3] = (char) count;
|
||||
+ addrlen = 4;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ addr[0] = 0x20;
|
||||
+ addr[1] = 0x01;
|
||||
+ addr[2] = 0x0d;
|
||||
+ addr[3] = 0xb8;
|
||||
+ addr[4] = addr[5] = addr[6] = addr[7] = 0x0;
|
||||
+ addr[8] = addr[9] = addr[10] = addr[11] = 0x0;
|
||||
+ addr[12] = 0x0;
|
||||
+ addr[13] = 0x0;
|
||||
+ addr[14] = 0x0;
|
||||
+ addr[15] = count;
|
||||
+ addrlen = 16;
|
||||
+ }
|
||||
+
|
||||
+ h_errno = 0;
|
||||
+ struct hostent *answer = gethostbyaddr (addr, addrlen, af);
|
||||
+ TEST_VERIFY (answer == NULL);
|
||||
+ TEST_VERIFY (h_errno == NO_RECOVERY);
|
||||
+ if (answer != NULL)
|
||||
+ printf ("error: unexpected success: %s\n",
|
||||
+ support_format_hostent (answer));
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ struct resolv_test *obj = resolv_test_start
|
||||
+ ((struct resolv_redirect_config)
|
||||
+ {
|
||||
+ .response_callback = response
|
||||
+ });
|
||||
+
|
||||
+ for (int i = 0; test_items[i].test != NULL; i++)
|
||||
+ {
|
||||
+ check_reverse (AF_INET, i);
|
||||
+ check_reverse (AF_INET6, i);
|
||||
+ }
|
||||
+
|
||||
+ resolv_test_end (obj);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
318
SOURCES/glibc-RHEL-168852.patch
Normal file
318
SOURCES/glibc-RHEL-168852.patch
Normal file
@ -0,0 +1,318 @@
|
||||
commit 9344c796f7a4ac8f2c59de63f3e1e936b51e817d
|
||||
Author: Carlos O'Donell <carlos@redhat.com>
|
||||
Date: Fri Mar 20 17:14:33 2026 -0400
|
||||
|
||||
resolv: Check hostname for validity (CVE-2026-4438)
|
||||
|
||||
The processed hostname in getanswer_ptr should be correctly checked to
|
||||
avoid invalid characters from being allowed, including shell
|
||||
metacharacters. It is a security issue to fail to check the returned
|
||||
hostname for validity.
|
||||
|
||||
A regression test is added for invalid metacharacters and other cases
|
||||
of invalid or valid characters.
|
||||
|
||||
No regressions on x86_64-linux-gnu.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit e10977481f4db4b2a3ce34fa4c3a1e26651ae312)
|
||||
|
||||
Conflicts:
|
||||
resolv/Makefile
|
||||
(fixup context)
|
||||
|
||||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||||
index 649c1254c30d40c6..aa25c71f1eea9c28 100644
|
||||
--- a/resolv/Makefile
|
||||
+++ b/resolv/Makefile
|
||||
@@ -111,6 +111,7 @@ tests += \
|
||||
tst-resolv-dns-section \
|
||||
tst-resolv-edns \
|
||||
tst-resolv-invalid-cname \
|
||||
+ tst-resolv-invalid-ptr \
|
||||
tst-resolv-network \
|
||||
tst-resolv-noaaaa \
|
||||
tst-resolv-noaaaa-vc \
|
||||
@@ -302,6 +303,8 @@ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
|
||||
$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
$(objpfx)tst-resolv-no-search: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
+$(objpfx)tst-resolv-invalid-ptr: $(objpfx)libresolv.so \
|
||||
+ $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
|
||||
index 54d6e2822d3454ca..2016131b24a55145 100644
|
||||
--- a/resolv/nss_dns/dns-host.c
|
||||
+++ b/resolv/nss_dns/dns-host.c
|
||||
@@ -867,7 +867,7 @@ getanswer_ptr (unsigned char *packet, size_t packetlen,
|
||||
char hname[MAXHOSTNAMELEN + 1];
|
||||
if (__ns_name_unpack (c.begin, c.end, rr.rdata,
|
||||
name_buffer, sizeof (name_buffer)) < 0
|
||||
- || !__res_binary_hnok (expected_name)
|
||||
+ || !__res_binary_hnok (name_buffer)
|
||||
|| __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
|
||||
{
|
||||
*h_errnop = NO_RECOVERY;
|
||||
diff --git a/resolv/tst-resolv-invalid-ptr.c b/resolv/tst-resolv-invalid-ptr.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..0c802ab96780efb0
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-resolv-invalid-ptr.c
|
||||
@@ -0,0 +1,255 @@
|
||||
+/* Test handling of invalid T_PTR results (bug 34015).
|
||||
+ Copyright (C) 2022-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 <array_length.h>
|
||||
+#include <errno.h>
|
||||
+#include <netdb.h>
|
||||
+#include <resolv.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/format_nss.h>
|
||||
+#include <support/resolv_test.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+/* Name of test, the answer, the expected error return, and if we
|
||||
+ expect the call to fail. */
|
||||
+struct item {
|
||||
+ const char *test;
|
||||
+ const char *answer;
|
||||
+ int expected;
|
||||
+ bool fail;
|
||||
+};
|
||||
+
|
||||
+static const struct item test_items[] =
|
||||
+ {
|
||||
+ /* Test for invalid characters. */
|
||||
+ { "Invalid use of \"|\"",
|
||||
+ "test.|.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"&\"",
|
||||
+ "test.&.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \";\"",
|
||||
+ "test.;.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"<\"",
|
||||
+ "test.<.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \">\"",
|
||||
+ "test.>.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"(\"",
|
||||
+ "test.(.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \")\"",
|
||||
+ "test.).ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"$\"",
|
||||
+ "test.$.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"`\"",
|
||||
+ "test.`.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"\\\"",
|
||||
+ "test.\\.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"\'\"",
|
||||
+ "test.'.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"\"\"",
|
||||
+ "test.\".ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \" \"",
|
||||
+ "test. .ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"\\t\"",
|
||||
+ "test.\t.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"\\n\"",
|
||||
+ "test.\n.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"\\r\"",
|
||||
+ "test.\r.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"*\"",
|
||||
+ "test.*.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"?\"",
|
||||
+ "test.?.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"[\"",
|
||||
+ "test.[.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"]\"",
|
||||
+ "test.].ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \",\"",
|
||||
+ "test.,.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"~\"",
|
||||
+ "test.~.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \":\"",
|
||||
+ "test.:.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"!\"",
|
||||
+ "test.!.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"@\"",
|
||||
+ "test.@.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"#\"",
|
||||
+ "test.#.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"%\"",
|
||||
+ "test.%%.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of \"^\"",
|
||||
+ "test.^.ptr.example", NO_RECOVERY, true },
|
||||
+
|
||||
+ /* Test for invalid UTF-8 characters (2-byte, 4-byte, 6-byte). */
|
||||
+ { "Invalid use of UTF-8 (2-byte, U+00C0-U+00C2)",
|
||||
+ "ÁÂÃ.test.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of UTF-8 (4-byte, U+0750-U+0752)",
|
||||
+ "ݐݑݒ.test.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Invalid use of UTF-8 (6-byte, U+0904-U+0906)",
|
||||
+ "ऄअआ.test.ptr.example", NO_RECOVERY, true },
|
||||
+
|
||||
+ /* Test for "-" which may be valid depending on position. */
|
||||
+ { "Invalid leading \"-\"",
|
||||
+ "-test.ptr.example", NO_RECOVERY, true },
|
||||
+ { "Valid trailing \"-\"",
|
||||
+ "test-.ptr.example", 0, false },
|
||||
+ { "Valid mid-label use of \"-\"",
|
||||
+ "te-st.ptr.example", 0, false },
|
||||
+
|
||||
+ /* Test for "_" which is always valid in any position. */
|
||||
+ { "Valid leading use of \"_\"",
|
||||
+ "_test.ptr.example", 0, false },
|
||||
+ { "Valid mid-label use of \"_\"",
|
||||
+ "te_st.ptr.example", 0, false },
|
||||
+ { "Valid trailing use of \"_\"",
|
||||
+ "test_.ptr.example", 0, false },
|
||||
+
|
||||
+ /* Sanity test the broader set [A-Za-z0-9_-] of valid characters. */
|
||||
+ { "Valid \"[A-Z]\"",
|
||||
+ "test.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ptr.example", 0, false },
|
||||
+ { "Valid \"[a-z]\"",
|
||||
+ "test.abcdefghijklmnopqrstuvwxyz.ptr.example", 0, false },
|
||||
+ { "Valid \"[0-9]\"",
|
||||
+ "test.0123456789.ptr.example", 0, false },
|
||||
+ { "Valid mixed use of \"[A-Za-z0-9_-]\"",
|
||||
+ "test.012abcABZ_-.ptr.example", 0, false },
|
||||
+ };
|
||||
+
|
||||
+static void
|
||||
+response (const struct resolv_response_context *ctx,
|
||||
+ struct resolv_response_builder *b,
|
||||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
+{
|
||||
+ TEST_COMPARE (qclass, C_IN);
|
||||
+
|
||||
+ /* We only test PTR. */
|
||||
+ TEST_COMPARE (qtype, T_PTR);
|
||||
+
|
||||
+ unsigned int count, count1;
|
||||
+ char *tail = NULL;
|
||||
+
|
||||
+ /* The test implementation can handle up to 255 tests. */
|
||||
+ if (strstr (qname, "in-addr.arpa") != NULL
|
||||
+ && sscanf (qname, "%u.%ms", &count, &tail) == 2)
|
||||
+ TEST_COMPARE_STRING (tail, "0.168.192.in-addr.arpa");
|
||||
+ else if (sscanf (qname, "%x.%x.%ms", &count, &count1, &tail) == 3)
|
||||
+ {
|
||||
+ TEST_COMPARE_STRING (tail, "\
|
||||
+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
|
||||
+ count |= count1 << 4;
|
||||
+ }
|
||||
+ else
|
||||
+ FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
|
||||
+ free (tail);
|
||||
+
|
||||
+ /* Cross check. Count has a fixed bound (soft limit). */
|
||||
+ TEST_VERIFY (count >= 0 && count <= 255);
|
||||
+
|
||||
+ /* We have a fixed number of tests (hard limit). */
|
||||
+ TEST_VERIFY_EXIT (count < array_length (test_items));
|
||||
+
|
||||
+ struct resolv_response_flags flags = {};
|
||||
+ resolv_response_init (b, flags);
|
||||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||||
+ resolv_response_section (b, ns_s_an);
|
||||
+
|
||||
+ /* Actual answer record. */
|
||||
+ resolv_response_open_record (b, qname, qclass, qtype, 60);
|
||||
+
|
||||
+ /* Record the answer. */
|
||||
+ resolv_response_add_name (b, test_items[count].answer);
|
||||
+ resolv_response_close_record (b);
|
||||
+}
|
||||
+
|
||||
+/* Perform one check using a reverse lookup. */
|
||||
+static void
|
||||
+check_reverse (int af, int count)
|
||||
+{
|
||||
+ TEST_VERIFY (af == AF_INET || af == AF_INET6);
|
||||
+ TEST_VERIFY_EXIT (count < array_length (test_items));
|
||||
+
|
||||
+ /* Generate an address to query for each test. */
|
||||
+ char addr[sizeof (struct in6_addr)] = { 0 };
|
||||
+ socklen_t addrlen;
|
||||
+ if (af == AF_INET)
|
||||
+ {
|
||||
+ addr[0] = (char) 192;
|
||||
+ addr[1] = (char) 168;
|
||||
+ addr[2] = (char) 0;
|
||||
+ addr[3] = (char) count;
|
||||
+ addrlen = 4;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ addr[0] = 0x20;
|
||||
+ addr[1] = 0x01;
|
||||
+ addr[2] = 0x0d;
|
||||
+ addr[3] = 0xb8;
|
||||
+ addr[4] = addr[5] = addr[6] = addr[7] = 0x0;
|
||||
+ addr[8] = addr[9] = addr[10] = addr[11] = 0x0;
|
||||
+ addr[12] = 0x0;
|
||||
+ addr[13] = 0x0;
|
||||
+ addr[14] = 0x0;
|
||||
+ addr[15] = (char) count;
|
||||
+ addrlen = 16;
|
||||
+ }
|
||||
+
|
||||
+ h_errno = 0;
|
||||
+ struct hostent *answer = gethostbyaddr (addr, addrlen, af);
|
||||
+
|
||||
+ /* Verify h_errno is as expected. */
|
||||
+ TEST_COMPARE (h_errno, test_items[count].expected);
|
||||
+ if (h_errno != test_items[count].expected)
|
||||
+ /* And print more information if it's not. */
|
||||
+ printf ("INFO: %s\n", test_items[count].test);
|
||||
+
|
||||
+ if (test_items[count].fail)
|
||||
+ {
|
||||
+ /* We expected a failure so verify answer is NULL. */
|
||||
+ TEST_VERIFY (answer == NULL);
|
||||
+ /* If it's not NULL we should print out what we received. */
|
||||
+ if (answer != NULL)
|
||||
+ printf ("error: unexpected success: %s\n",
|
||||
+ support_format_hostent (answer));
|
||||
+ }
|
||||
+ else
|
||||
+ /* We don't expect a failure so answer must be valid. */
|
||||
+ TEST_COMPARE_STRING (answer->h_name, test_items[count].answer);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ struct resolv_test *obj = resolv_test_start
|
||||
+ ((struct resolv_redirect_config)
|
||||
+ {
|
||||
+ .response_callback = response
|
||||
+ });
|
||||
+
|
||||
+ for (int i = 0; i < array_length (test_items); i++)
|
||||
+ {
|
||||
+ check_reverse (AF_INET, i);
|
||||
+ check_reverse (AF_INET6, i);
|
||||
+ }
|
||||
+ resolv_test_end (obj);
|
||||
+
|
||||
+ 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,
|
||||
117
SOURCES/glibc-RHEL-178279.patch
Normal file
117
SOURCES/glibc-RHEL-178279.patch
Normal file
@ -0,0 +1,117 @@
|
||||
commit e9325bd7d04aacc45cf39505e279b1ca9de22c08
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Jun 9 07:28:02 2026 +0200
|
||||
|
||||
iconv: Suppress intermediate errors with //TRANSLIT (bug 34236)
|
||||
|
||||
When tentatively converting characters on behalf of
|
||||
__gconv_transliterate, do not create a persistent error. Just
|
||||
produce a local error, and rely on __gconv_transliterate to
|
||||
produce the error if all transliteration options are exhausted.
|
||||
|
||||
This fixes transliteration of “½” to ASCII, which cannot use the
|
||||
“ 1⁄2 ” alternative. Eventually, the “ 1/2 ” alternative is chosen,
|
||||
but the error sticks. Therefore, iconv exited with status 1 before
|
||||
this change.
|
||||
|
||||
Adjust iconv/tst-iconv_prog.sh to test both C and en_US.UTF-8 locales.
|
||||
This requires changing the way the ICONV template is defined, so that
|
||||
run_program_env is evaluated multiple times.
|
||||
|
||||
Fixes commit 9a4b0eaf726f5404c6683d5c7c5e86f61c3f3fbc ("iconv: do not
|
||||
report error exit with transliteration [BZ #32448]"),
|
||||
commit 6cbf845fcdc76131d0e674cee454fe738b69c69d ("iconv: Preserve
|
||||
iconv -c error exit on invalid inputs (bug 32046)"), and bug 34236.
|
||||
|
||||
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
Conflicts:
|
||||
iconv/Makefile
|
||||
(adjust for slight context differences)
|
||||
iconv/tst-iconv_prog.sh
|
||||
(adjust for slight context differences)
|
||||
|
||||
diff -Nrup a/iconv/Makefile b/iconv/Makefile
|
||||
--- a/iconv/Makefile 2026-07-10 15:33:08.645711776 -0400
|
||||
+++ b/iconv/Makefile 2026-07-10 15:35:00.893038141 -0400
|
||||
@@ -130,7 +130,8 @@ $(objpfx)test-iconvconfig.out: $(objpfx)
|
||||
rm -f $$tmp) > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
-$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog
|
||||
+$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog \
|
||||
+ $(gen-locales)
|
||||
$(BASH) $< $(common-objdir) '$(test-wrapper-env)' \
|
||||
'$(run-program-env)' > $@; \
|
||||
$(evaluate-test)
|
||||
diff --git a/iconv/loop.c b/iconv/loop.c
|
||||
index 27dea1f5d6..81841d0d2d 100644
|
||||
--- a/iconv/loop.c
|
||||
+++ b/iconv/loop.c
|
||||
@@ -144,8 +144,10 @@
|
||||
if (irreversible == NULL) \
|
||||
{ \
|
||||
/* This means we are in call from __gconv_transliterate. In this \
|
||||
- case we are not doing any error recovery ourselves. */ \
|
||||
- result = __gconv_mark_illegal_input (step_data); \
|
||||
+ case we are not doing any error recovery ourselves. Do not create \
|
||||
+ a persistent error state. If __gconv_transliterate exhausts all \
|
||||
+ alternatives, it will call __gconv_mark_illegal_input itself. */ \
|
||||
+ result = __GCONV_ILLEGAL_INPUT; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
diff -Nrup a/iconv/tst-iconv_prog.sh b/iconv/tst-iconv_prog.sh
|
||||
--- a/iconv/tst-iconv_prog.sh 2026-07-15 11:10:33.321344932 -0400
|
||||
+++ b/iconv/tst-iconv_prog.sh 2026-07-15 11:16:10.328740778 -0400
|
||||
@@ -27,10 +27,10 @@ LIBPATH=$codir:$codir/iconvdata
|
||||
|
||||
# How the start the iconv(1) program. $from is not defined/expanded yet.
|
||||
ICONV='
|
||||
+$test_wrapper_env $run_program_env
|
||||
$codir/elf/ld.so --library-path $LIBPATH --inhibit-rpath ${from}.so
|
||||
$codir/iconv/iconv_prog
|
||||
'
|
||||
-ICONV="$test_wrapper_env $run_program_env $ICONV"
|
||||
|
||||
# List of known hangs;
|
||||
# Gathered by running an exhaustive 2 byte input search against glibc-2.28
|
||||
@@ -216,6 +216,7 @@ testarray=(
|
||||
"\x00\x00;;INVALID;UTF-8;1"
|
||||
"\x00\x00;;UTF-8;INVALID;1"
|
||||
"\xc3\xa9;;UTF-8;ASCII//TRANSLIT;0"
|
||||
+"X\xc2\xbdY;;UTF-8;ASCII//TRANSLIT;0"
|
||||
)
|
||||
|
||||
# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret
|
||||
@@ -275,12 +276,21 @@ check_errtest_result ()
|
||||
fi
|
||||
}
|
||||
|
||||
-for testcommand in "${testarray[@]}"; do
|
||||
- twobyte="$(echo "$testcommand" | cut -d";" -f 1)"
|
||||
- c="$(echo "$testcommand" | cut -d";" -f 2)"
|
||||
- from="$(echo "$testcommand" | cut -d";" -f 3)"
|
||||
- to="$(echo "$testcommand" | cut -d";" -f 4)"
|
||||
- eret="$(echo "$testcommand" | cut -d";" -f 5)"
|
||||
- execute_test
|
||||
- check_errtest_result
|
||||
-done
|
||||
+run_test_array ()
|
||||
+{
|
||||
+ for testcommand in "${testarray[@]}"; do
|
||||
+ twobyte="$(echo "$testcommand" | cut -d";" -f 1)"
|
||||
+ c="$(echo "$testcommand" | cut -d";" -f 2)"
|
||||
+ from="$(echo "$testcommand" | cut -d";" -f 3)"
|
||||
+ to="$(echo "$testcommand" | cut -d";" -f 4)"
|
||||
+ eret="$(echo "$testcommand" | cut -d";" -f 5)"
|
||||
+ execute_test
|
||||
+ check_errtest_result
|
||||
+ done
|
||||
+}
|
||||
+
|
||||
+echo "info: testing C locale"
|
||||
+run_test_array
|
||||
+echo "info: testing en_US.UTF-8 locale"
|
||||
+run_program_env="$run_program_env LC_ALL=en_US.UTF-8"
|
||||
+run_test_array
|
||||
47
SOURCES/glibc-RHEL-180336-1.patch
Normal file
47
SOURCES/glibc-RHEL-180336-1.patch
Normal file
@ -0,0 +1,47 @@
|
||||
commit 360f352c9a6da545d798ef3015e73ca114f0d230
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jun 19 18:22:20 2026 +0200
|
||||
|
||||
resolv: Declare __p_class_syms, __p_type_syms for internal use
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/include/resolv.h b/include/resolv.h
|
||||
index 4dbbac3800..d5ad9994b9 100644
|
||||
--- a/include/resolv.h
|
||||
+++ b/include/resolv.h
|
||||
@@ -70,6 +70,11 @@ libc_hidden_proto (__libc_res_nameinquery)
|
||||
extern __typeof (__res_queriesmatch) __libc_res_queriesmatch;
|
||||
libc_hidden_proto (__libc_res_queriesmatch)
|
||||
|
||||
+extern const struct res_sym __p_class_syms[];
|
||||
+libresolv_hidden_proto (__p_class_syms)
|
||||
+extern const struct res_sym __p_type_syms[];
|
||||
+libresolv_hidden_proto (__p_type_syms)
|
||||
+
|
||||
/* Variant of res_hnok which operates on binary (but uncompressed) names. */
|
||||
bool __res_binary_hnok (const unsigned char *dn) attribute_hidden;
|
||||
|
||||
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
|
||||
index 73af0c72fe..6bf9962916 100644
|
||||
--- a/resolv/res_debug.c
|
||||
+++ b/resolv/res_debug.c
|
||||
@@ -390,8 +390,6 @@ p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
|
||||
* that C_ANY is a qclass but not a class. (You can ask for records of class
|
||||
* C_ANY, but you can't have any records of that class in the database.)
|
||||
*/
|
||||
-extern const struct res_sym __p_class_syms[];
|
||||
-libresolv_hidden_proto (__p_class_syms)
|
||||
const struct res_sym __p_class_syms[] = {
|
||||
{C_IN, (char *) "IN"},
|
||||
{C_CHAOS, (char *) "CHAOS"},
|
||||
@@ -426,8 +424,6 @@ const struct res_sym __p_update_section_syms[] attribute_hidden = {
|
||||
* Names of RR types and qtypes. The list is incomplete because its
|
||||
* size is part of the ABI.
|
||||
*/
|
||||
-extern const struct res_sym __p_type_syms[];
|
||||
-libresolv_hidden_proto (__p_type_syms)
|
||||
const struct res_sym __p_type_syms[] = {
|
||||
{ns_t_a, (char *) "A", (char *) "address"},
|
||||
{ns_t_ns, (char *) "NS", (char *) "name server"},
|
||||
70
SOURCES/glibc-RHEL-180336-2.patch
Normal file
70
SOURCES/glibc-RHEL-180336-2.patch
Normal file
@ -0,0 +1,70 @@
|
||||
commit f69b7f95e3694177546faec25d88bb266885c3b8
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jun 19 18:22:20 2026 +0200
|
||||
|
||||
resolv: Fix ns_sprintrrf formatting of class, type values (bug 34289)
|
||||
|
||||
The p_class and p_type results could overwrite each other if both
|
||||
were unknown. Format unknown values with CLASS and TYPE prefixes,
|
||||
as in RFC 3597. Handle A6 separately because it cannot be added
|
||||
to __p_type_syms for ABI reasons.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/resolv/ns_print.c b/resolv/ns_print.c
|
||||
index cef2212fd2..e75c39eaa8 100644
|
||||
--- a/resolv/ns_print.c
|
||||
+++ b/resolv/ns_print.c
|
||||
@@ -78,6 +78,24 @@ ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
|
||||
}
|
||||
libresolv_hidden_def (ns_sprintrr)
|
||||
|
||||
+/* Writes the class/type symbol NUMBER to *BUF, using the name from
|
||||
+ *SYMS if possible. If NUMBER is not found in *SYMS, print the
|
||||
+ number with PREFIX. */
|
||||
+static int
|
||||
+addsym (const struct res_sym *syms, int number, const char *prefix,
|
||||
+ char **buf, size_t *buflen)
|
||||
+{
|
||||
+ for (; syms->name != NULL; syms++)
|
||||
+ if (number == syms->number)
|
||||
+ {
|
||||
+ T (addstr (" ", 1, buf, buflen));
|
||||
+ return addstr (syms->name, strlen (syms->name), buf, buflen);
|
||||
+ }
|
||||
+ char tmp[20];
|
||||
+ int len = snprintf (tmp, sizeof (tmp), " %s%d", prefix, number);
|
||||
+ return addstr (tmp, len, buf, buflen);
|
||||
+}
|
||||
+
|
||||
/*%
|
||||
* Convert the fields of an RR into presentation format.
|
||||
*
|
||||
@@ -128,11 +146,21 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
/*
|
||||
* TTL, Class, Type.
|
||||
*/
|
||||
- T(x = ns_format_ttl(ttl, buf, buflen));
|
||||
- addlen(x, &buf, &buflen);
|
||||
- len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
|
||||
- T(addstr(tmp, len, &buf, &buflen));
|
||||
- T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
|
||||
+ {
|
||||
+ char *start = buf;
|
||||
+
|
||||
+ T (x = ns_format_ttl (ttl, buf, buflen));
|
||||
+ addlen (x, &buf, &buflen);
|
||||
+ T (addsym (__p_class_syms, class, "CLASS", &buf, &buflen));
|
||||
+ if (type == ns_t_a6)
|
||||
+ /* A6 is not part of __p_type_syms, which is exported.
|
||||
+ Adding A6 there would change its size. Handle it here. */
|
||||
+ T (addstr (" A6", 3, &buf, &buflen));
|
||||
+ else
|
||||
+ T (addsym (__p_type_syms, type, "TYPE", &buf, &buflen));
|
||||
+
|
||||
+ T (spaced = addtab(buf - start, 16, spaced, &buf, &buflen));
|
||||
+ }
|
||||
|
||||
/*
|
||||
* RData.
|
||||
48
SOURCES/glibc-RHEL-180336-3.patch
Normal file
48
SOURCES/glibc-RHEL-180336-3.patch
Normal file
@ -0,0 +1,48 @@
|
||||
commit d58415eb17d457a160af99f9e8ab164404ca151b
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jun 19 18:22:20 2026 +0200
|
||||
|
||||
resolv: Improve formatting of unknown records in ns_sprintrrf
|
||||
|
||||
Do not add the "unknown RR type" comment. After adding the TYPE
|
||||
prefix, the number is largely redundant.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/resolv/ns_print.c b/resolv/ns_print.c
|
||||
index e75c39eaa8..3d38876483 100644
|
||||
--- a/resolv/ns_print.c
|
||||
+++ b/resolv/ns_print.c
|
||||
@@ -115,7 +115,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
|
||||
const char *comment;
|
||||
char tmp[100];
|
||||
- char errbuf[40];
|
||||
int len, x;
|
||||
|
||||
/*
|
||||
@@ -590,20 +589,18 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
break;
|
||||
}
|
||||
-
|
||||
default:
|
||||
- snprintf (errbuf, sizeof (errbuf), "unknown RR type %d", type);
|
||||
- comment = errbuf;
|
||||
+ comment = "";
|
||||
goto hexify;
|
||||
}
|
||||
return (buf - obuf);
|
||||
formerr:
|
||||
- comment = "RR format error";
|
||||
+ comment = " ; RR format error";
|
||||
hexify: {
|
||||
int n, m;
|
||||
char *p;
|
||||
|
||||
- len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
|
||||
+ len = SPRINTF((tmp, "\\# %u%s%s", (unsigned)(edata - rdata),
|
||||
rdlen != 0U ? " (" : "", comment));
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
while (rdata < edata) {
|
||||
63
SOURCES/glibc-RHEL-180336-4.patch
Normal file
63
SOURCES/glibc-RHEL-180336-4.patch
Normal file
@ -0,0 +1,63 @@
|
||||
commit cd0db208d56a2cecd528b8ae96df752ba5344d9a
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jun 19 18:22:20 2026 +0200
|
||||
|
||||
resolv: Check for inet_ntop failure in ns_sprintrrf
|
||||
|
||||
This makes the output more consistent (either failure or complete
|
||||
output) and helps with systematic testing with varying buffer
|
||||
sizes.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/resolv/ns_print.c b/resolv/ns_print.c
|
||||
index 3d38876483..e58df5f35a 100644
|
||||
--- a/resolv/ns_print.c
|
||||
+++ b/resolv/ns_print.c
|
||||
@@ -167,8 +167,9 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
switch (type) {
|
||||
case ns_t_a:
|
||||
if (rdlen != (size_t)NS_INADDRSZ)
|
||||
- goto formerr;
|
||||
- (void) inet_ntop(AF_INET, rdata, buf, buflen);
|
||||
+ goto formerr;
|
||||
+ if (inet_ntop (AF_INET, rdata, buf, buflen) == NULL)
|
||||
+ return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
break;
|
||||
|
||||
@@ -334,9 +335,10 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
}
|
||||
|
||||
case ns_t_aaaa:
|
||||
- if (rdlen != (size_t)NS_IN6ADDRSZ)
|
||||
- goto formerr;
|
||||
- (void) inet_ntop(AF_INET6, rdata, buf, buflen);
|
||||
+ if (rdlen != (size_t)NS_IN6ADDRSZ)
|
||||
+ goto formerr;
|
||||
+ if (inet_ntop (AF_INET6, rdata, buf, buflen) == NULL)
|
||||
+ return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
break;
|
||||
|
||||
@@ -427,7 +429,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
goto formerr;
|
||||
|
||||
/* Address. */
|
||||
- (void) inet_ntop(AF_INET, rdata, buf, buflen);
|
||||
+ if (inet_ntop (AF_INET, rdata, buf, buflen) == NULL)
|
||||
+ return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
rdata += NS_INADDRSZ;
|
||||
|
||||
@@ -569,7 +572,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
if (rdata + pbyte >= edata) goto formerr;
|
||||
memset(&a, 0, sizeof(a));
|
||||
memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
|
||||
- (void) inet_ntop(AF_INET6, &a, buf, buflen);
|
||||
+ if (inet_ntop (AF_INET6, &a, buf, buflen) == NULL)
|
||||
+ return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
rdata += sizeof(a) - pbyte;
|
||||
}
|
||||
130
SOURCES/glibc-RHEL-180336-5.patch
Normal file
130
SOURCES/glibc-RHEL-180336-5.patch
Normal file
@ -0,0 +1,130 @@
|
||||
commit ca44a6609c29a683b03575fa035c6d17aa591e72
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jun 19 18:22:20 2026 +0200
|
||||
|
||||
resolv: More types as unknown in ns_sprintrrf (CVE-2026-5435)
|
||||
|
||||
Specifically, CERT, TKEY, TSIG, OPT. This removes the buggy
|
||||
implementations of TSIG, fixing bug 34033, and partially
|
||||
fixing bug 34069.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
resolv/ns_print.c
|
||||
Account for typo fix in 7f0d9e61f40c
|
||||
|
||||
diff --git a/resolv/ns_print.c b/resolv/ns_print.c
|
||||
index e58df5f35a..ab68bf2cb7 100644
|
||||
--- a/resolv/ns_print.c
|
||||
+++ b/resolv/ns_print.c
|
||||
@@ -464,96 +464,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
break;
|
||||
}
|
||||
|
||||
- case ns_t_cert: {
|
||||
- u_int c_type, key_tag, alg;
|
||||
- int n;
|
||||
- unsigned int siz;
|
||||
- char base64_cert[8192], tmp[40];
|
||||
- const char *leader;
|
||||
-
|
||||
- c_type = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
- key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
- alg = (u_int) *rdata++;
|
||||
-
|
||||
- len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
|
||||
- T(addstr(tmp, len, &buf, &buflen));
|
||||
- siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
|
||||
- if (siz > sizeof(base64_cert) * 3/4) {
|
||||
- const char *str = "record too long to print";
|
||||
- T(addstr(str, strlen(str), &buf, &buflen));
|
||||
- }
|
||||
- else {
|
||||
- len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
|
||||
-
|
||||
- if (len < 0)
|
||||
- goto formerr;
|
||||
- else if (len > 15) {
|
||||
- T(addstr(" (", 2, &buf, &buflen));
|
||||
- leader = "\n\t\t";
|
||||
- spaced = 0;
|
||||
- }
|
||||
- else
|
||||
- leader = " ";
|
||||
-
|
||||
- for (n = 0; n < len; n += 48) {
|
||||
- T(addstr(leader, strlen(leader),
|
||||
- &buf, &buflen));
|
||||
- T(addstr(base64_cert + n, MIN(len - n, 48),
|
||||
- &buf, &buflen));
|
||||
- }
|
||||
- if (len > 15)
|
||||
- T(addstr(" )", 2, &buf, &buflen));
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- case ns_t_tkey: {
|
||||
- /* KJD - need to complete this */
|
||||
- u_long t;
|
||||
- int mode, err, keysize;
|
||||
-
|
||||
- /* Algorithm name. */
|
||||
- T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
|
||||
- T(addstr(" ", 1, &buf, &buflen));
|
||||
-
|
||||
- /* Inception. */
|
||||
- t = ns_get32(rdata); rdata += NS_INT32SZ;
|
||||
- len = SPRINTF((tmp, "%lu ", t));
|
||||
- T(addstr(tmp, len, &buf, &buflen));
|
||||
-
|
||||
- /* Experation. */
|
||||
- t = ns_get32(rdata); rdata += NS_INT32SZ;
|
||||
- len = SPRINTF((tmp, "%lu ", t));
|
||||
- T(addstr(tmp, len, &buf, &buflen));
|
||||
-
|
||||
- /* Mode , Error, Key Size. */
|
||||
- /* Priority, Weight, Port. */
|
||||
- mode = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
- err = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
- keysize = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
- len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
|
||||
- T(addstr(tmp, len, &buf, &buflen));
|
||||
-
|
||||
- /* XXX need to dump key, print otherdata length & other data */
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- case ns_t_tsig: {
|
||||
- /* BEW - need to complete this */
|
||||
- int n;
|
||||
-
|
||||
- T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
|
||||
- T(addstr(" ", 1, &buf, &buflen));
|
||||
- rdata += 8; /*%< time */
|
||||
- n = ns_get16(rdata); rdata += INT16SZ;
|
||||
- rdata += n; /*%< sig */
|
||||
- n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
|
||||
- sprintf(buf, "%d", ns_get16(rdata));
|
||||
- rdata += INT16SZ;
|
||||
- addlen(strlen(buf), &buf, &buflen);
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
case ns_t_a6: {
|
||||
struct in6_addr a;
|
||||
int pbyte, pbit;
|
||||
@@ -588,11 +498,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
break;
|
||||
}
|
||||
|
||||
- case ns_t_opt: {
|
||||
- len = SPRINTF((tmp, "%u bytes", class));
|
||||
- T(addstr(tmp, len, &buf, &buflen));
|
||||
- break;
|
||||
- }
|
||||
default:
|
||||
comment = "";
|
||||
goto hexify;
|
||||
59
SOURCES/glibc-RHEL-180336-6.patch
Normal file
59
SOURCES/glibc-RHEL-180336-6.patch
Normal file
@ -0,0 +1,59 @@
|
||||
commit a7b60d23bbb56eaef59f4962e4140062e552600a
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jun 19 18:22:20 2026 +0200
|
||||
|
||||
resolv: Fix buffer overreads in ns_sprintrrf (CVE-2026-6238)
|
||||
|
||||
Check that the RDATA payload does not require more than RDATALEN
|
||||
bytes while processing it. The fixes cover A6, LOC records.
|
||||
(CERT, TKEY, TSIG were fixed before, by switching to the generic
|
||||
formatter.)
|
||||
|
||||
The vulnerable LOC record handling was first introduced before
|
||||
glibc 2.0, in commit ee188d555b8c32ad9704a7440cab400af967292f.
|
||||
|
||||
CERT, TSIG, TKEY handling came with commit
|
||||
b43b13ac2544b11f35be301d1589b51a8473e32b, released with glibc 2.2.
|
||||
|
||||
A6 record handling was introduced in commit
|
||||
91633816430e7ec5a19fe3ff510a7c4822a9557e ("* resolv/ns_print.c
|
||||
(ns_sprintrrf): Handle ns_t_a6 and ns_t_opt."), which went into glibc
|
||||
2.7.
|
||||
|
||||
This fixes bug 34069.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/resolv/ns_print.c b/resolv/ns_print.c
|
||||
index ab68bf2cb7..f9dd086804 100644
|
||||
--- a/resolv/ns_print.c
|
||||
+++ b/resolv/ns_print.c
|
||||
@@ -345,7 +345,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
case ns_t_loc: {
|
||||
char t[255];
|
||||
|
||||
- /* XXX protocol format checking? */
|
||||
+ if (rdlen != 16)
|
||||
+ goto formerr;
|
||||
(void) loc_ntoa(rdata, t);
|
||||
T(addstr(t, strlen(t), &buf, &buflen));
|
||||
break;
|
||||
@@ -479,13 +480,14 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
|
||||
/* address suffix: provided only when prefix len != 128 */
|
||||
if (pbit < 128) {
|
||||
- if (rdata + pbyte >= edata) goto formerr;
|
||||
+ unsigned int bytelen = sizeof(a) - pbyte;
|
||||
+ if (edata - rdata < bytelen) goto formerr;
|
||||
memset(&a, 0, sizeof(a));
|
||||
- memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
|
||||
+ memcpy(&a.s6_addr[pbyte], rdata, bytelen);
|
||||
if (inet_ntop (AF_INET6, &a, buf, buflen) == NULL)
|
||||
return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
- rdata += sizeof(a) - pbyte;
|
||||
+ rdata += bytelen;
|
||||
}
|
||||
|
||||
/* prefix name: provided only when prefix len > 0 */
|
||||
371
SOURCES/glibc-RHEL-180336-7.patch
Normal file
371
SOURCES/glibc-RHEL-180336-7.patch
Normal file
@ -0,0 +1,371 @@
|
||||
commit 4ba0b79b9596e5a4951cc9eaa1546a55e543e083
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jun 19 18:22:20 2026 +0200
|
||||
|
||||
resolv: Add test case tst-ns_sprintrr (bug 34033, bug 34069)
|
||||
|
||||
This test case covers both input buffer overreads and output buffer
|
||||
overflows. It should systematically cover these issues.
|
||||
|
||||
I used code auto-generation for updating the test expectations for
|
||||
truncated RDATA in TXT, ISDN records, after writing the rest
|
||||
of the test by hand.
|
||||
|
||||
Assisted-by: LLM
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||||
index 68b3a4dbf3..02cc751732 100644
|
||||
--- a/resolv/Makefile
|
||||
+++ b/resolv/Makefile
|
||||
@@ -108,6 +108,7 @@ tests += \
|
||||
tst-ns_name \
|
||||
tst-ns_name_compress \
|
||||
tst-ns_name_pton \
|
||||
+ tst-ns_sprintrr \
|
||||
tst-res_hconf_reorder \
|
||||
tst-res_hnok \
|
||||
tst-resolv-aliases \
|
||||
@@ -341,5 +342,6 @@ $(objpfx)tst-ns_name: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-ns_name.out: tst-ns_name.data
|
||||
$(objpfx)tst-ns_name_compress: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-ns_name_pton: $(objpfx)libresolv.so
|
||||
+$(objpfx)tst-ns_sprintrr: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-res_hnok: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-p_secstodate: $(objpfx)libresolv.so
|
||||
diff --git a/resolv/tst-ns_sprintrr.c b/resolv/tst-ns_sprintrr.c
|
||||
new file mode 100644
|
||||
index 0000000000..34739b5924
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-ns_sprintrr.c
|
||||
@@ -0,0 +1,329 @@
|
||||
+/* Tests for the ns_sprintrr function.
|
||||
+ 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 <arpa/nameser.h>
|
||||
+
|
||||
+#include <alloc_buffer.h>
|
||||
+#include <arpa/inet.h>
|
||||
+#include <libc-diag.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/next_to_fault.h>
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+/* Regions that test_one_record uses for input and output. */
|
||||
+static struct support_next_to_fault ntf_in;
|
||||
+static struct support_next_to_fault ntf_out;
|
||||
+
|
||||
+/* This is used by test_one_record to construct the packet. */
|
||||
+static const char packet_prefix[] =
|
||||
+ /* DNS response with one question, one answer record. */
|
||||
+ "AA\x81\x80\0\1\0\1\0\0\0\0"
|
||||
+ /* Question: www.example.org/IN/ANY. */
|
||||
+ "\3www\7example\3org\0\0\xff\0\1"
|
||||
+ /* Response: compression reference. */
|
||||
+ "\xc0\x0c";
|
||||
+
|
||||
+/* Use ns_sprintrr to format a DNS record (starting with
|
||||
+ packet_prefix) of type RTYPE, with a record payload of RDATALEN
|
||||
+ bytes starting at RDATA. Check successful formatting against
|
||||
+ EXPECTED. Try various truncated input and output buffers to catch
|
||||
+ overreads and buffer overflows, using ntf_in and ntf_out above. */
|
||||
+static void
|
||||
+test_one_record (uint16_t rtype, const char *rdata, size_t rdatalen,
|
||||
+ const char *expected)
|
||||
+{
|
||||
+ struct rr_header
|
||||
+ {
|
||||
+ uint16_t typ;
|
||||
+ uint16_t cls;
|
||||
+ uint32_t ttl;
|
||||
+ uint16_t rdatalen;
|
||||
+ uint16_t pad;
|
||||
+ } hdr =
|
||||
+ {
|
||||
+ .typ = htons (rtype),
|
||||
+ .cls = htons (ns_c_in),
|
||||
+ .ttl = htonl (86400), /* One day. */
|
||||
+ .rdatalen = htons (rdatalen),
|
||||
+ };
|
||||
+ enum { hdrlen = offsetof (struct rr_header, pad) };
|
||||
+ TEST_COMPARE (hdrlen, 10);
|
||||
+
|
||||
+ /* Construct the packet from packet_prefix, hdr, and rdata. */
|
||||
+ unsigned char packet[512];
|
||||
+ size_t packetlen;
|
||||
+ {
|
||||
+ struct alloc_buffer buf = alloc_buffer_create (packet, sizeof (packet));
|
||||
+ alloc_buffer_copy_bytes (&buf, packet_prefix, sizeof (packet_prefix) - 1);
|
||||
+ alloc_buffer_copy_bytes (&buf, &hdr, hdrlen);
|
||||
+ alloc_buffer_copy_bytes (&buf, rdata, rdatalen);
|
||||
+ packetlen = sizeof (packet) - alloc_buffer_size (&buf);
|
||||
+ }
|
||||
+
|
||||
+ /* Parse the record. */
|
||||
+ ns_msg msg;
|
||||
+ TEST_COMPARE (ns_initparse (packet, packetlen, &msg), 0);
|
||||
+ ns_rr rr;
|
||||
+ TEST_COMPARE (ns_parserr (&msg, ns_s_an, 0, &rr), 0);
|
||||
+
|
||||
+ /* Try sizes up to this limit. Go a bit beyond the expected size to
|
||||
+ check for errors. */
|
||||
+ size_t max_result_size = strlen (expected) + 16;
|
||||
+
|
||||
+ bool success = false;
|
||||
+ for (size_t result_size = 1; result_size <= max_result_size; ++result_size)
|
||||
+ {
|
||||
+ char *result_start = ntf_out.buffer + ntf_out.length - result_size;
|
||||
+ memset (result_start, 'X', result_size);
|
||||
+
|
||||
+ /* ns_sprintrr was deprecated in 2.34. */
|
||||
+ DIAG_PUSH_NEEDS_COMMENT;
|
||||
+ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
|
||||
+ int ret = ns_sprintrr (&msg, &rr, NULL, NULL, result_start, result_size);
|
||||
+ DIAG_POP_NEEDS_COMMENT;
|
||||
+
|
||||
+ if (ret > 0)
|
||||
+ {
|
||||
+ TEST_COMPARE_STRING (result_start, expected);
|
||||
+ TEST_COMPARE (ret, strlen (expected));
|
||||
+ success = true;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ TEST_VERIFY (!success);
|
||||
+ TEST_COMPARE (ret, -1);
|
||||
+ }
|
||||
+ }
|
||||
+ TEST_VERIFY (success);
|
||||
+
|
||||
+ /* Test with truncated RDATA. */
|
||||
+ for (size_t rdata_size = 0; rdata_size <= rdatalen; ++rdata_size)
|
||||
+ {
|
||||
+ size_t truncated_packet_size = packetlen - rdatalen + rdata_size;
|
||||
+ unsigned char *packet_start
|
||||
+ = ((unsigned char *) ntf_in.buffer + ntf_in.length
|
||||
+ - truncated_packet_size);
|
||||
+ memcpy (packet_start, packet, truncated_packet_size);
|
||||
+ /* Patch in the updated RDATA length field. */
|
||||
+ uint16_t new_rdatalen = htons (rdata_size);
|
||||
+ memcpy (packet_start + truncated_packet_size - rdata_size - 2,
|
||||
+ &new_rdatalen, 2);
|
||||
+
|
||||
+ ns_msg msg;
|
||||
+ TEST_COMPARE (ns_initparse (packet_start, truncated_packet_size, &msg),
|
||||
+ 0);
|
||||
+ ns_rr rr;
|
||||
+ TEST_COMPARE (ns_parserr (&msg, ns_s_an, 0, &rr), 0);
|
||||
+
|
||||
+ size_t result_size = strlen (expected) + 1;
|
||||
+ char *result_start = ntf_out.buffer + ntf_out.length - result_size;
|
||||
+ memset (result_start, 'X', result_size);
|
||||
+
|
||||
+ /* ns_sprintrr was deprecated in 2.34. */
|
||||
+ DIAG_PUSH_NEEDS_COMMENT;
|
||||
+ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
|
||||
+ int ret = ns_sprintrr (&msg, &rr, NULL, NULL, result_start, result_size);
|
||||
+ DIAG_POP_NEEDS_COMMENT;
|
||||
+
|
||||
+ /* This flag indicates whether the output is syntactically
|
||||
+ correct. In some cases, truncation may still yield a valid
|
||||
+ payload. */
|
||||
+ bool broken = rdata_size < rdatalen;
|
||||
+ switch (rtype)
|
||||
+ {
|
||||
+ case ns_t_wks:
|
||||
+ /* WKS records use all trailing bytes for the port bitmap. */
|
||||
+ broken = rdata_size < 5;
|
||||
+ break;
|
||||
+ case ns_t_nsap:
|
||||
+ /* Uses all bytes that are available. */
|
||||
+ broken = false;
|
||||
+ break;
|
||||
+ case ns_t_txt:
|
||||
+ /* Truncation produces a valid payload if it occurs right
|
||||
+ after a complete string in the TXT payload. */
|
||||
+ broken = false;
|
||||
+ for (size_t pos = 0; pos < rdata_size; )
|
||||
+ {
|
||||
+ unsigned int slen = rdata[pos] & 0xff;
|
||||
+ if (pos + 1 + slen > rdata_size)
|
||||
+ {
|
||||
+ broken = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ pos += 1 + slen;
|
||||
+ }
|
||||
+ break;
|
||||
+ case ns_t_isdn:
|
||||
+ /* The second field is optional. If it is present, it must
|
||||
+ not be truncated. */
|
||||
+ broken = rdata_size < 6 || (rdata_size > 6 && rdata_size < rdatalen);
|
||||
+ break;
|
||||
+ case ns_t_a6:
|
||||
+ /* The first A6 subtest contains a trailing domain name,
|
||||
+ which is ignored and not formatted. */
|
||||
+ if (rdata_size > 0 && rdata[0] == 0)
|
||||
+ broken = rdata_size < 17;
|
||||
+ break;
|
||||
+ case ns_t_cert:
|
||||
+ case ns_t_tkey:
|
||||
+ case ns_t_tsig:
|
||||
+ /* Only generic printing, which does not validate anything. */
|
||||
+ broken = false;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (broken)
|
||||
+ {
|
||||
+ if (strstr (result_start, "RR format error") != NULL)
|
||||
+ /* No further checks if an error indicator has been added
|
||||
+ to the output. */
|
||||
+ ;
|
||||
+ else
|
||||
+ TEST_COMPARE (ret, -1);
|
||||
+ }
|
||||
+ else
|
||||
+ TEST_VERIFY (ret > 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ ntf_in = support_next_to_fault_allocate (512);
|
||||
+ ntf_out = support_next_to_fault_allocate (256);
|
||||
+
|
||||
+#define T(rtype, rdata, expected) \
|
||||
+ test_one_record (rtype, rdata, sizeof (rdata) - 1, expected)
|
||||
+ T (ns_t_a, "\xc0\0\2\1", "www.example.org.\t1D IN A\t\t192.0.2.1");
|
||||
+ T (ns_t_cname, "\4www1\4prod\xc0\x10",
|
||||
+ "www.example.org.\t1D IN CNAME\twww1.prod.example.org.");
|
||||
+ T (ns_t_hinfo, "\5first\6second",
|
||||
+ "www.example.org.\t1D IN HINFO\t\"first\" \"second\"");
|
||||
+ T (ns_t_isdn, "\5first\6second",
|
||||
+ "www.example.org.\t1D IN ISDN\t\"first\" \"second\"");
|
||||
+ /* Bug: Extra space at the end in the text representation of ISDN RRs. */
|
||||
+ T (ns_t_isdn, "\5first", "www.example.org.\t1D IN ISDN\t\"first\" ");
|
||||
+ T (ns_t_soa,
|
||||
+ "\2ns\xc0\x10\12hostmaster\xc0\x10"
|
||||
+ "\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5",
|
||||
+ "www.example.org.\t1D IN SOA\tns.example.org. hostmaster.example.org. (\n"
|
||||
+ "\t\t\t\t\t1\t\t; serial\n"
|
||||
+ "\t\t\t\t\t2S\t\t; refresh\n"
|
||||
+ "\t\t\t\t\t3S\t\t; retry\n"
|
||||
+ "\t\t\t\t\t4S\t\t; expiry\n"
|
||||
+ "\t\t\t\t\t5S )\t\t; minimum\n");
|
||||
+ T (ns_t_mx, "\0\xa\2mx\xc0\x10",
|
||||
+ "www.example.org.\t1D IN MX\t10 mx.example.org.");
|
||||
+ T (ns_t_px, "\0\xa\3px1\xc0\x10\3px2\xc0\x10",
|
||||
+ "www.example.org.\t1D IN PX\t10 px1.example.org. px2.example.org.");
|
||||
+ T (ns_t_x25, "\4X.25",
|
||||
+ "www.example.org.\t1D IN X25\t\"X.25\"");
|
||||
+ T (ns_t_txt, "\1A\2BC\3DEF",
|
||||
+ "www.example.org.\t1D IN TXT\t\"A\" \"BC\" \"DEF\"");
|
||||
+ T (ns_t_nsap, "",
|
||||
+ "www.example.org.\t1D IN NSAP\t");
|
||||
+ T (ns_t_nsap, "\1",
|
||||
+ "www.example.org.\t1D IN NSAP\t01");
|
||||
+ T (ns_t_nsap, "\1\2",
|
||||
+ "www.example.org.\t1D IN NSAP\t01.02");
|
||||
+ T (ns_t_nsap, "\1\2\3",
|
||||
+ "www.example.org.\t1D IN NSAP\t01.0203");
|
||||
+ T (ns_t_nsap, "\1\2\3\4",
|
||||
+ "www.example.org.\t1D IN NSAP\t01.0203.04");
|
||||
+ T (ns_t_nsap,
|
||||
+ "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32"
|
||||
+ "\33\34\35\36\37\40\41\42\43\44\45\46\47\50\51\52\53\54\55\56\57\60\61"
|
||||
+ "\62\63\64\65\66\67\70\71\72\73\74\75\76\77\100\101\102\103\104\105\106"
|
||||
+ "\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127"
|
||||
+ "\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150"
|
||||
+ "\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
|
||||
+ "\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212"
|
||||
+ "\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233"
|
||||
+ "\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254"
|
||||
+ "\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275"
|
||||
+ "\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316"
|
||||
+ "\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
|
||||
+ "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360"
|
||||
+ "\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
|
||||
+ "www.example.org.\t1D IN NSAP\t"
|
||||
+ "01.0203.0405.0607.0809.0A0B.0C0D.0E0F.1011.1213.1415.1617.1819.1A1B"
|
||||
+ ".1C1D.1E1F.2021.2223.2425.2627.2829.2A2B.2C2D.2E2F.3031.3233.3435.3637"
|
||||
+ ".3839.3A3B.3C3D.3E3F.4041.4243.4445.4647.4849.4A4B.4C4D.4E4F.5051.5253"
|
||||
+ ".5455.5657.5859.5A5B.5C5D.5E5F.6061.6263.6465.6667.6869.6A6B.6C6D.6E6F"
|
||||
+ ".7071.7273.7475.7677.7879.7A7B.7C7D.7E7F.8081.8283.8485.8687.8889.8A8B"
|
||||
+ ".8C8D.8E8F.9091.9293.9495.9697.9899.9A9B.9C9D.9E9F.A0A1.A2A3.A4A5.A6A7"
|
||||
+ ".A8A9.AAAB.ACAD.AEAF.B0B1.B2B3.B4B5.B6B7.B8B9.BABB.BCBD.BEBF.C0C1.C2C3"
|
||||
+ ".C4C5.C6C7.C8C9.CACB.CCCD.CECF.D0D1.D2D3.D4D5.D6D7.D8D9.DADB.DCDD.DEDF"
|
||||
+ ".E0E1.E2E3.E4E5.E6E7.E8E9.EAEB.ECED.EEEF.F0F1.F2F3.F4F5.F6F7.F8F9.FAFB"
|
||||
+ ".FCFD.FEFF");
|
||||
+ T (ns_t_aaaa, "\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34",
|
||||
+ "www.example.org.\t1D IN AAAA\t2001:db8::1234");
|
||||
+ /* Example from RFC 1876. The loc_ntoa format is different from the
|
||||
+ official text representation. */
|
||||
+ T (ns_t_loc,
|
||||
+ "\000\063\026\023\211\027\055\320\160\276\025\360\000\230\215\040",
|
||||
+ "www.example.org.\t1D IN LOC"
|
||||
+ "\t42 21 54.000 N 71 06 18.000 W -24.00m 30.00m 10000.00m 10.00m");
|
||||
+ T (ns_t_naptr,
|
||||
+ "\0\1\0\2\5flags\7service\2.*\5naptr\xc0\x10",
|
||||
+ "www.example.org.\t1D IN NAPTR\t1 2 \"flags\" \"service\" \".*\""
|
||||
+ " naptr.example.org.");
|
||||
+ T (ns_t_srv,
|
||||
+ "\0\1\0\2\0\x50\4www1\xc0\x10",
|
||||
+ "www.example.org.\t1D IN SRV\t1 2 80 www1.example.org.");
|
||||
+ T (ns_t_rp, "\3rp1\xc0\x10\3rp2\xc0\x10",
|
||||
+ "www.example.org.\t1D IN RP\trp1.example.org. rp2.example.org.");
|
||||
+ T (ns_t_wks, "\xc0\0\2\1\6\0\0\0\0\0\0\0\0\0\0\200",
|
||||
+ "www.example.org.\t1D IN WKS\t192.0.2.1 6 ( \n\t\t\t\t80 )");
|
||||
+ T (ns_t_cert, "\0\1\x04\xd2\0blob",
|
||||
+ "www.example.org.\t1D IN CERT\t\\# 9 (\n"
|
||||
+ "\t00 01 04 d2 00 62 6c 6f 62 )\t\t\t; .....blob");
|
||||
+ T (ns_t_tkey, "\4algo\0\0\0\0\1\0\0\0\2\0\3\0\4"
|
||||
+ "\0\5\xa1\xa2\xa3\xa4\xa5\0\3\xb1\xb2\xb3",
|
||||
+ "www.example.org.\t1D IN TYPE249\t\\# 30 (\n"
|
||||
+ "\t04 61 6c 67 6f 00 00 00 00 01 00 00 00 02 00 03 ; .algo...........\n"
|
||||
+ "\t00 04 00 05 a1 a2 a3 a4 a5 00 03 b1 b2 b3 )\t; ..............");
|
||||
+ T (ns_t_tsig, "\4algo\0"
|
||||
+ "\0\20\xdd\xcd\x64\x10\xe9\x21\x34\x1a\x8e\xe0\xa1\x9a\x30\xfc\x3b\xd1"
|
||||
+ "\0\2\0\3\0\5other",
|
||||
+ "www.example.org.\t1D IN TSIG\t\\# 35 (\n"
|
||||
+ "\t04 61 6c 67 6f 00 00 10 dd cd 64 10 e9 21 34 1a ; .algo.....d..!4.\n"
|
||||
+ "\t8e e0 a1 9a 30 fc 3b d1 00 02 00 03 00 05 6f 74 ; ....0.;.......ot\n"
|
||||
+ "\t68 65 72 )\t\t\t\t\t; her");
|
||||
+ T (ns_t_a6,
|
||||
+ "\0\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34\6prefix\xc0\x10",
|
||||
+ "www.example.org.\t1D IN A6\t0 2001:db8::1234");
|
||||
+ T (ns_t_a6,
|
||||
+ "\0\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x35",
|
||||
+ "www.example.org.\t1D IN A6\t0 2001:db8::1235");
|
||||
+ T (ns_t_a6, "\200\6prefix\xc0\x10",
|
||||
+ "www.example.org.\t1D IN A6\t128 prefix.example.org.");
|
||||
+ T (ns_t_a6, "\x20\0\0\0\0\0\0\0\0\0\0\x12\x36\6prefix\xc0\x10",
|
||||
+ "www.example.org.\t1D IN A6\t32 ::1236 prefix.example.org.");
|
||||
+#undef T
|
||||
+
|
||||
+ support_next_to_fault_free (&ntf_in);
|
||||
+ support_next_to_fault_free (&ntf_out);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
102
SOURCES/glibc-RHEL-180340.patch
Normal file
102
SOURCES/glibc-RHEL-180340.patch
Normal file
@ -0,0 +1,102 @@
|
||||
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>
|
||||
|
||||
diff --git a/libio/Makefile b/libio/Makefile
|
||||
index 93656466df..6e0627bb88 100644
|
||||
--- a/libio/Makefile
|
||||
+++ b/libio/Makefile
|
||||
@@ -84,6 +84,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 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!*/
|
||||
56
SOURCES/glibc-RHEL-49785-1.patch
Normal file
56
SOURCES/glibc-RHEL-49785-1.patch
Normal file
@ -0,0 +1,56 @@
|
||||
commit a0f9bfc3a5cc10920787d70d0653720a8fa013f3
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Mon Nov 6 17:25:48 2023 -0300
|
||||
|
||||
elf: Remove any_debug from dl_main_state
|
||||
|
||||
Its usage can be implied by the GLRO(dl_debug_mask).
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
elf/dl-main.h
|
||||
(fixup context)
|
||||
|
||||
diff --git a/elf/dl-main.h b/elf/dl-main.h
|
||||
index d3820e0063143878..35728d47d463c3fb 100644
|
||||
--- a/elf/dl-main.h
|
||||
+++ b/elf/dl-main.h
|
||||
@@ -94,9 +94,6 @@ struct dl_main_state
|
||||
|
||||
enum rtld_mode mode;
|
||||
|
||||
- /* True if any of the debugging options is enabled. */
|
||||
- bool any_debug;
|
||||
-
|
||||
/* True if information about versions has to be printed. */
|
||||
bool version_info;
|
||||
};
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index b788857924e5a388..629ad7f8f4f75353 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -305,7 +305,6 @@ dl_main_state_init (struct dl_main_state *state)
|
||||
state->glibc_hwcaps_prepend = NULL;
|
||||
state->glibc_hwcaps_mask = NULL;
|
||||
state->mode = rtld_mode_normal;
|
||||
- state->any_debug = false;
|
||||
state->version_info = false;
|
||||
}
|
||||
|
||||
@@ -2707,7 +2706,6 @@ process_dl_debug (struct dl_main_state *state, const char *dl_debug)
|
||||
&& memcmp (dl_debug, debopts[cnt].name, len) == 0)
|
||||
{
|
||||
GLRO(dl_debug_mask) |= debopts[cnt].mask;
|
||||
- state->any_debug = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2954,7 +2952,7 @@ process_envvars (struct dl_main_state *state)
|
||||
/* If we have to run the dynamic linker in debugging mode and the
|
||||
LD_DEBUG_OUTPUT environment variable is given, we write the debug
|
||||
messages to this file. */
|
||||
- else if (state->any_debug && debug_output != NULL)
|
||||
+ else if (GLRO(dl_debug_mask) != 0 && debug_output != NULL)
|
||||
{
|
||||
const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW;
|
||||
size_t name_len = strlen (debug_output);
|
||||
374
SOURCES/glibc-RHEL-49785-2.patch
Normal file
374
SOURCES/glibc-RHEL-49785-2.patch
Normal file
@ -0,0 +1,374 @@
|
||||
commit 332f8e62afef53492dd8285490bcf7aeef18c80a
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
Date: Fri Sep 5 16:14:38 2025 +0200
|
||||
|
||||
tls: Add debug logging for TLS and TCB management
|
||||
|
||||
Introduce the `DL_DEBUG_TLS` debug mask to enable detailed logging for
|
||||
Thread-Local Storage (TLS) and Thread Control Block (TCB) management.
|
||||
|
||||
This change integrates a new `tls` option into the `LD_DEBUG`
|
||||
environment variable, allowing developers to trace:
|
||||
- TCB allocation, deallocation, and reuse events in `dl-tls.c`,
|
||||
`nptl/allocatestack.c`, and `nptl/nptl-stack.c`.
|
||||
- Thread startup events, including the TID and TCB address, in
|
||||
`nptl/pthread_create.c`.
|
||||
|
||||
A new test, `tst-dl-debug-tid`, has been added to validate the
|
||||
functionality of this new debug logging, ensuring that relevant messages
|
||||
are correctly generated for both main and worker threads.
|
||||
|
||||
This enhances the debugging capabilities for diagnosing issues related
|
||||
to TLS allocation and thread lifecycle within the dynamic linker.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
sysdeps/generic/ldsodefs.h
|
||||
(PRELINK is still there downstream)
|
||||
|
||||
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
|
||||
index 1b1bc4292eb24747..20d6036b891f653c 100644
|
||||
--- a/elf/dl-tls.c
|
||||
+++ b/elf/dl-tls.c
|
||||
@@ -503,6 +503,8 @@ _dl_allocate_tls_storage (void)
|
||||
result = allocate_dtv (result);
|
||||
if (result == NULL)
|
||||
free (allocated);
|
||||
+ else if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("TCB allocated: 0x%lx\n", (unsigned long int) result);
|
||||
|
||||
_dl_tls_allocate_end ();
|
||||
return result;
|
||||
@@ -691,6 +693,10 @@ rtld_hidden_def (_dl_allocate_tls)
|
||||
void
|
||||
_dl_deallocate_tls (void *tcb, bool dealloc_tcb)
|
||||
{
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("TCB deallocating: 0x%lx (dealloc_tcb=%d)\n",
|
||||
+ (unsigned long int) tcb, dealloc_tcb);
|
||||
+
|
||||
dtv_t *dtv = GET_DTV (tcb);
|
||||
|
||||
/* We need to free the memory allocated for non-static TLS. */
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index 629ad7f8f4f75353..ff4c160d8fafd70d 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -2676,10 +2676,12 @@ process_dl_debug (struct dl_main_state *state, const char *dl_debug)
|
||||
DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS },
|
||||
{ LEN_AND_STR ("scopes"), "display scope information",
|
||||
DL_DEBUG_SCOPES },
|
||||
+ { LEN_AND_STR ("tls"), "display TLS structures processing",
|
||||
+ DL_DEBUG_TLS },
|
||||
{ LEN_AND_STR ("all"), "all previous options combined",
|
||||
DL_DEBUG_LIBS | DL_DEBUG_RELOC | DL_DEBUG_FILES | DL_DEBUG_SYMBOLS
|
||||
| DL_DEBUG_BINDINGS | DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS
|
||||
- | DL_DEBUG_SCOPES },
|
||||
+ | DL_DEBUG_SCOPES | DL_DEBUG_TLS },
|
||||
{ LEN_AND_STR ("statistics"), "display relocation statistics",
|
||||
DL_DEBUG_STATISTICS },
|
||||
{ LEN_AND_STR ("unused"), "determined unused DSOs",
|
||||
diff --git a/nptl/Makefile b/nptl/Makefile
|
||||
index 80c7587f0086677b..7001ecd17b752dba 100644
|
||||
--- a/nptl/Makefile
|
||||
+++ b/nptl/Makefile
|
||||
@@ -374,6 +374,7 @@ tests-container = tst-pthread-getattr
|
||||
tests-internal := \
|
||||
tst-barrier5 \
|
||||
tst-cond22 \
|
||||
+ tst-dl-debug-tid \
|
||||
tst-mutex8 \
|
||||
tst-mutex8-static \
|
||||
tst-mutexpi8 \
|
||||
@@ -562,6 +563,7 @@ xtests-static += tst-setuid1-static
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += \
|
||||
+ $(objpfx)tst-dl-debug-tid.out \
|
||||
$(objpfx)tst-oddstacklimit.out \
|
||||
$(objpfx)tst-stack3-mem.out \
|
||||
# tests-special
|
||||
@@ -685,6 +687,11 @@ tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child"
|
||||
tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
+$(objpfx)tst-dl-debug-tid.out: tst-dl-debug-tid.sh $(objpfx)tst-dl-debug-tid
|
||||
+ $(SHELL) $< $(common-objpfx) '$(test-wrapper)' '$(rtld-prefix)' \
|
||||
+ '$(test-wrapper-env)' '$(run-program-env)' \
|
||||
+ $(objpfx)tst-dl-debug-tid > $@; $(evaluate-test)
|
||||
+
|
||||
$(objpfx)tst-oddstacklimit.out: $(objpfx)tst-oddstacklimit $(objpfx)tst-basic1
|
||||
$(test-program-prefix) $< --command '$(host-test-program-cmd)' > $@; \
|
||||
$(evaluate-test)
|
||||
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
|
||||
index b0f40afd3f5801f6..9e0bb8f0eeff8e88 100644
|
||||
--- a/nptl/allocatestack.c
|
||||
+++ b/nptl/allocatestack.c
|
||||
@@ -114,6 +114,10 @@ get_cached_stack (size_t *sizep, void **memp)
|
||||
/* Release the lock early. */
|
||||
lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
|
||||
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ GLRO (dl_debug_printf) ("TLS TCB reused from cache: 0x%lx\n",
|
||||
+ (unsigned long int) result);
|
||||
+
|
||||
/* Report size and location of the stack to the caller. */
|
||||
*sizep = result->stackblock_size;
|
||||
*memp = result->stackblock;
|
||||
@@ -291,6 +295,12 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
||||
stack cache nor will the memory (except the TLS memory) be freed. */
|
||||
pd->user_stack = true;
|
||||
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ GLRO (dl_debug_printf) (
|
||||
+ "TCB for user-supplied stack created: 0x%lx, stack=0x%lx, size=%lu\n",
|
||||
+ (unsigned long int) pd, (unsigned long int) pd->stackblock,
|
||||
+ (unsigned long int) pd->stackblock_size);
|
||||
+
|
||||
/* This is at least the second thread. */
|
||||
pd->header.multiple_threads = 1;
|
||||
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
|
||||
@@ -425,6 +435,10 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
||||
/* Don't allow setxid until cloned. */
|
||||
pd->setxid_futex = -1;
|
||||
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ GLRO (dl_debug_printf) ("TCB for new stack allocated: 0x%lx\n",
|
||||
+ (unsigned long int) pd);
|
||||
+
|
||||
/* Allocate the DTV for this thread. */
|
||||
if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
|
||||
{
|
||||
diff --git a/nptl/nptl-stack.c b/nptl/nptl-stack.c
|
||||
index 3f33a4c20b39a4aa..4ef6527ff7e8192b 100644
|
||||
--- a/nptl/nptl-stack.c
|
||||
+++ b/nptl/nptl-stack.c
|
||||
@@ -75,6 +75,11 @@ __nptl_free_stacks (size_t limit)
|
||||
/* Account for the freed memory. */
|
||||
GL (dl_stack_cache_actsize) -= curr->stackblock_size;
|
||||
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ GLRO (dl_debug_printf) (
|
||||
+ "TCB cache full, deallocating: TID=%ld, TCB=0x%lx\n",
|
||||
+ (long int) curr->tid, (unsigned long int) curr);
|
||||
+
|
||||
/* Free the memory associated with the ELF TLS. */
|
||||
_dl_deallocate_tls (TLS_TPADJ (curr), false);
|
||||
|
||||
@@ -96,6 +101,12 @@ static inline void
|
||||
__attribute ((always_inline))
|
||||
queue_stack (struct pthread *stack)
|
||||
{
|
||||
+ /* The 'stack' parameter is a pointer to the TCB (struct pthread),
|
||||
+ not just the stack. */
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ GLRO (dl_debug_printf) ("TCB deallocated into cache: TID=%ld, TCB=0x%lx\n",
|
||||
+ (long int) stack->tid, (unsigned long int) stack);
|
||||
+
|
||||
/* We unconditionally add the stack to the list. The memory may
|
||||
still be in use but it will not be reused until the kernel marks
|
||||
the stack as not used anymore. */
|
||||
@@ -123,8 +134,16 @@ __nptl_deallocate_stack (struct pthread *pd)
|
||||
if (__glibc_likely (! pd->user_stack))
|
||||
(void) queue_stack (pd);
|
||||
else
|
||||
- /* Free the memory associated with the ELF TLS. */
|
||||
- _dl_deallocate_tls (TLS_TPADJ (pd), false);
|
||||
+ {
|
||||
+ /* User-provided stack. We must not free it. But we must free
|
||||
+ the TLS memory. */
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ GLRO (dl_debug_printf) (
|
||||
+ "TCB for user-supplied stack deallocated: TID=%ld, TCB=0x%lx\n",
|
||||
+ (long int) pd->tid, (unsigned long int) pd);
|
||||
+ /* Free the memory associated with the ELF TLS. */
|
||||
+ _dl_deallocate_tls (TLS_TPADJ (pd), false);
|
||||
+ }
|
||||
|
||||
lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
|
||||
}
|
||||
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
|
||||
index 109c5e3dc78c9aa2..37de54eaa570cedb 100644
|
||||
--- a/nptl/pthread_create.c
|
||||
+++ b/nptl/pthread_create.c
|
||||
@@ -362,6 +362,10 @@ start_thread (void *arg)
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ GLRO (dl_debug_printf) ("Thread starting: TID=%ld, TCB=0x%lx\n",
|
||||
+ (long int) pd->tid, (unsigned long int) pd);
|
||||
+
|
||||
/* Initialize resolver state pointer. */
|
||||
__resp = &pd->res;
|
||||
|
||||
diff --git a/nptl/tst-dl-debug-tid.c b/nptl/tst-dl-debug-tid.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..231fa43516b233b3
|
||||
--- /dev/null
|
||||
+++ b/nptl/tst-dl-debug-tid.c
|
||||
@@ -0,0 +1,69 @@
|
||||
+/* Test for thread ID logging in dynamic linker.
|
||||
+ 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/>. */
|
||||
+
|
||||
+/* This test checks that the dynamic linker correctly logs thread creation
|
||||
+ and destruction. It creates a detached thread followed by a joinable
|
||||
+ thread to exercise different code paths. A barrier is used to ensure
|
||||
+ the detached thread has started before the joinable one is created,
|
||||
+ making the test more deterministic. The tst-dl-debug-tid.sh shell script
|
||||
+ wrapper then verifies the LD_DEBUG output. */
|
||||
+
|
||||
+#include <pthread.h>
|
||||
+#include <support/xthread.h>
|
||||
+#include <stdio.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+static void *
|
||||
+thread_function (void *arg)
|
||||
+{
|
||||
+ if (arg)
|
||||
+ pthread_barrier_wait ((pthread_barrier_t *) arg);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ pthread_t thread1;
|
||||
+ pthread_attr_t attr;
|
||||
+ pthread_barrier_t barrier;
|
||||
+
|
||||
+ pthread_barrier_init (&barrier, NULL, 2);
|
||||
+
|
||||
+ /* A detached thread.
|
||||
+ * Deallocation is done by the thread itself upon exit. */
|
||||
+ xpthread_attr_init (&attr);
|
||||
+ xpthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
|
||||
+ /* We don't need the thread handle for the detached thread. */
|
||||
+ xpthread_create (&attr, thread_function, &barrier);
|
||||
+ xpthread_attr_destroy (&attr);
|
||||
+
|
||||
+ /* Wait for the detached thread to be executed. */
|
||||
+ pthread_barrier_wait (&barrier);
|
||||
+ pthread_barrier_destroy (&barrier);
|
||||
+
|
||||
+ /* A joinable thread.
|
||||
+ * Deallocation is done by the main thread in pthread_join. */
|
||||
+ thread1 = xpthread_create (NULL, thread_function, NULL);
|
||||
+
|
||||
+ xpthread_join (thread1);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/nptl/tst-dl-debug-tid.sh b/nptl/tst-dl-debug-tid.sh
|
||||
new file mode 100644
|
||||
index 0000000000000000..93d27134a09eaca7
|
||||
--- /dev/null
|
||||
+++ b/nptl/tst-dl-debug-tid.sh
|
||||
@@ -0,0 +1,72 @@
|
||||
+#!/bin/sh
|
||||
+# Test for thread ID logging in dynamic linker.
|
||||
+# 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/>.
|
||||
+
|
||||
+# This script runs the tst-dl-debug-tid test case and verifies its
|
||||
+# LD_DEBUG output. It checks for thread creation/destruction messages
|
||||
+# to ensure the dynamic linker's thread-aware logging is working.
|
||||
+
|
||||
+set -e
|
||||
+
|
||||
+# Arguments are from Makefile.
|
||||
+common_objpfx="$1"
|
||||
+test_wrapper="$2"
|
||||
+rtld_prefix="$3"
|
||||
+test_wrapper_env="$4"
|
||||
+run_program_env="$5"
|
||||
+test_program="$6"
|
||||
+
|
||||
+debug_output="${common_objpfx}elf/tst-dl-debug-tid.debug"
|
||||
+rm -f "${debug_output}".*
|
||||
+
|
||||
+# Run the test program with LD_DEBUG=tls.
|
||||
+eval "${test_wrapper_env}" LD_DEBUG=tls LD_DEBUG_OUTPUT="${debug_output}" \
|
||||
+ "${test_wrapper}" "${rtld_prefix}" "${test_program}"
|
||||
+
|
||||
+debug_output=$(ls "${debug_output}".*)
|
||||
+# Check for the "Thread starting" message.
|
||||
+if ! grep -q 'Thread starting: TID=' "${debug_output}"; then
|
||||
+ echo "error: 'Thread starting' message not found"
|
||||
+ cat "${debug_output}"
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
+# Check that we have a message where the PID (from prefix) is different
|
||||
+# from the TID (in the message). This indicates a worker thread log.
|
||||
+if ! grep 'Thread starting: TID=' "${debug_output}" | awk -F '[ \t:]+' '{
|
||||
+ sub(/,/, "", $5);
|
||||
+ sub(/TID=/, "", $5);
|
||||
+ if ($1 != $5)
|
||||
+ exit 0;
|
||||
+ exit 1
|
||||
+}'; then
|
||||
+ echo "error: No 'Thread starting' message from a worker thread found"
|
||||
+ cat "${debug_output}"
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
+# We expect messages from thread creation and destruction.
|
||||
+if ! grep -q 'TCB allocated\|TCB deallocating\|TCB reused\|TCB deallocated' \
|
||||
+ "${debug_output}"; then
|
||||
+ echo "error: Expected TCB allocation/deallocation message not found"
|
||||
+ cat "${debug_output}"
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
+cat "${debug_output}"
|
||||
+rm -f "${debug_output}"
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index e5860916345487e7..5080db9381c31c4f 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -560,9 +560,10 @@ struct rtld_global_ro
|
||||
#define DL_DEBUG_STATISTICS (1 << 7)
|
||||
#define DL_DEBUG_UNUSED (1 << 8)
|
||||
#define DL_DEBUG_SCOPES (1 << 9)
|
||||
-/* These two are used only internally. */
|
||||
+/* DL_DEBUG_HELP is only used internally. */
|
||||
#define DL_DEBUG_HELP (1 << 10)
|
||||
#define DL_DEBUG_PRELINK (1 << 11)
|
||||
+#define DL_DEBUG_TLS (1 << 12)
|
||||
|
||||
/* OS version. */
|
||||
EXTERN unsigned int _dl_osversion;
|
||||
107
SOURCES/glibc-RHEL-49785-3.patch
Normal file
107
SOURCES/glibc-RHEL-49785-3.patch
Normal file
@ -0,0 +1,107 @@
|
||||
commit d4d472366ba69df7b14eba22a75f887b99855d70
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
Date: Thu Oct 2 19:15:29 2025 +0200
|
||||
|
||||
docs: Add dynamic linker environment variable docs
|
||||
|
||||
The Dynamic Linker chapter now includes a new section detailing
|
||||
environment variables that influence its behavior.
|
||||
|
||||
This new section documents the `LD_DEBUG` environment variable,
|
||||
explaining how to enable debugging output and listing its various
|
||||
keywords like `libs`, `reloc`, `files`, `symbols`, `bindings`,
|
||||
`versions`, `scopes`, `tls`, `all`, `statistics`, `unused`, and `help`.
|
||||
|
||||
It also documents `LD_DEBUG_OUTPUT`, which controls where the debug
|
||||
output is written, allowing redirection to a file with the process ID
|
||||
appended.
|
||||
|
||||
This provides users with essential information for controlling and
|
||||
debugging the dynamic linker.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
diff --git a/manual/dynlink.texi b/manual/dynlink.texi
|
||||
index 2b35e5883c3e65c0..469340e1d4ae8a88 100644
|
||||
--- a/manual/dynlink.texi
|
||||
+++ b/manual/dynlink.texi
|
||||
@@ -14,6 +14,8 @@ Dynamic linkers are sometimes called @dfn{dynamic loaders}.
|
||||
|
||||
@menu
|
||||
* Dynamic Linker Invocation:: Explicit invocation of the dynamic linker.
|
||||
+* Dynamic Linker Environment Variables:: Environment variables that control the
|
||||
+ dynamic linker.
|
||||
* Dynamic Linker Introspection:: Interfaces for querying mapping information.
|
||||
@end menu
|
||||
|
||||
@@ -348,6 +350,70 @@ probed CPU are omitted. Nothing is printed if the system does not
|
||||
support the XGETBV instruction.
|
||||
@end table
|
||||
|
||||
+@node Dynamic Linker Environment Variables
|
||||
+@section Dynamic Linker Environment Variables
|
||||
+
|
||||
+The behavior of the dynamic linker can be modified through various environment
|
||||
+variables.
|
||||
+
|
||||
+@table @code
|
||||
+@item LD_DEBUG
|
||||
+@cindex @code{LD_DEBUG} environment variable
|
||||
+The @env{LD_DEBUG} environment variable can be set to a comma-separated list
|
||||
+of keywords to enable debugging output from the dynamic linker. Setting it to
|
||||
+@code{help} will display a list of all available keywords. The output is
|
||||
+written to standard output by default.
|
||||
+
|
||||
+@table @code
|
||||
+@item libs
|
||||
+Display library search paths.
|
||||
+
|
||||
+@item reloc
|
||||
+Display relocation processing.
|
||||
+
|
||||
+@item files
|
||||
+Display progress for input file processing.
|
||||
+
|
||||
+@item symbols
|
||||
+Display symbol table processing.
|
||||
+
|
||||
+@item bindings
|
||||
+Display information about symbol binding.
|
||||
+
|
||||
+@item versions
|
||||
+Display version dependencies.
|
||||
+
|
||||
+@item scopes
|
||||
+Display scope information.
|
||||
+
|
||||
+@item tls
|
||||
+Display information about Thread-Local Storage (TLS) handling, including TCB
|
||||
+allocation, deallocation, and reuse. This is useful for debugging issues
|
||||
+related to thread creation and lifecycle.
|
||||
+
|
||||
+@item all
|
||||
+All previous options combined.
|
||||
+
|
||||
+@item statistics
|
||||
+Display relocation statistics.
|
||||
+
|
||||
+@item unused
|
||||
+Determined unused DSOs.
|
||||
+
|
||||
+@item help
|
||||
+Display a help message with all available options and exit.
|
||||
+@end table
|
||||
+
|
||||
+@item LD_DEBUG_OUTPUT
|
||||
+@cindex @code{LD_DEBUG_OUTPUT} environment variable
|
||||
+If @env{LD_DEBUG} is set, the output is written to standard output by
|
||||
+default. If @env{LD_DEBUG_OUTPUT} is set, the output is written to the
|
||||
+file specified by its value, with the process ID appended. For example, if
|
||||
+@env{LD_DEBUG_OUTPUT} is set to @file{/tmp/glibc.debug}, the output will be
|
||||
+written to a file named @file{/tmp/glibc.debug.12345}, where @code{12345} is
|
||||
+the process ID.
|
||||
+@end table
|
||||
+
|
||||
@node Dynamic Linker Introspection
|
||||
@section Dynamic Linker Introspection
|
||||
|
||||
70
SOURCES/glibc-RHEL-49785-4.patch
Normal file
70
SOURCES/glibc-RHEL-49785-4.patch
Normal file
@ -0,0 +1,70 @@
|
||||
commit 20092f2ef601aef57cc184cbacd7cab39bba5a25
|
||||
Author: Yury Khrustalev <yury.khrustalev@arm.com>
|
||||
Date: Mon Dec 1 10:09:14 2025 +0000
|
||||
|
||||
nptl: tests: Fix test-wrapper use in tst-dl-debug-tid.sh
|
||||
|
||||
Test wrapper script was used twice: once to run the test
|
||||
command and second time within the text command which
|
||||
seems unnecessary and results in false errors when running
|
||||
this test.
|
||||
|
||||
Fixes 332f8e62afef53492dd8285490bcf7aeef18c80a
|
||||
|
||||
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
|
||||
|
||||
diff --git a/nptl/Makefile b/nptl/Makefile
|
||||
index 7001ecd17b752dba..597311bf07223c4f 100644
|
||||
--- a/nptl/Makefile
|
||||
+++ b/nptl/Makefile
|
||||
@@ -688,8 +688,8 @@ tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
$(objpfx)tst-dl-debug-tid.out: tst-dl-debug-tid.sh $(objpfx)tst-dl-debug-tid
|
||||
- $(SHELL) $< $(common-objpfx) '$(test-wrapper)' '$(rtld-prefix)' \
|
||||
- '$(test-wrapper-env)' '$(run-program-env)' \
|
||||
+ $(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' '$(rtld-prefix)' \
|
||||
+ '$(run-program-env)' \
|
||||
$(objpfx)tst-dl-debug-tid > $@; $(evaluate-test)
|
||||
|
||||
$(objpfx)tst-oddstacklimit.out: $(objpfx)tst-oddstacklimit $(objpfx)tst-basic1
|
||||
diff --git a/nptl/tst-dl-debug-tid.sh b/nptl/tst-dl-debug-tid.sh
|
||||
index 93d27134a09eaca7..9ee31ac4f241f0b4 100644
|
||||
--- a/nptl/tst-dl-debug-tid.sh
|
||||
+++ b/nptl/tst-dl-debug-tid.sh
|
||||
@@ -25,18 +25,17 @@ set -e
|
||||
|
||||
# Arguments are from Makefile.
|
||||
common_objpfx="$1"
|
||||
-test_wrapper="$2"
|
||||
+test_wrapper_env="$2"
|
||||
rtld_prefix="$3"
|
||||
-test_wrapper_env="$4"
|
||||
-run_program_env="$5"
|
||||
-test_program="$6"
|
||||
+run_program_env="$4"
|
||||
+test_program="$5"
|
||||
|
||||
debug_output="${common_objpfx}elf/tst-dl-debug-tid.debug"
|
||||
rm -f "${debug_output}".*
|
||||
|
||||
# Run the test program with LD_DEBUG=tls.
|
||||
eval "${test_wrapper_env}" LD_DEBUG=tls LD_DEBUG_OUTPUT="${debug_output}" \
|
||||
- "${test_wrapper}" "${rtld_prefix}" "${test_program}"
|
||||
+ "${rtld_prefix}" "${test_program}"
|
||||
|
||||
debug_output=$(ls "${debug_output}".*)
|
||||
# Check for the "Thread starting" message.
|
||||
@@ -49,9 +48,9 @@ fi
|
||||
# Check that we have a message where the PID (from prefix) is different
|
||||
# from the TID (in the message). This indicates a worker thread log.
|
||||
if ! grep 'Thread starting: TID=' "${debug_output}" | awk -F '[ \t:]+' '{
|
||||
- sub(/,/, "", $5);
|
||||
- sub(/TID=/, "", $5);
|
||||
- if ($1 != $5)
|
||||
+ sub(/,/, "", $4);
|
||||
+ sub(/TID=/, "", $4);
|
||||
+ if ($1 != $4)
|
||||
exit 0;
|
||||
exit 1
|
||||
}'; then
|
||||
681
SOURCES/glibc-RHEL-49785-5.patch
Normal file
681
SOURCES/glibc-RHEL-49785-5.patch
Normal file
@ -0,0 +1,681 @@
|
||||
commit 1e47dbcce4d5cf2ce71377e729014e454a3e15ae
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
Date: Fri Dec 12 16:19:43 2025 +0100
|
||||
|
||||
elf(tls): Add debug logging for TLS operations
|
||||
|
||||
This commit introduces extensive debug logging for thread-local storage
|
||||
(TLS) operations within the dynamic linker. When `LD_DEBUG=tls` is
|
||||
enabled, messages are printed for:
|
||||
- TLS module assignment and release.
|
||||
- DTV (Dynamic Thread Vector) resizing events.
|
||||
- TLS block allocations and deallocations.
|
||||
- `__tls_get_addr` slow path events (DTV updates, lazy allocations, and
|
||||
static TLS usage).
|
||||
|
||||
The log format is standardized to use a "tls: " prefix and identifies
|
||||
modules using the "modid %lu" convention. To aid in debugging
|
||||
multithreaded applications, thread-specific logs include the Thread
|
||||
Control Block (TCB) address to identify the context of the operation.
|
||||
|
||||
A new test module `tst-tls-debug-mod.c` and a corresponding shell script
|
||||
`tst-tls-debug-recursive.sh` have been added. Additionally, the existing
|
||||
`tst-dl-debug-tid` NPTL test has been updated to verify these TLS debug
|
||||
messages in a multithreaded context.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
(fixup context)
|
||||
elf/dl-tls.c
|
||||
(missing 5e249192cac7354af02a7347a0d8c984e0c88ed3 downstream)
|
||||
sysdeps/x86_64/dl-tls.c
|
||||
(missing 5e249192cac7354af02a7347a0d8c984e0c88ed3 downstream)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index bd12a20435538fdd..2431e7032c44beb8 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -1252,6 +1252,7 @@ $(objpfx)tst-glibcelf.out: tst-glibcelf.py elf.h $(..)/scripts/glibcelf.py \
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += $(objpfx)tst-tls-allocation-failure-static-patched.out
|
||||
+tests-special += $(objpfx)tst-tls-debug-recursive.out
|
||||
endif
|
||||
|
||||
# The test requires shared _and_ PIE because the executable
|
||||
@@ -3052,3 +3053,15 @@ LDFLAGS-tst-version-hash-zero-linkmod.so = \
|
||||
$(objpfx)tst-version-hash-zero-refmod.so: \
|
||||
$(objpfx)tst-version-hash-zero-linkmod.so
|
||||
tst-version-hash-zero-refmod.so-no-z-defs = yes
|
||||
+
|
||||
+ifeq ($(run-built-tests),yes)
|
||||
+$(objpfx)tst-tls-debug-recursive.out: tst-tls-debug-recursive.sh \
|
||||
+ $(objpfx)tst-recursive-tls \
|
||||
+ $(objpfx)tst-recursive-tlsmallocmod.so \
|
||||
+ $(patsubst %,$(objpfx)tst-recursive-tlsmod%.so, \
|
||||
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
|
||||
+ $(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' \
|
||||
+ '$(rtld-prefix)' '$(run_program_env)' \
|
||||
+ $(objpfx)tst-recursive-tls > $@; \
|
||||
+ $(evaluate-test)
|
||||
+endif
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index 4514c53d2db261c1..8020b0b182d66f4f 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -79,6 +79,11 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
|
||||
if (__glibc_likely (old_map != NULL))
|
||||
{
|
||||
/* Mark the entry as unused. These can be read concurrently. */
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf (
|
||||
+ "tls: release modid %lu from %s [%ld]\n",
|
||||
+ (unsigned long int) idx, DSO_FILENAME (old_map->l_name),
|
||||
+ (long int) old_map->l_ns);
|
||||
atomic_store_relaxed (&listp->slotinfo[idx - disp].gen,
|
||||
GL(dl_tls_generation) + 1);
|
||||
atomic_store_relaxed (&listp->slotinfo[idx - disp].map, NULL);
|
||||
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
|
||||
index 20d6036b891f653c..f22d828a86539057 100644
|
||||
--- a/elf/dl-tls.c
|
||||
+++ b/elf/dl-tls.c
|
||||
@@ -215,6 +215,12 @@ _dl_assign_tls_modid (struct link_map *l)
|
||||
}
|
||||
|
||||
l->l_tls_modid = result;
|
||||
+
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: assign modid %lu to %s [%ld]\n",
|
||||
+ (unsigned long int) result,
|
||||
+ DSO_FILENAME (l->l_name),
|
||||
+ (long int) l->l_ns);
|
||||
}
|
||||
|
||||
|
||||
@@ -504,7 +510,7 @@ _dl_allocate_tls_storage (void)
|
||||
if (result == NULL)
|
||||
free (allocated);
|
||||
else if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
- _dl_debug_printf ("TCB allocated: 0x%lx\n", (unsigned long int) result);
|
||||
+ _dl_debug_printf ("tls: allocate TCB 0x%lx\n", (unsigned long int) result);
|
||||
|
||||
_dl_tls_allocate_end ();
|
||||
return result;
|
||||
@@ -517,13 +523,18 @@ extern dtv_t _dl_static_dtv[];
|
||||
#endif
|
||||
|
||||
static dtv_t *
|
||||
-_dl_resize_dtv (dtv_t *dtv, size_t max_modid)
|
||||
+_dl_resize_dtv (dtv_t *dtv, size_t max_modid, void *tcb)
|
||||
{
|
||||
/* Resize the dtv. */
|
||||
dtv_t *newp;
|
||||
size_t newsize = max_modid + DTV_SURPLUS;
|
||||
size_t oldsize = dtv[-1].counter;
|
||||
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: DTV resized for TCB 0x%lx: oldsize=%lu, newsize=%lu\n",
|
||||
+ (unsigned long int) tcb,
|
||||
+ (unsigned long int) oldsize, (unsigned long int) newsize);
|
||||
+
|
||||
_dl_tls_allocate_begin ();
|
||||
if (dtv == GL(dl_initial_dtv))
|
||||
{
|
||||
@@ -592,7 +603,7 @@ _dl_allocate_tls_init (void *result, bool main_thread)
|
||||
if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
|
||||
{
|
||||
/* Resize the dtv. */
|
||||
- dtv = _dl_resize_dtv (dtv, GL(dl_tls_max_dtv_idx));
|
||||
+ dtv = _dl_resize_dtv (dtv, GL(dl_tls_max_dtv_idx), result);
|
||||
|
||||
/* Install this new dtv in the thread data structures. */
|
||||
INSTALL_DTV (result, &dtv[-1]);
|
||||
@@ -683,9 +694,14 @@ rtld_hidden_def (_dl_allocate_tls_init)
|
||||
void *
|
||||
_dl_allocate_tls (void *mem)
|
||||
{
|
||||
- return _dl_allocate_tls_init (mem == NULL
|
||||
- ? _dl_allocate_tls_storage ()
|
||||
- : allocate_dtv (mem), false);
|
||||
+ void *result = _dl_allocate_tls_init (mem == NULL
|
||||
+ ? _dl_allocate_tls_storage ()
|
||||
+ : allocate_dtv (mem), false);
|
||||
+ if (__glibc_unlikely (result != NULL
|
||||
+ && (GLRO (dl_debug_mask) & DL_DEBUG_TLS)))
|
||||
+ _dl_debug_printf ("tls: TLS initialized for TCB 0x%lx\n",
|
||||
+ (unsigned long int) result);
|
||||
+ return result;
|
||||
}
|
||||
rtld_hidden_def (_dl_allocate_tls)
|
||||
|
||||
@@ -694,14 +710,22 @@ void
|
||||
_dl_deallocate_tls (void *tcb, bool dealloc_tcb)
|
||||
{
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
- _dl_debug_printf ("TCB deallocating: 0x%lx (dealloc_tcb=%d)\n",
|
||||
+ _dl_debug_printf ("tls: deallocate TCB 0x%lx (dealloc_tcb=%d)\n",
|
||||
(unsigned long int) tcb, dealloc_tcb);
|
||||
|
||||
dtv_t *dtv = GET_DTV (tcb);
|
||||
|
||||
/* We need to free the memory allocated for non-static TLS. */
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
- free (dtv[1 + cnt].pointer.to_free);
|
||||
+ {
|
||||
+ if (dtv[1 + cnt].pointer.to_free != NULL
|
||||
+ && __glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf (
|
||||
+ "tls: deallocate block 0x%lx for modid %lu; TCB=0x%lx\n",
|
||||
+ (unsigned long int) dtv[1 + cnt].pointer.to_free,
|
||||
+ (unsigned long int) (1 + cnt), (unsigned long int) tcb);
|
||||
+ free (dtv[1 + cnt].pointer.to_free);
|
||||
+ }
|
||||
|
||||
/* The array starts with dtv[-1]. */
|
||||
if (dtv != GL(dl_initial_dtv))
|
||||
@@ -773,6 +797,12 @@ allocate_and_init (struct link_map *map)
|
||||
(map->l_tls_align, map->l_tls_blocksize);
|
||||
if (result.val == NULL)
|
||||
oom ();
|
||||
+ else if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: allocate block 0x%lx for modid %lu; size=%lu, TCB=0x%lx\n",
|
||||
+ (unsigned long int) result.to_free,
|
||||
+ (unsigned long int) map->l_tls_modid,
|
||||
+ (unsigned long int) map->l_tls_blocksize,
|
||||
+ (unsigned long int) THREAD_SELF);
|
||||
|
||||
/* Initialize the memory. */
|
||||
memset (__mempcpy (result.val, map->l_tls_initimage,
|
||||
@@ -874,7 +904,7 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)
|
||||
continue;
|
||||
|
||||
/* Resizing the dtv aborts on failure: bug 16134. */
|
||||
- dtv = _dl_resize_dtv (dtv, max_modid);
|
||||
+ dtv = _dl_resize_dtv (dtv, max_modid, THREAD_SELF);
|
||||
|
||||
assert (modid <= dtv[-1].counter);
|
||||
|
||||
@@ -895,6 +925,12 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)
|
||||
least some dynamic TLS usage by interposed mallocs. */
|
||||
if (dtv[modid].pointer.to_free != NULL)
|
||||
{
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf (
|
||||
+ "tls: DTV update for TCB 0x%lx: modid %lu deallocated block 0x%lx\n",
|
||||
+ (unsigned long int) THREAD_SELF,
|
||||
+ (unsigned long int) modid,
|
||||
+ (unsigned long int) dtv[modid].pointer.to_free);
|
||||
_dl_tls_allocate_begin ();
|
||||
free (dtv[modid].pointer.to_free);
|
||||
_dl_tls_allocate_end ();
|
||||
@@ -975,6 +1011,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
|
||||
dtv[GET_ADDR_MODULE].pointer.val = p;
|
||||
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: modid %lu using static TLS; TCB=0x%lx\n",
|
||||
+ (unsigned long int) GET_ADDR_MODULE,
|
||||
+ (unsigned long int) THREAD_SELF);
|
||||
+
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
}
|
||||
else
|
||||
@@ -1030,18 +1071,28 @@ __tls_get_addr (GET_ADDR_ARGS)
|
||||
{
|
||||
if (_dl_tls_allocate_active ()
|
||||
&& GET_ADDR_MODULE < _dl_tls_initial_modid_limit)
|
||||
+ {
|
||||
/* This is a reentrant __tls_get_addr call, but we can
|
||||
satisfy it because it's an initially-loaded module ID.
|
||||
These TLS slotinfo slots do not change, so the
|
||||
out-of-date generation counter does not matter. However,
|
||||
if not in a TLS update, still update_get_addr below, to
|
||||
get off the slow path eventually. */
|
||||
- ;
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: modid %lu reentrant usage; TCB=0x%lx\n",
|
||||
+ (unsigned long int) GET_ADDR_MODULE,
|
||||
+ (unsigned long int) THREAD_SELF);
|
||||
+ }
|
||||
else
|
||||
{
|
||||
/* Update DTV up to the global generation, see CONCURRENCY NOTES
|
||||
in _dl_update_slotinfo. */
|
||||
gen = atomic_load_acquire (&GL(dl_tls_generation));
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf (
|
||||
+ "tls: modid %lu update DTV to generation %lu; TCB=0x%lx\n",
|
||||
+ (unsigned long int) GET_ADDR_MODULE, (unsigned long int) gen,
|
||||
+ (unsigned long int) THREAD_SELF);
|
||||
return update_get_addr (GET_ADDR_PARAM, gen);
|
||||
}
|
||||
}
|
||||
@@ -1049,7 +1100,13 @@ __tls_get_addr (GET_ADDR_ARGS)
|
||||
void *p = dtv[GET_ADDR_MODULE].pointer.val;
|
||||
|
||||
if (__glibc_unlikely (p == TLS_DTV_UNALLOCATED))
|
||||
- return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
|
||||
+ {
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: modid %lu lazy allocation; TCB=0x%lx\n",
|
||||
+ (unsigned long int) GET_ADDR_MODULE,
|
||||
+ (unsigned long int) THREAD_SELF);
|
||||
+ return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
|
||||
+ }
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
}
|
||||
@@ -1119,6 +1176,10 @@ _dl_tls_initial_modid_limit_setup (void)
|
||||
break;
|
||||
}
|
||||
_dl_tls_initial_modid_limit = idx;
|
||||
+
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: initial modid limit set to %lu\n",
|
||||
+ (unsigned long int) idx);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index ff4c160d8fafd70d..3221bc8520996097 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -1257,6 +1257,11 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
|
||||
/* This image gets the ID one. */
|
||||
GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: assign modid %lu to %s [%ld]\n",
|
||||
+ (unsigned long int) main_map->l_tls_modid,
|
||||
+ DSO_FILENAME (main_map->l_name),
|
||||
+ (long int) main_map->l_ns);
|
||||
}
|
||||
break;
|
||||
|
||||
diff --git a/elf/tst-recursive-tlsmodN.c b/elf/tst-recursive-tlsmodN.c
|
||||
index bb7592aee6ed347e..921980605cf32a38 100644
|
||||
--- a/elf/tst-recursive-tlsmodN.c
|
||||
+++ b/elf/tst-recursive-tlsmodN.c
|
||||
@@ -19,10 +19,10 @@
|
||||
/* Compiled with VAR and FUNC set via -D. FUNC requires some
|
||||
relocation against TLS variable VAR. */
|
||||
|
||||
-__thread int VAR;
|
||||
+__thread char VAR[32768];
|
||||
|
||||
int
|
||||
FUNC (void)
|
||||
{
|
||||
- return VAR;
|
||||
+ return VAR[0];
|
||||
}
|
||||
diff --git a/elf/tst-tls-debug-recursive.sh b/elf/tst-tls-debug-recursive.sh
|
||||
new file mode 100755
|
||||
index 0000000000000000..083e716f7216ffd5
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-tls-debug-recursive.sh
|
||||
@@ -0,0 +1,83 @@
|
||||
+#!/bin/sh
|
||||
+# Test for TLS logging in dynamic linker.
|
||||
+# 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/>.
|
||||
+
|
||||
+# This script runs the tst-tls-debug-recursive test case and verifies its
|
||||
+# LD_DEBUG=tls output. It checks for various TLS-related messages
|
||||
+# to ensure the dynamic linker's TLS logging is working correctly.
|
||||
+
|
||||
+set -e
|
||||
+common_objpfx="$1"
|
||||
+test_wrapper_env="$2"
|
||||
+rtld_prefix="$3"
|
||||
+run_program_env="$4"
|
||||
+test_program="$5"
|
||||
+
|
||||
+debug_output="${common_objpfx}elf/tst-tls-debug-recursive.debug"
|
||||
+rm -f "${debug_output}".*
|
||||
+
|
||||
+# Run the test program with LD_DEBUG=tls.
|
||||
+eval "${test_wrapper_env}" LD_DEBUG=tls LD_DEBUG_OUTPUT="${debug_output}" \
|
||||
+ "${rtld_prefix}" "${test_program}"
|
||||
+
|
||||
+debug_output=$(ls "${debug_output}".*)
|
||||
+
|
||||
+fail=0
|
||||
+
|
||||
+# Check for expected messages
|
||||
+if ! grep -q 'tls: DTV resized for TCB 0x.*: oldsize' "${debug_output}"; then
|
||||
+ echo "FAIL: DTV resized message not found"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+if ! grep -q 'tls: DTV update for TCB 0x.*: modid .* deallocated block' "${debug_output}"; then
|
||||
+ echo "FAIL: module deallocated during DTV update message not found"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+if ! grep -q 'tls: assign modid .* to' "${debug_output}"; then
|
||||
+ echo "FAIL: module assigned message not found"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+if ! grep -q 'tls: allocate block .* for modid .* size=.*, TCB=0x' "${debug_output}"; then
|
||||
+ echo "FAIL: module allocated message not found"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+if ! grep -q 'tls: modid .* update DTV to generation .* TCB=0x' "${debug_output}"; then
|
||||
+ echo "FAIL: update DTV message not found"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+if ! grep -q 'tls: initial modid limit set to' "${debug_output}"; then
|
||||
+ echo "FAIL: initial modid limit message not found"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+if [ $fail -ne 0 ]; then
|
||||
+ echo "Test FAILED"
|
||||
+ cat "${debug_output}"
|
||||
+ rm -f "${debug_output}"
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
+echo "Test PASSED"
|
||||
+cat "${debug_output}"
|
||||
+rm -f "${debug_output}"
|
||||
+exit 0
|
||||
diff --git a/nptl/Makefile b/nptl/Makefile
|
||||
index 597311bf07223c4f..958de6b0002f63aa 100644
|
||||
--- a/nptl/Makefile
|
||||
+++ b/nptl/Makefile
|
||||
@@ -274,6 +274,7 @@ CFLAGS-tst-thread-exit-clobber.o = -std=gnu++11
|
||||
LDLIBS-tst-thread-exit-clobber = -lstdc++
|
||||
CFLAGS-tst-minstack-throw.o = -std=gnu++11
|
||||
LDLIBS-tst-minstack-throw = -lstdc++
|
||||
+LDLIBS-tst-dl-debug-tid = $(libdl)
|
||||
|
||||
tests = \
|
||||
tst-attr2 \
|
||||
@@ -486,6 +487,7 @@ modules-names = \
|
||||
tst-compat-forwarder-mod \
|
||||
tst-execstack-mod \
|
||||
tst-stack4mod \
|
||||
+ tst-tls-debug-mod \
|
||||
tst-tls3mod \
|
||||
tst-tls5mod \
|
||||
tst-tls5moda \
|
||||
@@ -687,7 +689,8 @@ tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child"
|
||||
tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
-$(objpfx)tst-dl-debug-tid.out: tst-dl-debug-tid.sh $(objpfx)tst-dl-debug-tid
|
||||
+$(objpfx)tst-dl-debug-tid.out: tst-dl-debug-tid.sh $(objpfx)tst-dl-debug-tid \
|
||||
+ $(objpfx)tst-tls-debug-mod.so
|
||||
$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' '$(rtld-prefix)' \
|
||||
'$(run-program-env)' \
|
||||
$(objpfx)tst-dl-debug-tid > $@; $(evaluate-test)
|
||||
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
|
||||
index 9e0bb8f0eeff8e88..6c6094e929f927cc 100644
|
||||
--- a/nptl/allocatestack.c
|
||||
+++ b/nptl/allocatestack.c
|
||||
@@ -115,7 +115,7 @@ get_cached_stack (size_t *sizep, void **memp)
|
||||
lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
|
||||
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
- GLRO (dl_debug_printf) ("TLS TCB reused from cache: 0x%lx\n",
|
||||
+ GLRO (dl_debug_printf) ("tls: TCB reused from cache: 0x%lx\n",
|
||||
(unsigned long int) result);
|
||||
|
||||
/* Report size and location of the stack to the caller. */
|
||||
@@ -297,9 +297,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
||||
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
GLRO (dl_debug_printf) (
|
||||
- "TCB for user-supplied stack created: 0x%lx, stack=0x%lx, size=%lu\n",
|
||||
- (unsigned long int) pd, (unsigned long int) pd->stackblock,
|
||||
- (unsigned long int) pd->stackblock_size);
|
||||
+ "tls: TCB created (user-supplied stack); stack=0x%lx, size=%lu, TCB=0x%lx\n",
|
||||
+ (unsigned long int) pd->stackblock,
|
||||
+ (unsigned long int) pd->stackblock_size, (unsigned long int) pd);
|
||||
|
||||
/* This is at least the second thread. */
|
||||
pd->header.multiple_threads = 1;
|
||||
@@ -436,7 +436,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
||||
pd->setxid_futex = -1;
|
||||
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
- GLRO (dl_debug_printf) ("TCB for new stack allocated: 0x%lx\n",
|
||||
+ GLRO (dl_debug_printf) ("tls: TCB allocated (new stack): 0x%lx\n",
|
||||
(unsigned long int) pd);
|
||||
|
||||
/* Allocate the DTV for this thread. */
|
||||
diff --git a/nptl/nptl-stack.c b/nptl/nptl-stack.c
|
||||
index 4ef6527ff7e8192b..d2d0729035a19dfe 100644
|
||||
--- a/nptl/nptl-stack.c
|
||||
+++ b/nptl/nptl-stack.c
|
||||
@@ -77,7 +77,7 @@ __nptl_free_stacks (size_t limit)
|
||||
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
GLRO (dl_debug_printf) (
|
||||
- "TCB cache full, deallocating: TID=%ld, TCB=0x%lx\n",
|
||||
+ "tls: TCB deallocating from full cache; TID=%ld, TCB=0x%lx\n",
|
||||
(long int) curr->tid, (unsigned long int) curr);
|
||||
|
||||
/* Free the memory associated with the ELF TLS. */
|
||||
@@ -104,7 +104,7 @@ queue_stack (struct pthread *stack)
|
||||
/* The 'stack' parameter is a pointer to the TCB (struct pthread),
|
||||
not just the stack. */
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
- GLRO (dl_debug_printf) ("TCB deallocated into cache: TID=%ld, TCB=0x%lx\n",
|
||||
+ GLRO (dl_debug_printf) ("tls: TCB deallocated into cache; TID=%ld, TCB=0x%lx\n",
|
||||
(long int) stack->tid, (unsigned long int) stack);
|
||||
|
||||
/* We unconditionally add the stack to the list. The memory may
|
||||
@@ -139,7 +139,7 @@ __nptl_deallocate_stack (struct pthread *pd)
|
||||
the TLS memory. */
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
GLRO (dl_debug_printf) (
|
||||
- "TCB for user-supplied stack deallocated: TID=%ld, TCB=0x%lx\n",
|
||||
+ "tls: TCB deallocated (user-supplied stack); TID=%ld, TCB=0x%lx\n",
|
||||
(long int) pd->tid, (unsigned long int) pd);
|
||||
/* Free the memory associated with the ELF TLS. */
|
||||
_dl_deallocate_tls (TLS_TPADJ (pd), false);
|
||||
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
|
||||
index 37de54eaa570cedb..c69b4108f60f647d 100644
|
||||
--- a/nptl/pthread_create.c
|
||||
+++ b/nptl/pthread_create.c
|
||||
@@ -363,7 +363,7 @@ start_thread (void *arg)
|
||||
}
|
||||
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
- GLRO (dl_debug_printf) ("Thread starting: TID=%ld, TCB=0x%lx\n",
|
||||
+ GLRO (dl_debug_printf) ("tls: thread starting; TID=%ld, TCB=0x%lx\n",
|
||||
(long int) pd->tid, (unsigned long int) pd);
|
||||
|
||||
/* Initialize resolver state pointer. */
|
||||
diff --git a/nptl/tst-dl-debug-tid.c b/nptl/tst-dl-debug-tid.c
|
||||
index 231fa43516b233b3..f3b443f9786a9a99 100644
|
||||
--- a/nptl/tst-dl-debug-tid.c
|
||||
+++ b/nptl/tst-dl-debug-tid.c
|
||||
@@ -27,12 +27,25 @@
|
||||
#include <support/xthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
+#include <dlfcn.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+#include <support/check.h>
|
||||
|
||||
static void *
|
||||
thread_function (void *arg)
|
||||
{
|
||||
if (arg)
|
||||
pthread_barrier_wait ((pthread_barrier_t *) arg);
|
||||
+
|
||||
+ /* Load a module with TLS to verify allocation/deallocation logs. */
|
||||
+ void *h = xdlopen ("tst-tls-debug-mod.so", RTLD_NOW);
|
||||
+
|
||||
+ /* Call a function that accesses TLS. */
|
||||
+ int (*fp) (void) = (int (*) (void)) xdlsym (h, "in_dso");
|
||||
+ TEST_COMPARE (fp (), 0);
|
||||
+
|
||||
+ xdlclose (h);
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
|
||||
diff --git a/nptl/tst-dl-debug-tid.sh b/nptl/tst-dl-debug-tid.sh
|
||||
index 9ee31ac4f241f0b4..8708ac9f2ea25c9e 100644
|
||||
--- a/nptl/tst-dl-debug-tid.sh
|
||||
+++ b/nptl/tst-dl-debug-tid.sh
|
||||
@@ -39,7 +39,7 @@ eval "${test_wrapper_env}" LD_DEBUG=tls LD_DEBUG_OUTPUT="${debug_output}" \
|
||||
|
||||
debug_output=$(ls "${debug_output}".*)
|
||||
# Check for the "Thread starting" message.
|
||||
-if ! grep -q 'Thread starting: TID=' "${debug_output}"; then
|
||||
+if ! grep -q 'tls: thread starting; TID=.*, TCB=0x' "${debug_output}"; then
|
||||
echo "error: 'Thread starting' message not found"
|
||||
cat "${debug_output}"
|
||||
exit 1
|
||||
@@ -47,10 +47,10 @@ fi
|
||||
|
||||
# Check that we have a message where the PID (from prefix) is different
|
||||
# from the TID (in the message). This indicates a worker thread log.
|
||||
-if ! grep 'Thread starting: TID=' "${debug_output}" | awk -F '[ \t:]+' '{
|
||||
- sub(/,/, "", $4);
|
||||
- sub(/TID=/, "", $4);
|
||||
- if ($1 != $4)
|
||||
+if ! grep 'tls: thread starting; TID=.*, TCB=0x' "${debug_output}" | awk -F '[ \t:]+' '{
|
||||
+ sub(/TID=/, "", $5);
|
||||
+ sub(/,/, "", $5);
|
||||
+ if ($1 != $5)
|
||||
exit 0;
|
||||
exit 1
|
||||
}'; then
|
||||
@@ -60,12 +60,33 @@ if ! grep 'Thread starting: TID=' "${debug_output}" | awk -F '[ \t:]+' '{
|
||||
fi
|
||||
|
||||
# We expect messages from thread creation and destruction.
|
||||
-if ! grep -q 'TCB allocated\|TCB deallocating\|TCB reused\|TCB deallocated' \
|
||||
+if ! grep -q 'tls: allocate TCB 0x\|tls: deallocate TCB 0x\|tls: TCB reused from cache\|tls: TCB deallocated' \
|
||||
"${debug_output}"; then
|
||||
echo "error: Expected TCB allocation/deallocation message not found"
|
||||
cat "${debug_output}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
+# Check for TLS module ID assignment.
|
||||
+if ! grep -q 'tls: assign modid .* to' "${debug_output}"; then
|
||||
+ echo "error: Expected 'modid ... assigned to' message not found"
|
||||
+ cat "${debug_output}"
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
+# Check for TLS block allocation.
|
||||
+if ! grep -q 'tls: allocate block .* for modid .* size=.*, TCB=0x' "${debug_output}"; then
|
||||
+ echo "error: Expected 'modid ... allocated' message not found"
|
||||
+ cat "${debug_output}"
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
+# TLS block deallocation might be skipped due to DTV surplus.
|
||||
+if grep -q 'tls: deallocate block .* for modid .* TCB=0x' "${debug_output}"; then
|
||||
+ echo "INFO: module deallocated message found"
|
||||
+else
|
||||
+ echo "INFO: module deallocated message not found (may be due to DTV surplus)"
|
||||
+fi
|
||||
+
|
||||
cat "${debug_output}"
|
||||
rm -f "${debug_output}"
|
||||
diff --git a/nptl/tst-tls-debug-mod.c b/nptl/tst-tls-debug-mod.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..0308c8a3e2d76fe1
|
||||
--- /dev/null
|
||||
+++ b/nptl/tst-tls-debug-mod.c
|
||||
@@ -0,0 +1,26 @@
|
||||
+/* Test for TLS logging in dynamic linker.
|
||||
+ 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/>. */
|
||||
+
|
||||
+__thread char tls_var[32768] __attribute__ ((tls_model ("global-dynamic")));
|
||||
+
|
||||
+int
|
||||
+in_dso (void)
|
||||
+{
|
||||
+ tls_var[0] = 42;
|
||||
+ return tls_var[0] - 42;
|
||||
+}
|
||||
diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
|
||||
index 7abfb18413b1d06c..2bd336876a6613c8 100644
|
||||
--- a/sysdeps/x86_64/dl-tls.c
|
||||
+++ b/sysdeps/x86_64/dl-tls.c
|
||||
@@ -41,11 +41,36 @@ __tls_get_addr_slow (GET_ADDR_ARGS)
|
||||
dtv_t *dtv = THREAD_DTV ();
|
||||
|
||||
size_t gen = atomic_load_acquire (&GL(dl_tls_generation));
|
||||
- if (__glibc_unlikely (dtv[0].counter != gen)
|
||||
+ if (__glibc_unlikely (dtv[0].counter != gen))
|
||||
+ {
|
||||
/* See comment in __tls_get_addr in elf/dl-tls.c. */
|
||||
- && !(_dl_tls_allocate_active ()
|
||||
- && GET_ADDR_MODULE < _dl_tls_initial_modid_limit))
|
||||
- return update_get_addr (GET_ADDR_PARAM, gen);
|
||||
+ if (_dl_tls_allocate_active ()
|
||||
+ && GET_ADDR_MODULE < _dl_tls_initial_modid_limit)
|
||||
+ {
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf (
|
||||
+ "tls: modid %lu reentrant usage; TCB=0x%lx\n",
|
||||
+ (unsigned long int) GET_ADDR_MODULE,
|
||||
+ (unsigned long int) THREAD_SELF);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf (
|
||||
+ "tls: modid %lu update DTV to generation %lu; TCB=0x%lx\n",
|
||||
+ (unsigned long int) GET_ADDR_MODULE, (unsigned long int) gen,
|
||||
+ (unsigned long int) THREAD_SELF);
|
||||
+ return update_get_addr (GET_ADDR_PARAM, gen);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (__glibc_unlikely (dtv[GET_ADDR_MODULE].pointer.val == TLS_DTV_UNALLOCATED))
|
||||
+ {
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))
|
||||
+ _dl_debug_printf ("tls: modid %lu lazy allocation; TCB=0x%lx\n",
|
||||
+ (unsigned long int) GET_ADDR_MODULE,
|
||||
+ (unsigned long int) THREAD_SELF);
|
||||
+ }
|
||||
|
||||
return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
|
||||
}
|
||||
177
SOURCES/glibc-RHEL-49785-6.patch
Normal file
177
SOURCES/glibc-RHEL-49785-6.patch
Normal file
@ -0,0 +1,177 @@
|
||||
commit 9181dc6eb6084da95d8c14d9defe96189fd0360d
|
||||
Author: Frédéric Bérat <berat.fred@gmail.com>
|
||||
Date: Tue Jan 27 23:07:17 2026 +0100
|
||||
|
||||
feat(rtld): Allow LD_DEBUG category exclusion
|
||||
|
||||
Adds support for excluding specific categories from `LD_DEBUG` output.
|
||||
|
||||
The `LD_DEBUG` environment variable now accepts category names prefixed
|
||||
with a dash (`-`) to disable their debugging output. This allows users
|
||||
to enable broad categories (e.g., `all`) while suppressing verbose or
|
||||
irrelevant information from specific sub-categories (e.g., `-tls`).
|
||||
|
||||
The `process_dl_debug` function in `rtld.c` has been updated to parse
|
||||
these exclusion options and unset the corresponding bits in
|
||||
`GLRO(dl_debug_mask)`. The `LD_DEBUG=help` output has also been updated
|
||||
to document this new functionality. A new test `tst-dl-debug-exclude.sh`
|
||||
is added to verify the correct behavior of category exclusion.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 2431e7032c44beb8..ec87811c61565511 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -1253,6 +1253,7 @@ $(objpfx)tst-glibcelf.out: tst-glibcelf.py elf.h $(..)/scripts/glibcelf.py \
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += $(objpfx)tst-tls-allocation-failure-static-patched.out
|
||||
tests-special += $(objpfx)tst-tls-debug-recursive.out
|
||||
+tests-special += $(objpfx)tst-dl-debug-exclude.out
|
||||
endif
|
||||
|
||||
# The test requires shared _and_ PIE because the executable
|
||||
@@ -3064,4 +3065,14 @@ $(objpfx)tst-tls-debug-recursive.out: tst-tls-debug-recursive.sh \
|
||||
'$(rtld-prefix)' '$(run_program_env)' \
|
||||
$(objpfx)tst-recursive-tls > $@; \
|
||||
$(evaluate-test)
|
||||
+
|
||||
+$(objpfx)tst-dl-debug-exclude.out: tst-dl-debug-exclude.sh \
|
||||
+ $(objpfx)tst-recursive-tls \
|
||||
+ $(objpfx)tst-recursive-tlsmallocmod.so \
|
||||
+ $(patsubst %,$(objpfx)tst-recursive-tlsmod%.so, \
|
||||
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
|
||||
+ $(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' \
|
||||
+ '$(rtld-prefix)' '$(run_program_env)' \
|
||||
+ $(objpfx)tst-recursive-tls > $@; \
|
||||
+ $(evaluate-test)
|
||||
endif
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index 3221bc8520996097..a4290890d6bca263 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -2708,11 +2708,18 @@ process_dl_debug (struct dl_main_state *state, const char *dl_debug)
|
||||
&& dl_debug[len] != ',' && dl_debug[len] != ':')
|
||||
++len;
|
||||
|
||||
+ bool exclude = *dl_debug == '-';
|
||||
+ const char *name = exclude ? dl_debug + 1 : dl_debug;
|
||||
+ size_t name_len = exclude ? len - 1 : len;
|
||||
+
|
||||
for (cnt = 0; cnt < ndebopts; ++cnt)
|
||||
- if (debopts[cnt].len == len
|
||||
- && memcmp (dl_debug, debopts[cnt].name, len) == 0)
|
||||
+ if (debopts[cnt].len == name_len
|
||||
+ && memcmp (name, debopts[cnt].name, name_len) == 0)
|
||||
{
|
||||
- GLRO(dl_debug_mask) |= debopts[cnt].mask;
|
||||
+ if (exclude)
|
||||
+ GLRO(dl_debug_mask) &= ~debopts[cnt].mask;
|
||||
+ else
|
||||
+ GLRO(dl_debug_mask) |= debopts[cnt].mask;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2754,7 +2761,8 @@ Valid options for the LD_DEBUG environment variable are:\n\n");
|
||||
|
||||
_dl_printf ("\n\
|
||||
To direct the debugging output into a file instead of standard output\n\
|
||||
-a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n");
|
||||
+a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n\
|
||||
+Categories can be excluded by prefixing them with a dash (-).\n");
|
||||
_exit (0);
|
||||
}
|
||||
}
|
||||
diff --git a/elf/tst-dl-debug-exclude.sh b/elf/tst-dl-debug-exclude.sh
|
||||
new file mode 100644
|
||||
index 0000000000000000..9837ffcea8e07933
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dl-debug-exclude.sh
|
||||
@@ -0,0 +1,87 @@
|
||||
+#!/bin/sh
|
||||
+# Test for LD_DEBUG category exclusion.
|
||||
+# 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/>.
|
||||
+
|
||||
+# This script verifies the LD_DEBUG category exclusion functionality.
|
||||
+# It checks that:
|
||||
+# 1. Categories can be excluded using the '-' prefix.
|
||||
+# 2. Options are processed sequentially, meaning the last specified
|
||||
+# option for a category (enable or exclude) takes precedence.
|
||||
+
|
||||
+set -e
|
||||
+
|
||||
+common_objpfx="$1"
|
||||
+test_wrapper_env="$2"
|
||||
+rtld_prefix="$3"
|
||||
+run_program_env="$4"
|
||||
+test_program="$5"
|
||||
+
|
||||
+debug_output="${common_objpfx}elf/tst-dl-debug-exclude.debug"
|
||||
+rm -f "${debug_output}".*
|
||||
+
|
||||
+# Run the test program with LD_DEBUG=all,-tls.
|
||||
+# We expect general logs but no TLS logs.
|
||||
+eval "${test_wrapper_env}" LD_DEBUG=all,-tls LD_DEBUG_OUTPUT="${debug_output}" \
|
||||
+ "${rtld_prefix}" "${test_program}"
|
||||
+
|
||||
+fail=0
|
||||
+
|
||||
+# 1. Check that general logs are present (e.g., file loading)
|
||||
+if ! grep -q 'file=' "${debug_output}".*; then
|
||||
+ echo "FAIL: 'file=' message not found (LD_DEBUG=all failed)"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+# 2. Check that TLS logs are NOT present
|
||||
+if grep -q 'tls: ' "${debug_output}".*; then
|
||||
+ echo "FAIL: TLS message found (exclusion of -tls failed)"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+rm -f "${debug_output}".*
|
||||
+# 3. Check for LD_DEBUG=all,-tls,tls (ordering verification)
|
||||
+# We expect TLS logs to BE present
|
||||
+eval "${test_wrapper_env}" LD_DEBUG=all,-tls,tls LD_DEBUG_OUTPUT="${debug_output}" \
|
||||
+ "${rtld_prefix}" "${test_program}"
|
||||
+
|
||||
+if ! grep -q 'tls: ' "${debug_output}".*; then
|
||||
+ echo "FAIL: TLS message not found (ordering -tls,tls failed)"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+rm -f "${debug_output}".*
|
||||
+# 4. Check for LD_DEBUG=tls,-tls
|
||||
+# We expect TLS logs to NOT be present
|
||||
+eval "${test_wrapper_env}" LD_DEBUG=tls,-tls LD_DEBUG_OUTPUT="${debug_output}" \
|
||||
+ "${rtld_prefix}" "${test_program}"
|
||||
+
|
||||
+if grep -q 'tls: ' "${debug_output}".*; then
|
||||
+ echo "FAIL: TLS message found (ordering tls,-tls failed)"
|
||||
+ fail=1
|
||||
+fi
|
||||
+
|
||||
+if [ $fail -ne 0 ]; then
|
||||
+ echo "Test FAILED"
|
||||
+ cat "${debug_output}".*
|
||||
+ rm -f "${debug_output}".*
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
+echo "Test PASSED"
|
||||
+rm -f "${debug_output}".*
|
||||
+exit 0
|
||||
288
SOURCES/glibc-RHEL-52966.patch
Normal file
288
SOURCES/glibc-RHEL-52966.patch
Normal file
@ -0,0 +1,288 @@
|
||||
commit 39ca997ab378990d5ac1aadbaa52aaf1db6d526f
|
||||
Author: Andreas Schwab <schwab@suse.de>
|
||||
Date: Mon Aug 5 10:55:51 2024 +0200
|
||||
|
||||
Fix name space violation in fortify wrappers (bug 32052)
|
||||
|
||||
Rename the identifier sz to __sz everywhere.
|
||||
|
||||
Fixes: a643f60c53 ("Make sure that the fortified function conditionals are constant")
|
||||
|
||||
Conflicts:
|
||||
libio/bits/stdio2.h
|
||||
(29951991f5db1001c059f8ed7afa2c359cdc7f44 missing downstream)
|
||||
socket/bits/socket2.h
|
||||
(4289b00d4393f490515527864cf09093f4f8c2c4 missing downstream)
|
||||
stdlib/bits/stdlib.h
|
||||
(d39a893ed6de8e63ffbfbcc4b7176a2fa852f8a8 missing downstream)
|
||||
wcsmbs/bits/wchar2.h
|
||||
(68444c045077368446eced143510419c901e31b1 missing downstream)
|
||||
|
||||
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
|
||||
index 4570f86a4496c1ee..5d1f3574f9f3fa9e 100644
|
||||
--- a/libio/bits/stdio2.h
|
||||
+++ b/libio/bits/stdio2.h
|
||||
@@ -208,12 +208,12 @@ extern char *__REDIRECT (__fgets_chk_warn,
|
||||
__fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
|
||||
fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
|
||||
return __fgets_alias (__s, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
|
||||
- return __fgets_chk_warn (__s, sz, __n, __stream);
|
||||
- return __fgets_chk (__s, sz, __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
|
||||
+ return __fgets_chk_warn (__s, __sz, __n, __stream);
|
||||
+ return __fgets_chk (__s, __sz, __n, __stream);
|
||||
}
|
||||
|
||||
extern size_t __REDIRECT (__fread_alias,
|
||||
@@ -232,12 +232,12 @@ __fortify_function __wur size_t
|
||||
fread (void *__restrict __ptr, size_t __size, size_t __n,
|
||||
FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize0 (__ptr);
|
||||
- if (__glibc_safe_or_unknown_len (__n, __size, sz))
|
||||
+ size_t __sz = __glibc_objsize0 (__ptr);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, __size, __sz))
|
||||
return __fread_alias (__ptr, __size, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, __size, sz))
|
||||
- return __fread_chk_warn (__ptr, sz, __size, __n, __stream);
|
||||
- return __fread_chk (__ptr, sz, __size, __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, __size, __sz))
|
||||
+ return __fread_chk_warn (__ptr, __sz, __size, __n, __stream);
|
||||
+ return __fread_chk (__ptr, __sz, __size, __n, __stream);
|
||||
}
|
||||
|
||||
#ifdef __USE_GNU
|
||||
@@ -254,12 +254,12 @@ extern char *__REDIRECT (__fgets_unlocked_chk_warn,
|
||||
__fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
|
||||
fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
|
||||
return __fgets_unlocked_alias (__s, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
|
||||
- return __fgets_unlocked_chk_warn (__s, sz, __n, __stream);
|
||||
- return __fgets_unlocked_chk (__s, sz, __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
|
||||
+ return __fgets_unlocked_chk_warn (__s, __sz, __n, __stream);
|
||||
+ return __fgets_unlocked_chk (__s, __sz, __n, __stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -281,8 +281,8 @@ __fortify_function __wur size_t
|
||||
fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
|
||||
FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize0 (__ptr);
|
||||
- if (__glibc_safe_or_unknown_len (__n, __size, sz))
|
||||
+ size_t __sz = __glibc_objsize0 (__ptr);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, __size, __sz))
|
||||
{
|
||||
# ifdef __USE_EXTERN_INLINES
|
||||
if (__builtin_constant_p (__size)
|
||||
@@ -307,9 +307,9 @@ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
|
||||
# endif
|
||||
return __fread_unlocked_alias (__ptr, __size, __n, __stream);
|
||||
}
|
||||
- if (__glibc_unsafe_len (__n, __size, sz))
|
||||
- return __fread_unlocked_chk_warn (__ptr, sz, __size, __n, __stream);
|
||||
- return __fread_unlocked_chk (__ptr, sz, __size, __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, __size, __sz))
|
||||
+ return __fread_unlocked_chk_warn (__ptr, __sz, __size, __n, __stream);
|
||||
+ return __fread_unlocked_chk (__ptr, __sz, __size, __n, __stream);
|
||||
|
||||
}
|
||||
#endif
|
||||
diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h
|
||||
index b28cde55f3fd9c16..e278ebf37b03f121 100644
|
||||
--- a/socket/bits/socket2.h
|
||||
+++ b/socket/bits/socket2.h
|
||||
@@ -33,12 +33,12 @@ extern ssize_t __REDIRECT (__recv_chk_warn,
|
||||
__fortify_function ssize_t
|
||||
recv (int __fd, void *__buf, size_t __n, int __flags)
|
||||
{
|
||||
- size_t sz = __glibc_objsize0 (__buf);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
|
||||
+ size_t __sz = __glibc_objsize0 (__buf);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
|
||||
return __recv_alias (__fd, __buf, __n, __flags);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
|
||||
- return __recv_chk_warn (__fd, __buf, __n, sz, __flags);
|
||||
- return __recv_chk (__fd, __buf, __n, sz, __flags);
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
|
||||
+ return __recv_chk_warn (__fd, __buf, __n, __sz, __flags);
|
||||
+ return __recv_chk (__fd, __buf, __n, __sz, __flags);
|
||||
}
|
||||
|
||||
extern ssize_t __recvfrom_chk (int __fd, void *__restrict __buf, size_t __n,
|
||||
@@ -61,11 +61,11 @@ __fortify_function ssize_t
|
||||
recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
|
||||
__SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
|
||||
{
|
||||
- size_t sz = __glibc_objsize0 (__buf);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
|
||||
+ size_t __sz = __glibc_objsize0 (__buf);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
|
||||
return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
|
||||
- return __recvfrom_chk_warn (__fd, __buf, __n, sz, __flags, __addr,
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
|
||||
+ return __recvfrom_chk_warn (__fd, __buf, __n, __sz, __flags, __addr,
|
||||
__addr_len);
|
||||
- return __recvfrom_chk (__fd, __buf, __n, sz, __flags, __addr, __addr_len);
|
||||
+ return __recvfrom_chk (__fd, __buf, __n, __sz, __flags, __addr, __addr_len);
|
||||
}
|
||||
diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
|
||||
index ac9badc81f3990c5..658a08b80f3a3141 100644
|
||||
--- a/stdlib/bits/stdlib.h
|
||||
+++ b/stdlib/bits/stdlib.h
|
||||
@@ -36,16 +36,16 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn,
|
||||
__fortify_function __wur char *
|
||||
__NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__resolved);
|
||||
+ size_t __sz = __glibc_objsize (__resolved);
|
||||
|
||||
- if (sz == (size_t) -1)
|
||||
+ if (__sz == (size_t) -1)
|
||||
return __realpath_alias (__name, __resolved);
|
||||
|
||||
#if defined _LIBC_LIMITS_H_ && defined PATH_MAX
|
||||
- if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
|
||||
- return __realpath_chk_warn (__name, __resolved, sz);
|
||||
+ if (__glibc_unsafe_len (PATH_MAX, sizeof (char), __sz))
|
||||
+ return __realpath_chk_warn (__name, __resolved, __sz);
|
||||
#endif
|
||||
- return __realpath_chk (__name, __resolved, sz);
|
||||
+ return __realpath_chk (__name, __resolved, __sz);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
|
||||
index 50151b424d85a032..ee43dcb6a9170564 100644
|
||||
--- a/wcsmbs/bits/wchar2.h
|
||||
+++ b/wcsmbs/bits/wchar2.h
|
||||
@@ -107,9 +107,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
|
||||
__fortify_function wchar_t *
|
||||
__NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__dest);
|
||||
- if (sz != (size_t) -1)
|
||||
- return __wcscpy_chk (__dest, __src, sz / sizeof (wchar_t));
|
||||
+ size_t __sz = __glibc_objsize (__dest);
|
||||
+ if (__sz != (size_t) -1)
|
||||
+ return __wcscpy_chk (__dest, __src, __sz / sizeof (wchar_t));
|
||||
return __wcscpy_alias (__dest, __src);
|
||||
}
|
||||
|
||||
@@ -121,9 +121,9 @@ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
|
||||
__fortify_function wchar_t *
|
||||
__NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__dest);
|
||||
- if (sz != (size_t) -1)
|
||||
- return __wcpcpy_chk (__dest, __src, sz / sizeof (wchar_t));
|
||||
+ size_t __sz = __glibc_objsize (__dest);
|
||||
+ if (__sz != (size_t) -1)
|
||||
+ return __wcpcpy_chk (__dest, __src, __sz / sizeof (wchar_t));
|
||||
return __wcpcpy_alias (__dest, __src);
|
||||
}
|
||||
|
||||
@@ -177,9 +177,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
|
||||
__fortify_function wchar_t *
|
||||
__NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__dest);
|
||||
- if (sz != (size_t) -1)
|
||||
- return __wcscat_chk (__dest, __src, sz / sizeof (wchar_t));
|
||||
+ size_t __sz = __glibc_objsize (__dest);
|
||||
+ if (__sz != (size_t) -1)
|
||||
+ return __wcscat_chk (__dest, __src, __sz / sizeof (wchar_t));
|
||||
return __wcscat_alias (__dest, __src);
|
||||
}
|
||||
|
||||
@@ -193,9 +193,9 @@ __fortify_function wchar_t *
|
||||
__NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
|
||||
size_t __n))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__dest);
|
||||
- if (sz != (size_t) -1)
|
||||
- return __wcsncat_chk (__dest, __src, __n, sz / sizeof (wchar_t));
|
||||
+ size_t __sz = __glibc_objsize (__dest);
|
||||
+ if (__sz != (size_t) -1)
|
||||
+ return __wcsncat_chk (__dest, __src, __n, __sz / sizeof (wchar_t));
|
||||
return __wcsncat_alias (__dest, __src, __n);
|
||||
}
|
||||
|
||||
@@ -211,10 +211,10 @@ __fortify_function int
|
||||
__NTH (swprintf (wchar_t *__restrict __s, size_t __n,
|
||||
const wchar_t *__restrict __fmt, ...))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
|
||||
return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
|
||||
- sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
|
||||
+ __sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
|
||||
return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
|
||||
}
|
||||
#elif !defined __cplusplus
|
||||
@@ -236,10 +236,10 @@ __fortify_function int
|
||||
__NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
|
||||
const wchar_t *__restrict __fmt, __gnuc_va_list __ap))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
|
||||
return __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
|
||||
- sz / sizeof (wchar_t), __fmt, __ap);
|
||||
+ __sz / sizeof (wchar_t), __fmt, __ap);
|
||||
return __vswprintf_alias (__s, __n, __fmt, __ap);
|
||||
}
|
||||
|
||||
@@ -293,12 +293,12 @@ extern wchar_t *__REDIRECT (__fgetws_chk_warn,
|
||||
__fortify_function __wur wchar_t *
|
||||
fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
|
||||
return __fgetws_alias (__s, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
|
||||
- return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream);
|
||||
- return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
|
||||
+ return __fgetws_chk_warn (__s, __sz / sizeof (wchar_t), __n, __stream);
|
||||
+ return __fgetws_chk (__s, __sz / sizeof (wchar_t), __n, __stream);
|
||||
}
|
||||
|
||||
#ifdef __USE_GNU
|
||||
@@ -316,13 +316,13 @@ extern wchar_t *__REDIRECT (__fgetws_unlocked_chk_warn,
|
||||
__fortify_function __wur wchar_t *
|
||||
fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
|
||||
return __fgetws_unlocked_alias (__s, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
|
||||
- return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n,
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
|
||||
+ return __fgetws_unlocked_chk_warn (__s, __sz / sizeof (wchar_t), __n,
|
||||
__stream);
|
||||
- return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
|
||||
+ return __fgetws_unlocked_chk (__s, __sz / sizeof (wchar_t), __n, __stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
111
SOURCES/glibc-RHEL-54450.patch
Normal file
111
SOURCES/glibc-RHEL-54450.patch
Normal file
@ -0,0 +1,111 @@
|
||||
commit b52619f2e8bbae57d79c95538346198c4a9f24a6
|
||||
Author: Arjun Shankar <arjun@redhat.com>
|
||||
Date: Mon Jan 26 13:49:37 2026 +0100
|
||||
|
||||
dlfcn: Add dlinfo request type RTLD_DI_ORIGIN_PATH (bug #24298)
|
||||
|
||||
The existing dlinfo request type RTLD_DI_ORIGIN used for querying the
|
||||
value of the '$ORIGIN' dynamic string token is prone to buffer
|
||||
overflows.
|
||||
|
||||
This commit adds a new request type named RTLD_DI_ORIGIN_PATH that
|
||||
returns a pointer to the dynamic string token (i.e. the 'l_origin' field
|
||||
in the link map) instead. The dlinfo manual is updated with the new
|
||||
request type, and the description of RTLD_DI_ORIGIN is updated to
|
||||
recommend RTLD_DI_ORIGIN_PATH instead.
|
||||
|
||||
A test for the new request type is also added to tst-dlinfo.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h
|
||||
index 8168a71dbfe90e75..b80c3e3d9f240e80 100644
|
||||
--- a/dlfcn/dlfcn.h
|
||||
+++ b/dlfcn/dlfcn.h
|
||||
@@ -169,7 +169,12 @@ enum
|
||||
the number of program headers in the array. */
|
||||
RTLD_DI_PHDR = 11,
|
||||
|
||||
- RTLD_DI_MAX = 11
|
||||
+ /* Treat ARG as `const char **' and at that location, store the address
|
||||
+ of the directory name used to expand $ORIGIN in this shared object's
|
||||
+ dependency file names. */
|
||||
+ RTLD_DI_ORIGIN_PATH = 12,
|
||||
+
|
||||
+ RTLD_DI_MAX = 12
|
||||
};
|
||||
|
||||
|
||||
diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c
|
||||
index 1842925fb7c594dd..28681a865a11e102 100644
|
||||
--- a/dlfcn/dlinfo.c
|
||||
+++ b/dlfcn/dlinfo.c
|
||||
@@ -67,6 +67,13 @@ dlinfo_doit (void *argsblock)
|
||||
strcpy (args->arg, l->l_origin);
|
||||
break;
|
||||
|
||||
+ case RTLD_DI_ORIGIN_PATH:
|
||||
+ if (l->l_origin != (char *) -1)
|
||||
+ *(const char **) args->arg = l->l_origin;
|
||||
+ else
|
||||
+ *(const char **) args->arg = NULL;
|
||||
+ break;
|
||||
+
|
||||
case RTLD_DI_TLS_MODID:
|
||||
*(size_t *) args->arg = 0;
|
||||
*(size_t *) args->arg = l->l_tls_modid;
|
||||
diff --git a/dlfcn/tst-dlinfo.c b/dlfcn/tst-dlinfo.c
|
||||
index d47eebc013a556b4..0765be8e649251b7 100644
|
||||
--- a/dlfcn/tst-dlinfo.c
|
||||
+++ b/dlfcn/tst-dlinfo.c
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <error.h>
|
||||
+#include <support/check.h>
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
|
||||
@@ -56,6 +57,13 @@ do_test (void)
|
||||
printf ("origin: %s\n", origin);
|
||||
}
|
||||
|
||||
+ const char *origin_path;
|
||||
+ TRY (RTLD_DI_ORIGIN_PATH, &origin_path)
|
||||
+ {
|
||||
+ TEST_COMPARE_STRING (origin, origin_path);
|
||||
+ printf ("origin_path: %s\n", origin_path);
|
||||
+ }
|
||||
+
|
||||
Dl_serinfo counts;
|
||||
TRY (RTLD_DI_SERINFOSIZE, &counts)
|
||||
{
|
||||
diff --git a/manual/dynlink.texi b/manual/dynlink.texi
|
||||
index f97f13444f1c5946..2b35e5883c3e65c0 100644
|
||||
--- a/manual/dynlink.texi
|
||||
+++ b/manual/dynlink.texi
|
||||
@@ -482,13 +482,23 @@ The namespace identifier of @var{handle} is written to
|
||||
@code{*@var{arg}}. The @var{arg} argument must be the address of an
|
||||
object of type @code{Lmid_t}.
|
||||
|
||||
+@item RTLD_DI_ORIGIN_PATH
|
||||
+The @code{$ORIGIN} dynamic string token pointer for @var{handle} is written
|
||||
+to @code{*@var{arg}}. The @var{arg} argument must be the address of a
|
||||
+@code{const char *}. If the @code{$ORIGIN} could not be determined, the
|
||||
+function still returns 0 but writes a null pointer to @code{*@var{arg}}.
|
||||
+The returned string is only valid as long as the corresponding handle is
|
||||
+valid. Accessing it after @code{dlclose} has been called for the
|
||||
+corresponding @var{handle} is undefined behavior.
|
||||
+
|
||||
@item RTLD_DI_ORIGIN
|
||||
The value of the @code{$ORIGIN} dynamic string token for @var{handle} is
|
||||
written to the character array starting at @var{arg} as a
|
||||
null-terminated string.
|
||||
|
||||
This request type should not be used because it is prone to buffer
|
||||
-overflows.
|
||||
+overflows. Instead, @code{RTLD_DI_ORIGIN_PATH} described above should be
|
||||
+used.
|
||||
|
||||
@item RTLD_DI_SERINFO
|
||||
@itemx RTLD_DI_SERINFOSIZE
|
||||
@ -1,2 +1,2 @@
|
||||
eae38d8010e461f8f0d4a9ec27080eb89bc2e6fe
|
||||
92cd2bbb684588d562a37ffea13a37cccebe428a
|
||||
v1
|
||||
|
||||
@ -1,3 +1,402 @@
|
||||
commit 92cd2bbb684588d562a37ffea13a37cccebe428a
|
||||
Author: DJ Delorie <dj@redhat.com>
|
||||
AuthorDate: Wed Jul 29 13:35:13 2026 -0400
|
||||
Commit: DJ Delorie <dj@redhat.com>
|
||||
CommitDate: Wed Jul 29 14:23:26 2026 -0400
|
||||
|
||||
Stop shipping glibc32-debuginfo (RHEL-219516)
|
||||
|
||||
By stripping the symbol table from the glibc32 shared objects,
|
||||
we disable the creation of debuginfo packages, which we do not
|
||||
need nor want to ship.
|
||||
|
||||
Resolves: RHEL-219516
|
||||
|
||||
:100644 100644 509fa59 c7c189a M glibc.spec
|
||||
|
||||
commit 107c909712e52b9e6bd3792ac930d9436eb0ba8f
|
||||
Author: Bruno Goncalves <bgoncalv@redhat.com>
|
||||
AuthorDate: Fri Jun 19 14:28:54 2026 +0200
|
||||
Commit: Bruno Goncalves <bgoncalv@redhat.com>
|
||||
CommitDate: Tue Jul 28 09:55:38 2026 +0200
|
||||
|
||||
CI Gating: drop kernel-qe gating
|
||||
|
||||
RPM-Changelog: -
|
||||
RPM-Skip-Release: yes
|
||||
|
||||
:100644 100644 9300333 2df044a M gating.yaml
|
||||
|
||||
commit 4927d93cd55390c899eae233b64b508e599fc678
|
||||
Author: Patsy Griffin <patsy@redhat.com>
|
||||
AuthorDate: Fri Jul 10 17:09:17 2026 -0400
|
||||
Commit: pfrankli <pfrankli@redhat.com>
|
||||
CommitDate: Wed Jul 22 16:46:27 2026 +0000
|
||||
|
||||
iconv: Suppress intermediate errors with //TRANSLIT (RHEL-178279)
|
||||
|
||||
Resolves: RHEL-178279
|
||||
|
||||
:000000 100644 0000000 ded65f1 A glibc-RHEL-178279.patch
|
||||
|
||||
commit 16fb6ccc05ad3ba571a4adf64058fa7bc30e455f
|
||||
Author: Lenka Špačková <lspackova@redhat.com>
|
||||
AuthorDate: Wed Jul 15 15:47:43 2026 +0200
|
||||
Commit: Lenka Špačková <lspackova@redhat.com>
|
||||
CommitDate: Wed Jul 15 15:47:43 2026 +0200
|
||||
|
||||
Regression/bz2115831-glibc-missing-gnu-debuglink-section-in: adjust relevancy for RHEL 9
|
||||
|
||||
Fixed in RHEL 9.8: RHEL-27851
|
||||
|
||||
RPM-Changelog: -
|
||||
RPM-Skip-Release: yes
|
||||
|
||||
:100644 100644 36de426 b9c1fe0 M tests/Regression/bz2115831-glibc-missing-gnu-debuglink-section-in/main.fmf
|
||||
|
||||
commit 1d22b956dda1e7fdc090165ae3bc8d882cd4e516
|
||||
Author: DJ Delorie <dj@redhat.com>
|
||||
AuthorDate: Thu Jun 25 23:10:08 2026 -0400
|
||||
Commit: Frédéric Bérat <fberat@redhat.com>
|
||||
CommitDate: Tue Jul 7 12:54:03 2026 +0000
|
||||
|
||||
CVE-2026-5435 Out-of-bounds write via TSIG record processing
|
||||
|
||||
Resolves: RHEL-180336
|
||||
Resolves: RHEL-185614
|
||||
|
||||
:000000 100644 0000000 9894622 A glibc-RHEL-180336-1.patch
|
||||
:000000 100644 0000000 2f90da8 A glibc-RHEL-180336-2.patch
|
||||
:000000 100644 0000000 cc495bc A glibc-RHEL-180336-3.patch
|
||||
:000000 100644 0000000 acef669 A glibc-RHEL-180336-4.patch
|
||||
:000000 100644 0000000 a019f27 A glibc-RHEL-180336-5.patch
|
||||
:000000 100644 0000000 1222ad9 A glibc-RHEL-180336-6.patch
|
||||
:000000 100644 0000000 3250e7b A glibc-RHEL-180336-7.patch
|
||||
|
||||
commit 2acec79102345198aa8dfd4b8a89f75f11205a0b
|
||||
Author: Patsy Griffin <patsy@redhat.com>
|
||||
AuthorDate: Fri Jun 26 11:52:03 2026 -0400
|
||||
Commit: Patsy Griffin <patsy@redhat.com>
|
||||
CommitDate: Fri Jun 26 11:52:03 2026 -0400
|
||||
|
||||
CVE-2026-5928: Fix ungetwc operating on byte stream (RHEL-180340)
|
||||
|
||||
Resolves: RHEL-180340
|
||||
|
||||
:000000 100644 0000000 0771d0a A glibc-RHEL-180340.patch
|
||||
|
||||
commit ec99e297ec21a794af038ae0b8ad9eae6a5b7a54
|
||||
Author: Patsy Griffin <patsy@redhat.com>
|
||||
AuthorDate: Mon Jun 22 06:53:56 2026 -0400
|
||||
Commit: pfrankli <pfrankli@redhat.com>
|
||||
CommitDate: Mon Jun 22 13:49:01 2026 +0000
|
||||
|
||||
CVE-2026-5450: Fix buffer overflow in scanf (RHEL-172710)
|
||||
|
||||
Resolves: RHEL-172710
|
||||
|
||||
:000000 100644 0000000 1bd6427 A glibc-RHEL-172710-1.patch
|
||||
:000000 100644 0000000 a334a8c A glibc-RHEL-172710-2.patch
|
||||
:000000 100644 0000000 6bfe8c5 A glibc-RHEL-172710-3.patch
|
||||
:000000 100644 0000000 12a03cd A glibc-RHEL-172710-4.patch
|
||||
|
||||
commit 396dbae5399bc8ee97a617cc9ad4e1d95d26faf1
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
AuthorDate: Fri Jun 19 14:54:09 2026 +0200
|
||||
Commit: Sergey Kolosov <skolosov@redhat.com>
|
||||
CommitDate: Fri Jun 19 14:54:09 2026 +0200
|
||||
|
||||
CI Gating: Add fail-fast test plan jobs as required rules
|
||||
|
||||
RPM-Changelog: -
|
||||
RPM-Skip-Release: yes
|
||||
|
||||
:100644 100644 ba7f921 9300333 M gating.yaml
|
||||
|
||||
commit beeb5b354b9f5fd8745cc034694041b2ca91e31d
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
AuthorDate: Thu Jun 4 11:49:13 2026 +0200
|
||||
Commit: Frédéric Bérat <fberat@redhat.com>
|
||||
CommitDate: Tue Jun 9 11:29:39 2026 +0200
|
||||
|
||||
Fix gconv module reference counter overflow in swscanf and swprintf families
|
||||
|
||||
Resolves: RHEL-145156
|
||||
|
||||
:000000 100644 0000000 d591eea A glibc-RHEL-145156-1.patch
|
||||
:000000 100644 0000000 01b7d9c A glibc-RHEL-145156-2.patch
|
||||
:000000 100644 0000000 78b117e A glibc-RHEL-145156-3.patch
|
||||
:000000 100644 0000000 62dec63 A glibc-RHEL-145156-4.patch
|
||||
:000000 100644 0000000 41d91fd A glibc-RHEL-145156-5.patch
|
||||
|
||||
commit 381936891b4e421cd9a03b682bcb5a66039fd230
|
||||
Author: Patsy Griffin <patsy@redhat.com>
|
||||
AuthorDate: Mon May 4 22:48:56 2026 -0400
|
||||
Commit: Florian Weimer <fweimer@redhat.com>
|
||||
CommitDate: Sun May 10 17:40:44 2026 +0000
|
||||
|
||||
Fix incorrect setting of CXX variable in spec file (RHEL-148252)
|
||||
|
||||
Resolves: RHEL-148252
|
||||
|
||||
:100644 100644 54e9fb1 509fa59 M glibc.spec
|
||||
|
||||
commit c86a21c28e56e47fa7ff5507191d9f3146363574
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
AuthorDate: Wed May 6 10:07:53 2026 +0200
|
||||
Commit: Florian Weimer <fweimer@redhat.com>
|
||||
CommitDate: Sun May 10 05:29:05 2026 +0000
|
||||
|
||||
Fix __nss_get_default_domain logic to restore netgroup user enumeration (RHEL-168096)
|
||||
|
||||
Resolves: RHEL-168096
|
||||
|
||||
:000000 100644 0000000 cd80ed7 A glibc-RHEL-168096.patch
|
||||
|
||||
commit a35ccbc1615d3cc93ac7427a3c3b3d2f4da64e55
|
||||
Author: Arjun Shankar <arjun@redhat.com>
|
||||
AuthorDate: Mon May 4 13:48:25 2026 +0200
|
||||
Commit: Florian Weimer <fweimer@redhat.com>
|
||||
CommitDate: Sat May 9 08:46:30 2026 +0000
|
||||
|
||||
resolv: Correctly count records and check hostname validity (RHEL-168851, RHEL-168852)
|
||||
|
||||
Resolves: RHEL-168851
|
||||
Resolves: RHEL-168852
|
||||
|
||||
:000000 100644 0000000 9e41b3f A glibc-RHEL-168851.patch
|
||||
:000000 100644 0000000 159e4d5 A glibc-RHEL-168852.patch
|
||||
|
||||
commit 437183f942920f2ae5a825d4a710edd5b0def2d1
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
AuthorDate: Thu Apr 30 15:34:53 2026 +0200
|
||||
Commit: Florian Weimer <fweimer@redhat.com>
|
||||
CommitDate: Wed May 6 08:18:22 2026 +0000
|
||||
|
||||
CVE-2026-4046: Fix assertion failure in IBM1390 and IBM1399 iconv modules (RHEL-162901)
|
||||
|
||||
Resolves: RHEL-162901
|
||||
|
||||
:000000 100644 0000000 39624a7 A glibc-RHEL-162901-1.patch
|
||||
:000000 100644 0000000 b31887c A glibc-RHEL-162901-2.patch
|
||||
:000000 100644 0000000 9294f79 A glibc-RHEL-162901-3.patch
|
||||
|
||||
commit 7fbc71a39a05131ddc4e61bd013acc2e34c62ca5
|
||||
Author: Martin Coufal <mcoufal@redhat.com>
|
||||
AuthorDate: Wed Apr 29 13:22:27 2026 +0000
|
||||
Commit: Martin Coufal <mcoufal@redhat.com>
|
||||
CommitDate: Thu Apr 30 10:13:36 2026 +0200
|
||||
|
||||
gating.yaml: mark power9 and power10 specific jobs as required
|
||||
|
||||
RPM-Changelog: -
|
||||
RPM-Skip-Release: yes
|
||||
|
||||
:100644 100644 a1e2d55 ba7f921 M gating.yaml
|
||||
|
||||
commit 6876da6c3cd740735f9227fa71494e3e72c91cdf
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
AuthorDate: Tue Mar 24 15:29:18 2026 +0100
|
||||
Commit: Frédéric Bérat <fberat@redhat.com>
|
||||
CommitDate: Thu Mar 26 16:10:21 2026 +0000
|
||||
|
||||
Fix namespace violation in fortify wrappers (bug 32052) (RHEL-52966)
|
||||
|
||||
Resolves: RHEL-52966
|
||||
|
||||
:000000 100644 0000000 52a65c1 A glibc-RHEL-52966.patch
|
||||
|
||||
commit d19518e588c4477fcde9374ec70350a1bc382c0b
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
AuthorDate: Tue Mar 24 14:18:52 2026 +0100
|
||||
Commit: Frédéric Bérat <fberat@redhat.com>
|
||||
CommitDate: Wed Mar 25 20:42:54 2026 +0000
|
||||
|
||||
Fix null pointer dereference and assertion failures in __nss_database_get (bug 28940) (RHEL-150269)
|
||||
|
||||
Resolves: RHEL-150269
|
||||
|
||||
:000000 100644 0000000 0eda8a7 A glibc-RHEL-150269-1.patch
|
||||
:000000 100644 0000000 3925565 A glibc-RHEL-150269-2.patch
|
||||
:000000 100644 0000000 7c99f3d A glibc-RHEL-150269-3.patch
|
||||
:000000 100644 0000000 f811d42 A glibc-RHEL-150269-4.patch
|
||||
|
||||
commit 0e8e4ecae9fa126d2cea194d09042c554bdc420c
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
AuthorDate: Tue Mar 24 11:01:32 2026 +0100
|
||||
Commit: Frédéric Bérat <fberat@redhat.com>
|
||||
CommitDate: Wed Mar 25 12:30:41 2026 +0000
|
||||
|
||||
Add LD_DEBUG=tls support for tracking TLS and TCB events (RHEL-49785)
|
||||
|
||||
Resolves: RHEL-49785
|
||||
|
||||
:000000 100644 0000000 b9a8d92 A glibc-RHEL-49785-1.patch
|
||||
:000000 100644 0000000 312faf7 A glibc-RHEL-49785-2.patch
|
||||
:000000 100644 0000000 3969165 A glibc-RHEL-49785-3.patch
|
||||
:000000 100644 0000000 6ee9ef6 A glibc-RHEL-49785-4.patch
|
||||
:000000 100644 0000000 be0b0eb A glibc-RHEL-49785-5.patch
|
||||
:000000 100644 0000000 e109ac5 A glibc-RHEL-49785-6.patch
|
||||
|
||||
commit d58e05d599e91bf2d7597da217208b2ef4c92fc1
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
AuthorDate: Mon Mar 23 16:53:51 2026 +0100
|
||||
Commit: Florian Weimer <fweimer@redhat.com>
|
||||
CommitDate: Mon Mar 23 16:53:51 2026 +0100
|
||||
|
||||
Avoid duplicate DNS query if search list contains '.'
|
||||
|
||||
Resolves: RHEL-153056
|
||||
|
||||
:000000 100644 0000000 bf93cf7 A glibc-RHEL-153056-1.patch
|
||||
:000000 100644 0000000 df43536 A glibc-RHEL-153056-2.patch
|
||||
:000000 100644 0000000 ed5efd8 A glibc-RHEL-153056-3.patch
|
||||
|
||||
commit 6a5da8faa95148af5ace04cd63a9e11686b61d12
|
||||
Author: Arjun Shankar <arjun@redhat.com>
|
||||
AuthorDate: Tue Mar 17 12:39:23 2026 +0100
|
||||
Commit: Arjun Shankar <arjun@redhat.com>
|
||||
CommitDate: Tue Mar 17 12:39:23 2026 +0100
|
||||
|
||||
dlfcn: Add dlinfo request type RTLD_DI_ORIGIN_PATH (RHEL-54450)
|
||||
|
||||
Resolves: RHEL-54450
|
||||
|
||||
:000000 100644 0000000 ab7c187 A glibc-RHEL-54450.patch
|
||||
|
||||
commit 7bff59bb7c59d40d81878bbe411782c7e393b538
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
AuthorDate: Mon Mar 2 20:38:08 2026 +0100
|
||||
Commit: Sergey Kolosov <skolosov@redhat.com>
|
||||
CommitDate: Mon Mar 9 08:59:24 2026 +0000
|
||||
|
||||
CI Gating: update gating.yaml for taskrpm deprecation
|
||||
|
||||
Replace the deprecated baseos-ci.brew-build.tier1.functional rule with
|
||||
fast-line and slow-line rules for tier0, tier1 and testsuite tests.
|
||||
|
||||
Related: RHEL-126175
|
||||
RPM-Changelog: -
|
||||
RPM-Skip-Release: yes
|
||||
|
||||
:100644 100644 07eeedb a1e2d55 M gating.yaml
|
||||
|
||||
commit e2834b00283401e1a1cb8c6a1768b2c2fdaa7836
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
AuthorDate: Tue Feb 24 09:51:00 2026 +0100
|
||||
Commit: Sergey Kolosov <skolosov@redhat.com>
|
||||
CommitDate: Mon Mar 2 19:10:44 2026 +0100
|
||||
|
||||
CI Tests: remove conflicting glibc32 to fix prepare stage
|
||||
|
||||
RPM-Changelog: -
|
||||
RPM-Skip-Release: yes
|
||||
|
||||
:100644 100644 7249575 7749a2d M plans/ci.fmf
|
||||
|
||||
commit ca2c60812dc5d34b77f94382c7340dbdf0ca2748
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
AuthorDate: Mon Feb 23 21:36:01 2026 +0100
|
||||
Commit: Sergey Kolosov <skolosov@redhat.com>
|
||||
CommitDate: Mon Mar 2 19:10:44 2026 +0100
|
||||
|
||||
CI Tests: add Regression/bz1882466-RHEL8-2-LD-PRELOAD-of-some-lib-that-has
|
||||
|
||||
This test was originally missing during the import from Fedora test
|
||||
plan.
|
||||
|
||||
RPM-Changelog: -
|
||||
RPM-Skip-Release: yes
|
||||
|
||||
:000000 100644 0000000 2852f58 A tests/Regression/bz1882466-RHEL8-2-LD-PRELOAD-of-some-lib-that-has/Makefile
|
||||
:000000 100644 0000000 020631c A tests/Regression/bz1882466-RHEL8-2-LD-PRELOAD-of-some-lib-that-has/PURPOSE
|
||||
:000000 100644 0000000 45d1371 A tests/Regression/bz1882466-RHEL8-2-LD-PRELOAD-of-some-lib-that-has/main.fmf
|
||||
:000000 100755 0000000 d36bb2d A tests/Regression/bz1882466-RHEL8-2-LD-PRELOAD-of-some-lib-that-has/runtest.sh
|
||||
:000000 100644 0000000 b8a08ec A tests/Regression/bz1882466-RHEL8-2-LD-PRELOAD-of-some-lib-that-has/testlib.cc
|
||||
|
||||
commit 1d7a0617ff0c43317425ee2a5b7379c7e2ef73ac
|
||||
Author: Patsy Griffin <patsy@redhat.com>
|
||||
AuthorDate: Mon Feb 23 18:22:41 2026 -0500
|
||||
Commit: Frédéric Bérat <fberat@redhat.com>
|
||||
CommitDate: Thu Feb 26 10:03:06 2026 +0000
|
||||
|
||||
Remove default value for LD_PROFILE_OUTPUT
|
||||
|
||||
Resolves: RHEL-142196
|
||||
|
||||
:000000 100644 0000000 fa52d55 A glibc-RHEL-142196-1.patch
|
||||
:000000 100644 0000000 f12aeb8 A glibc-RHEL-142196-2.patch
|
||||
:000000 100644 0000000 28567d2 A glibc-RHEL-142196-3.patch
|
||||
:000000 100644 0000000 e1a8ab7 A glibc-RHEL-142196-4.patch
|
||||
:000000 100644 0000000 84b027a A glibc-RHEL-142196-5.patch
|
||||
:000000 100644 0000000 68cdcff A glibc-RHEL-142196-6.patch
|
||||
:000000 100644 0000000 7997560 A glibc-RHEL-142196-7.patch
|
||||
:000000 100644 0000000 a999fc8 A glibc-RHEL-142196-8.patch
|
||||
|
||||
commit 8a9ddda3347d613915845ebc322ed2c38145b070
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
AuthorDate: Tue Feb 24 15:23:26 2026 +0100
|
||||
Commit: Frédéric Bérat <fberat@redhat.com>
|
||||
CommitDate: Tue Feb 24 15:23:26 2026 +0100
|
||||
|
||||
Fix race condition in io/tst-stat symlink test (RHEL-142209)
|
||||
|
||||
Resolves: RHEL-142209
|
||||
|
||||
:000000 100644 0000000 0b0cc99 A glibc-RHEL-142209.patch
|
||||
|
||||
commit a5df4f06f796a4c1f78aa9c8e06f4ca823431072
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
AuthorDate: Mon Feb 23 14:17:12 2026 +0100
|
||||
Commit: Frédéric Bérat <fberat@redhat.com>
|
||||
CommitDate: Mon Feb 23 14:17:12 2026 +0100
|
||||
|
||||
Restore iconv tool verbosity for unrecognized encoding names (RHEL-1018)
|
||||
|
||||
Resolves: RHEL-1018
|
||||
|
||||
:000000 100644 0000000 ffe3c50 A glibc-RHEL-1018.patch
|
||||
|
||||
commit 3b96603253e3faf6588dee6d8b20043566c6d5e4
|
||||
Author: Patsy Griffin <patsy@redhat.com>
|
||||
AuthorDate: Fri Feb 6 16:08:23 2026 -0500
|
||||
Commit: Florian Weimer <fweimer@redhat.com>
|
||||
CommitDate: Mon Feb 16 07:43:17 2026 +0000
|
||||
|
||||
Optimize trylock for high cache contention workloads.
|
||||
|
||||
Resolves: RHEL-141072
|
||||
|
||||
:000000 100644 0000000 496a62f A glibc-RHEL-141072.patch
|
||||
|
||||
commit c7f278779ca2b29a5524121252ab11f051cfb8bb
|
||||
Author: Patsy Griffin <patsy@redhat.com>
|
||||
AuthorDate: Tue Feb 10 18:53:05 2026 -0500
|
||||
Commit: Florian Weimer <fweimer@redhat.com>
|
||||
CommitDate: Fri Feb 13 15:27:36 2026 +0000
|
||||
|
||||
Update locales for Croatia to use EUR as currency symbol
|
||||
|
||||
Resolves: RHEL-140105
|
||||
|
||||
:000000 100644 0000000 1b763ae A glibc-RHEL-140105.patch
|
||||
|
||||
commit 426ad63b6259338de1b2083c57dab64d16b06bb0
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
AuthorDate: Thu Feb 12 20:37:12 2026 +0100
|
||||
Commit: Florian Weimer <fweimer@redhat.com>
|
||||
CommitDate: Fri Feb 13 15:21:49 2026 +0000
|
||||
|
||||
CI Tests: enable Regression/bz2115831-glibc-missing-gnu-debuglink-section-in
|
||||
|
||||
Re-enable this test as RHEL-27851 has been fixed
|
||||
|
||||
Related: RHEL-27851
|
||||
RPM-Changelog: -
|
||||
RPM-Skip-Release: yes
|
||||
|
||||
:100644 100644 4a3341c 36de426 M tests/Regression/bz2115831-glibc-missing-gnu-debuglink-section-in/main.fmf
|
||||
|
||||
commit eae38d8010e461f8f0d4a9ec27080eb89bc2e6fe
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
AuthorDate: Thu Feb 12 15:17:05 2026 +0100
|
||||
|
||||
@ -1844,7 +1844,7 @@ build build-%{target}-32 \
|
||||
# Default set of compiler options.
|
||||
build build-%{target} \
|
||||
CC="gcc $glibc_flags_cc $glibc_flags_cc_main" \
|
||||
CXX="gcc $glibc_flags_cc $glibc_flags_cc_main" \
|
||||
CXX="g++ $glibc_flags_cc $glibc_flags_cc_main" \
|
||||
CFLAGS="$glibc_flags_cflags" \
|
||||
%{?glibc_rtld_early_cflags:--with-rtld-early-cflags=%glibc_rtld_early_cflags} \
|
||||
%ifarch x86_64
|
||||
@ -1902,6 +1902,15 @@ rm -rf etc var usr/bin usr/lib/gconv usr/libexec usr/sbin usr/share
|
||||
rm -f lib/libnss_db* lib/libnss_hesiod* lib/libnsl* usr/lib/libnsl* usr/lib/libnss*
|
||||
rm usr/lib/libc_malloc_debug.so
|
||||
strip -g usr/lib/*.o
|
||||
for f in usr/lib/*.so; do
|
||||
case "$f" in
|
||||
# libc.so is a text file, not an object
|
||||
usr/lib/libc.so ) ;;
|
||||
* ) strip $f ;;
|
||||
esac
|
||||
done
|
||||
strip usr/lib/*.so.?
|
||||
strip usr/lib/audit/*.so
|
||||
popd
|
||||
%endif
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user