diff --git a/SOURCES/glibc-RHEL-1017-1.patch b/SOURCES/glibc-RHEL-1017-1.patch new file mode 100644 index 0000000..3db69a3 --- /dev/null +++ b/SOURCES/glibc-RHEL-1017-1.patch @@ -0,0 +1,432 @@ +From e4ca6de1bc5e4ba3f94cf0c501a293c5bc827b10 Mon Sep 17 00:00:00 2001 +From: Anton Blanchard +Date: Tue, 27 Jul 2021 15:47:49 +1000 +Subject: powerpc64: Replace some PPC_FEATURE_HAS_VSX with + PPC_FEATURE_ARCH_2_06 + +We use PPC_FEATURE_HAS_VSX to select a number of POWER7 optimised +functions. These functions don't use any VSX instructions, so +PPC_FEATURE_ARCH_2_06 seems like a better fit. + +Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 0acdf22ba3..32564c8f1f 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -95,7 +95,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + #endif + IFUNC_IMPL_ADD (array, i, memset, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __memset_power8) +- IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_ARCH_2_06, + __memset_power7) + IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_ARCH_2_05, + __memset_power6) +@@ -139,7 +139,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + #endif + IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strlen_power8) +- IFUNC_IMPL_ADD (array, i, strlen, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, strlen, hwcap & PPC_FEATURE_ARCH_2_06, + __strlen_power7) + IFUNC_IMPL_ADD (array, i, strlen, 1, + __strlen_ppc)) +@@ -152,7 +152,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + #endif + IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strncmp_power8) +- IFUNC_IMPL_ADD (array, i, strncmp, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, strncmp, hwcap & PPC_FEATURE_ARCH_2_06, + __strncmp_power7) + IFUNC_IMPL_ADD (array, i, strncmp, hwcap & PPC_FEATURE_POWER4, + __strncmp_power4) +@@ -165,7 +165,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strchr_power8) + IFUNC_IMPL_ADD (array, i, strchr, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strchr_power7) + IFUNC_IMPL_ADD (array, i, strchr, 1, + __strchr_ppc)) +@@ -176,7 +176,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strchrnul_power8) + IFUNC_IMPL_ADD (array, i, strchrnul, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strchrnul_power7) + IFUNC_IMPL_ADD (array, i, strchrnul, 1, + __strchrnul_ppc)) +@@ -192,7 +192,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + #endif + IFUNC_IMPL_ADD (array, i, memcmp, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __memcmp_power8) +- IFUNC_IMPL_ADD (array, i, memcmp, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, memcmp, hwcap & PPC_FEATURE_ARCH_2_06, + __memcmp_power7) + IFUNC_IMPL_ADD (array, i, memcmp, hwcap & PPC_FEATURE_POWER4, + __memcmp_power4) +@@ -244,7 +244,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __memchr_power8) + IFUNC_IMPL_ADD (array, i, memchr, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __memchr_power7) + IFUNC_IMPL_ADD (array, i, memchr, 1, + __memchr_ppc)) +@@ -255,7 +255,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __memrchr_power8) + IFUNC_IMPL_ADD (array, i, memrchr, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __memrchr_power7) + IFUNC_IMPL_ADD (array, i, memrchr, 1, + __memrchr_ppc)) +@@ -272,7 +272,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __rawmemchr_power9) + #endif + IFUNC_IMPL_ADD (array, i, rawmemchr, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __rawmemchr_power7) + IFUNC_IMPL_ADD (array, i, rawmemchr, 1, + __rawmemchr_ppc)) +@@ -282,7 +282,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, strnlen, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strnlen_power8) +- IFUNC_IMPL_ADD (array, i, strnlen, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, strnlen, hwcap & PPC_FEATURE_ARCH_2_06, + __strnlen_power7) + IFUNC_IMPL_ADD (array, i, strnlen, 1, + __strnlen_ppc)) +@@ -293,14 +293,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strcasecmp_power8) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strcasecmp_power7) + IFUNC_IMPL_ADD (array, i, strcasecmp, 1, __strcasecmp_ppc)) + + /* Support sysdeps/powerpc/powerpc64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp_l, + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strcasecmp_l_power7) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, 1, + __strcasecmp_l_ppc)) +@@ -311,14 +311,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strncasecmp_power8) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strncasecmp_power7) + IFUNC_IMPL_ADD (array, i, strncasecmp, 1, __strncasecmp_ppc)) + + /* Support sysdeps/powerpc/powerpc64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp_l, + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strncasecmp_l_power7) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, 1, + __strncasecmp_l_ppc)) +@@ -329,7 +329,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strrchr_power8) + IFUNC_IMPL_ADD (array, i, strrchr, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strrchr_power7) + IFUNC_IMPL_ADD (array, i, strrchr, 1, + __strrchr_ppc)) +@@ -357,7 +357,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strncpy_power8) + IFUNC_IMPL_ADD (array, i, strncpy, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strncpy_power7) + IFUNC_IMPL_ADD (array, i, strncpy, 1, + __strncpy_ppc)) +@@ -374,7 +374,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __stpncpy_power8) + IFUNC_IMPL_ADD (array, i, stpncpy, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __stpncpy_power7) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, + __stpncpy_ppc)) +@@ -390,7 +390,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strcmp_power8) + IFUNC_IMPL_ADD (array, i, strcmp, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strcmp_power7) + IFUNC_IMPL_ADD (array, i, strcmp, 1, + __strcmp_ppc)) +@@ -425,7 +425,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strstr.c. */ + IFUNC_IMPL (i, name, strstr, + IFUNC_IMPL_ADD (array, i, strstr, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06, + __strstr_power7) + IFUNC_IMPL_ADD (array, i, strstr, 1, + __strstr_ppc)) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memchr.c b/sysdeps/powerpc/powerpc64/multiarch/memchr.c +index 0c718d4f15..c24186689e 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memchr.c +@@ -30,7 +30,7 @@ extern __typeof (__memchr) __memchr_power8 attribute_hidden; + libc_ifunc (__memchr, + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __memchr_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __memchr_power7 + : __memchr_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c +index 4fd089aba7..99559bce26 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c +@@ -40,7 +40,7 @@ libc_ifunc_redirected (__redirect_memcmp, memcmp, + #endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __memcmp_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __memcmp_power7 + : (hwcap & PPC_FEATURE_POWER4) + ? __memcmp_power4 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memrchr.c b/sysdeps/powerpc/powerpc64/multiarch/memrchr.c +index e06d6468b8..16bb6f0042 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memrchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memrchr.c +@@ -30,7 +30,7 @@ extern __typeof (__memrchr) __memrchr_power8 attribute_hidden; + libc_ifunc (__memrchr, + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __memrchr_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __memrchr_power7 + : __memrchr_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memset.c b/sysdeps/powerpc/powerpc64/multiarch/memset.c +index 5994bf02e6..c1aa143f60 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memset.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memset.c +@@ -48,7 +48,7 @@ libc_ifunc (__libc_memset, + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __memset_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __memset_power7 : + (hwcap & PPC_FEATURE_ARCH_2_05) + ? __memset_power6 : +diff --git a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c +index c0ffea2b93..b5d2d3a635 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c +@@ -41,7 +41,7 @@ libc_ifunc_redirected (__redirect___rawmemchr, __rawmemchr, + (hwcap2 & PPC_FEATURE2_ARCH_3_00) + ? __rawmemchr_power9 : + # endif +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __rawmemchr_power7 + : __rawmemchr_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c b/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c +index bebd377fd9..e7035761a7 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c +@@ -40,7 +40,7 @@ libc_ifunc_redirected (__redirect___stpncpy, __stpncpy, + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __stpncpy_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) ++ : (hwcap & PPC_FEATURE_ARCH_2_06) + ? __stpncpy_power7 + : __stpncpy_ppc); + weak_alias (__stpncpy, stpncpy) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c b/sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c +index dcd7774403..55ca6c85c4 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c +@@ -29,7 +29,7 @@ extern __typeof (__strcasecmp) __strcasecmp_power8 attribute_hidden; + libc_ifunc (__libc_strcasecmp, + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strcasecmp_power8: +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strcasecmp_power7 + : __strcasecmp_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcasecmp_l.c b/sysdeps/powerpc/powerpc64/multiarch/strcasecmp_l.c +index 96a70b8b11..1afee5d7fd 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcasecmp_l.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcasecmp_l.c +@@ -32,7 +32,7 @@ extern __typeof (__strcasecmp_l) __strcasecmp_l_power7 attribute_hidden; + + extern __typeof (__strcasecmp_l) __libc_strcasecmp_l; + libc_ifunc (__libc_strcasecmp_l, +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strcasecmp_l_power7 + : __strcasecmp_l_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strchr.c b/sysdeps/powerpc/powerpc64/multiarch/strchr.c +index ea9ac1134f..27c794c6b7 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strchr.c +@@ -35,7 +35,7 @@ extern __typeof (strchr) __strchr_power8 attribute_hidden; + libc_ifunc_redirected (__redirect_strchr, strchr, + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strchr_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strchr_power7 + : __strchr_ppc); + weak_alias (strchr, index) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strchrnul.c b/sysdeps/powerpc/powerpc64/multiarch/strchrnul.c +index 4688e7c3f0..4a07b4a242 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strchrnul.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strchrnul.c +@@ -30,7 +30,7 @@ extern __typeof (__strchrnul) __strchrnul_power8 attribute_hidden; + libc_ifunc (__strchrnul, + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strchrnul_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strchrnul_power7 + : __strchrnul_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c +index 72f9a639bf..4b0b25fff6 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c +@@ -40,7 +40,7 @@ libc_ifunc_redirected (__redirect_strcmp, strcmp, + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strcmp_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) ++ : (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strcmp_power7 + : __strcmp_ppc); + #endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strlen.c b/sysdeps/powerpc/powerpc64/multiarch/strlen.c +index 109c8a90bd..0cd1c6faff 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strlen.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strlen.c +@@ -42,7 +42,7 @@ libc_ifunc (__libc_strlen, + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strlen_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strlen_power7 + : __strlen_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncase.c b/sysdeps/powerpc/powerpc64/multiarch/strncase.c +index 2013a5d75a..644046bd74 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncase.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncase.c +@@ -29,7 +29,7 @@ extern __typeof (__strncasecmp) __strncasecmp_power8 attribute_hidden; + libc_ifunc (__libc_strncasecmp, + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strncasecmp_power8: +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strncasecmp_power7 + : __strncasecmp_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncase_l.c b/sysdeps/powerpc/powerpc64/multiarch/strncase_l.c +index cad6da302d..d2d761af72 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncase_l.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncase_l.c +@@ -34,7 +34,7 @@ extern __typeof (__strncasecmp_l) __strncasecmp_l_power7 attribute_hidden; + ifunc symbol properly. */ + extern __typeof (__strncasecmp_l) __libc_strncasecmp_l; + libc_ifunc (__libc_strncasecmp_l, +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strncasecmp_l_power7 + : __strncasecmp_l_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +index eef524ddfb..1f689e5c05 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +@@ -43,7 +43,7 @@ libc_ifunc_redirected (__redirect_strncmp, strncmp, + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strncmp_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) ++ : (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strncmp_power7 + : (hwcap & PPC_FEATURE_POWER4) + ? __strncmp_power4 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncpy.c b/sysdeps/powerpc/powerpc64/multiarch/strncpy.c +index 7da9def358..d4d3463bd1 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncpy.c +@@ -43,7 +43,7 @@ libc_ifunc_redirected (__redirect_strncpy, strncpy, + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strncpy_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) ++ : (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strncpy_power7 + : __strncpy_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strnlen.c b/sysdeps/powerpc/powerpc64/multiarch/strnlen.c +index 264b7a752d..baf375a75a 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strnlen.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strnlen.c +@@ -31,7 +31,7 @@ extern __typeof (__strnlen) __strnlen_power8 attribute_hidden; + libc_ifunc_redirected (__redirect___strnlen, __strnlen, + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strnlen_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strnlen_power7 + : __strnlen_ppc); + weak_alias (__strnlen, strnlen) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strrchr.c b/sysdeps/powerpc/powerpc64/multiarch/strrchr.c +index bb06b93d19..1c9eea1817 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strrchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strrchr.c +@@ -33,7 +33,7 @@ extern __typeof (strrchr) __strrchr_power8 attribute_hidden; + libc_ifunc_redirected (__redirect_strrchr, strrchr, + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strrchr_power8 : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strrchr_power7 + : __strrchr_ppc); + weak_alias (strrchr, rindex) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strstr.c b/sysdeps/powerpc/powerpc64/multiarch/strstr.c +index bb0588844e..6582798dda 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strstr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strstr.c +@@ -30,7 +30,7 @@ extern __typeof (strstr) __strstr_power7 attribute_hidden; + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect_strstr, strstr, +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strstr_power7 + : __strstr_ppc); + #endif diff --git a/SOURCES/glibc-RHEL-1017-2.patch b/SOURCES/glibc-RHEL-1017-2.patch new file mode 100644 index 0000000..ef94f5b --- /dev/null +++ b/SOURCES/glibc-RHEL-1017-2.patch @@ -0,0 +1,83 @@ +From f2a15dd668913c5a1388ba7e1131b25162b2ea75 Mon Sep 17 00:00:00 2001 +From: Anton Blanchard +Date: Tue, 27 Jul 2021 15:47:50 +1000 +Subject: powerpc64: Check cacheline size before using optimised memset + routines + +A number of optimised memset routines assume the cacheline size is 128B, +so we better check before using them. + +Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 32564c8f1f..a3fdcd43bd 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -35,6 +35,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + unsigned long int hwcap = GLRO(dl_hwcap); + unsigned long int hwcap2 = GLRO(dl_hwcap2); ++#ifdef SHARED ++ int cacheline_size = GLRO(dl_cache_line_size); ++#endif + + /* hwcap contains only the latest supported ISA, the code checks which is + and fills the previous supported ones. */ +@@ -90,16 +93,21 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, memset, + hwcap2 & PPC_FEATURE2_ARCH_3_1 + && hwcap2 & PPC_FEATURE2_HAS_ISEL +- && hwcap & PPC_FEATURE_HAS_VSX, ++ && hwcap & PPC_FEATURE_HAS_VSX ++ && cacheline_size == 128, + __memset_power10) + #endif +- IFUNC_IMPL_ADD (array, i, memset, hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ IFUNC_IMPL_ADD (array, i, memset, hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && cacheline_size == 128, + __memset_power8) +- IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_ARCH_2_06, ++ IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_ARCH_2_06 ++ && cacheline_size == 128, + __memset_power7) +- IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_ARCH_2_05, ++ IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_ARCH_2_05 ++ && cacheline_size == 128, + __memset_power6) +- IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_POWER4, ++ IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_POWER4 ++ && cacheline_size == 128, + __memset_power4) + IFUNC_IMPL_ADD (array, i, memset, 1, __memset_ppc)) + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memset.c b/sysdeps/powerpc/powerpc64/multiarch/memset.c +index c1aa143f60..056e911699 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memset.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memset.c +@@ -43,16 +43,21 @@ libc_ifunc (__libc_memset, + # ifdef __LITTLE_ENDIAN__ + (hwcap2 & PPC_FEATURE2_ARCH_3_1 + && hwcap2 & PPC_FEATURE2_HAS_ISEL +- && hwcap & PPC_FEATURE_HAS_VSX) ++ && hwcap & PPC_FEATURE_HAS_VSX ++ && GLRO(dl_cache_line_size) == 128) + ? __memset_power10 : + # endif +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && GLRO(dl_cache_line_size) == 128) + ? __memset_power8 : +- (hwcap & PPC_FEATURE_ARCH_2_06) ++ (hwcap & PPC_FEATURE_ARCH_2_06 ++ && GLRO(dl_cache_line_size) == 128) + ? __memset_power7 : +- (hwcap & PPC_FEATURE_ARCH_2_05) ++ (hwcap & PPC_FEATURE_ARCH_2_05 ++ && GLRO(dl_cache_line_size) == 128) + ? __memset_power6 : +- (hwcap & PPC_FEATURE_POWER4) ++ (hwcap & PPC_FEATURE_POWER4 ++ && GLRO(dl_cache_line_size) == 128) + ? __memset_power4 + : __memset_ppc); + diff --git a/SOURCES/glibc-RHEL-1017-3.patch b/SOURCES/glibc-RHEL-1017-3.patch new file mode 100644 index 0000000..1f06fde --- /dev/null +++ b/SOURCES/glibc-RHEL-1017-3.patch @@ -0,0 +1,703 @@ +From 60b4dd25790342b40e8942e3a4115f511a6b6911 Mon Sep 17 00:00:00 2001 +From: Anton Blanchard +Date: Tue, 27 Jul 2021 15:47:51 +1000 +Subject: powerpc64: Add checks for Altivec and VSX in ifunc selection + +We'd like to support processors without Altivec or VSX, so check +the relevant hwcap bits before selecting them. + +Reviewed-by: Tulio Magno Quites Machado Filho + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/bzero.c b/sysdeps/powerpc/powerpc64/multiarch/bzero.c +index 660d7dc686..c8ffbea01c 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/bzero.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/bzero.c +@@ -38,11 +38,13 @@ libc_ifunc (__bzero, + && hwcap & PPC_FEATURE_HAS_VSX) + ? __bzero_power10 : + # endif +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __bzero_power8 : + (hwcap & PPC_FEATURE_HAS_VSX) + ? __bzero_power7 : +- (hwcap & PPC_FEATURE_ARCH_2_05) ++ (hwcap & PPC_FEATURE_ARCH_2_05 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __bzero_power6 : + (hwcap & PPC_FEATURE_POWER4) + ? __bzero_power4 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index a3fdcd43bd..c3e25c5981 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -60,9 +60,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && hwcap & PPC_FEATURE_HAS_VSX, + __memcpy_power10) + #endif +- IFUNC_IMPL_ADD (array, i, memcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ IFUNC_IMPL_ADD (array, i, memcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __memcpy_power8_cached) +- IFUNC_IMPL_ADD (array, i, memcpy, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, memcpy, hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __memcpy_power7) + IFUNC_IMPL_ADD (array, i, memcpy, hwcap & PPC_FEATURE_ARCH_2_06, + __memcpy_a2) +@@ -83,7 +85,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && hwcap & PPC_FEATURE_HAS_VSX, + __memmove_power10) + #endif +- IFUNC_IMPL_ADD (array, i, memmove, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, memmove, hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __memmove_power7) + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_ppc)) + +@@ -98,6 +101,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __memset_power10) + #endif + IFUNC_IMPL_ADD (array, i, memset, hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC + && cacheline_size == 128, + __memset_power8) + IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_ARCH_2_06 +@@ -114,12 +118,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strcpy.c. */ + IFUNC_IMPL (i, name, strcpy, + #ifdef __LITTLE_ENDIAN__ +- IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strcpy_power9) + #endif +- IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strcpy_power8) +- IFUNC_IMPL_ADD (array, i, strcpy, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, strcpy, hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strcpy_power7) + IFUNC_IMPL_ADD (array, i, strcpy, 1, + __strcpy_ppc)) +@@ -127,12 +134,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/stpcpy.c. */ + IFUNC_IMPL (i, name, stpcpy, + #ifdef __LITTLE_ENDIAN__ +- IFUNC_IMPL_ADD (array, i, stpcpy, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ IFUNC_IMPL_ADD (array, i, stpcpy, hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __stpcpy_power9) + #endif +- IFUNC_IMPL_ADD (array, i, stpcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ IFUNC_IMPL_ADD (array, i, stpcpy, hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __stpcpy_power8) +- IFUNC_IMPL_ADD (array, i, stpcpy, hwcap & PPC_FEATURE_HAS_VSX, ++ IFUNC_IMPL_ADD (array, i, stpcpy, hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __stpcpy_power7) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, + __stpcpy_ppc)) +@@ -140,12 +150,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strlen.c. */ + IFUNC_IMPL (i, name, strlen, + #ifdef __LITTLE_ENDIAN__ +- IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_3_1, ++ IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strlen_power10) +- IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strlen_power9) + #endif +- IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strlen_power8) + IFUNC_IMPL_ADD (array, i, strlen, hwcap & PPC_FEATURE_ARCH_2_06, + __strlen_power7) +@@ -155,7 +168,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strncmp.c. */ + IFUNC_IMPL (i, name, strncmp, + #ifdef __LITTLE_ENDIAN__ +- IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strncmp_power9) + #endif + IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_2_07, +@@ -170,7 +184,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strchr.c. */ + IFUNC_IMPL (i, name, strchr, + IFUNC_IMPL_ADD (array, i, strchr, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strchr_power8) + IFUNC_IMPL_ADD (array, i, strchr, + hwcap & PPC_FEATURE_ARCH_2_06, +@@ -181,7 +196,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strchrnul.c. */ + IFUNC_IMPL (i, name, strchrnul, + IFUNC_IMPL_ADD (array, i, strchrnul, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strchrnul_power8) + IFUNC_IMPL_ADD (array, i, strchrnul, + hwcap & PPC_FEATURE_ARCH_2_06, +@@ -198,7 +214,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && hwcap & PPC_FEATURE_HAS_VSX, + __memcmp_power10) + #endif +- IFUNC_IMPL_ADD (array, i, memcmp, hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ IFUNC_IMPL_ADD (array, i, memcmp, hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __memcmp_power8) + IFUNC_IMPL_ADD (array, i, memcmp, hwcap & PPC_FEATURE_ARCH_2_06, + __memcmp_power7) +@@ -215,11 +232,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && hwcap & PPC_FEATURE_HAS_VSX, + __bzero_power10) + #endif +- IFUNC_IMPL_ADD (array, i, bzero, hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ IFUNC_IMPL_ADD (array, i, bzero, hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __bzero_power8) + IFUNC_IMPL_ADD (array, i, bzero, hwcap & PPC_FEATURE_HAS_VSX, + __bzero_power7) +- IFUNC_IMPL_ADD (array, i, bzero, hwcap & PPC_FEATURE_ARCH_2_05, ++ IFUNC_IMPL_ADD (array, i, bzero, hwcap & PPC_FEATURE_ARCH_2_05 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __bzero_power6) + IFUNC_IMPL_ADD (array, i, bzero, hwcap & PPC_FEATURE_POWER4, + __bzero_power4) +@@ -241,7 +260,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/mempcpy.c. */ + IFUNC_IMPL (i, name, mempcpy, + IFUNC_IMPL_ADD (array, i, mempcpy, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __mempcpy_power7) + IFUNC_IMPL_ADD (array, i, mempcpy, 1, + __mempcpy_ppc)) +@@ -249,7 +269,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/memchr.c. */ + IFUNC_IMPL (i, name, memchr, + IFUNC_IMPL_ADD (array, i, memchr, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __memchr_power8) + IFUNC_IMPL_ADD (array, i, memchr, + hwcap & PPC_FEATURE_ARCH_2_06, +@@ -260,7 +281,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/memrchr.c. */ + IFUNC_IMPL (i, name, memrchr, + IFUNC_IMPL_ADD (array, i, memrchr, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __memrchr_power8) + IFUNC_IMPL_ADD (array, i, memrchr, + hwcap & PPC_FEATURE_ARCH_2_06, +@@ -276,7 +298,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && (hwcap & PPC_FEATURE_HAS_VSX), + __rawmemchr_power10) + IFUNC_IMPL_ADD (array, i, rawmemchr, +- hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __rawmemchr_power9) + #endif + IFUNC_IMPL_ADD (array, i, rawmemchr, +@@ -288,7 +311,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strnlen.c. */ + IFUNC_IMPL (i, name, strnlen, + IFUNC_IMPL_ADD (array, i, strnlen, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strnlen_power8) + IFUNC_IMPL_ADD (array, i, strnlen, hwcap & PPC_FEATURE_ARCH_2_06, + __strnlen_power7) +@@ -298,7 +322,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c. */ + IFUNC_IMPL (i, name, strcasecmp, + IFUNC_IMPL_ADD (array, i, strcasecmp, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strcasecmp_power8) + IFUNC_IMPL_ADD (array, i, strcasecmp, + hwcap & PPC_FEATURE_ARCH_2_06, +@@ -316,7 +341,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strncase.c. */ + IFUNC_IMPL (i, name, strncasecmp, + IFUNC_IMPL_ADD (array, i, strncasecmp, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strncasecmp_power8) + IFUNC_IMPL_ADD (array, i, strncasecmp, + hwcap & PPC_FEATURE_ARCH_2_06, +@@ -334,7 +360,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strrchr.c. */ + IFUNC_IMPL (i, name, strrchr, + IFUNC_IMPL_ADD (array, i, strrchr, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strrchr_power8) + IFUNC_IMPL_ADD (array, i, strrchr, + hwcap & PPC_FEATURE_ARCH_2_06, +@@ -345,10 +372,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strncat.c. */ + IFUNC_IMPL (i, name, strncat, + IFUNC_IMPL_ADD (array, i, strncat, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strncat_power8) + IFUNC_IMPL_ADD (array, i, strncat, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strncat_power7) + IFUNC_IMPL_ADD (array, i, strncat, 1, + __strncat_ppc)) +@@ -391,7 +420,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcmp, + #ifdef __LITTLE_ENDIAN__ + IFUNC_IMPL_ADD (array, i, strcmp, +- hwcap2 & PPC_FEATURE2_ARCH_3_00, ++ hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strcmp_power9) + #endif + IFUNC_IMPL_ADD (array, i, strcmp, +@@ -406,10 +436,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strcat.c. */ + IFUNC_IMPL (i, name, strcat, + IFUNC_IMPL_ADD (array, i, strcat, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strcat_power8) + IFUNC_IMPL_ADD (array, i, strcat, +- hwcap & PPC_FEATURE_HAS_VSX, ++ hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strcat_power7) + IFUNC_IMPL_ADD (array, i, strcat, 1, + __strcat_ppc)) +@@ -417,7 +449,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strspn.c. */ + IFUNC_IMPL (i, name, strspn, + IFUNC_IMPL_ADD (array, i, strspn, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strspn_power8) + IFUNC_IMPL_ADD (array, i, strspn, 1, + __strspn_ppc)) +@@ -425,7 +458,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strcspn.c. */ + IFUNC_IMPL (i, name, strcspn, + IFUNC_IMPL_ADD (array, i, strcspn, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_VSX, + __strcspn_power8) + IFUNC_IMPL_ADD (array, i, strcspn, 1, + __strcspn_ppc)) +@@ -442,7 +476,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/powerpc/powerpc64/multiarch/strcasestr.c. */ + IFUNC_IMPL (i, name, strcasestr, + IFUNC_IMPL_ADD (array, i, strcasestr, +- hwcap2 & PPC_FEATURE2_ARCH_2_07, ++ hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC, + __strcasestr_power8) + IFUNC_IMPL_ADD (array, i, strcasestr, 1, + __strcasestr_ppc)) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memchr.c b/sysdeps/powerpc/powerpc64/multiarch/memchr.c +index c24186689e..f40013e061 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memchr.c +@@ -28,7 +28,8 @@ extern __typeof (__memchr) __memchr_power8 attribute_hidden; + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc (__memchr, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __memchr_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __memchr_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c +index 99559bce26..89b56c103b 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c +@@ -38,7 +38,8 @@ libc_ifunc_redirected (__redirect_memcmp, memcmp, + && hwcap & PPC_FEATURE_HAS_VSX) + ? __memcmp_power10 : + #endif +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __memcmp_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __memcmp_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcpy.c b/sysdeps/powerpc/powerpc64/multiarch/memcpy.c +index 53ab32ef26..684ee064f2 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memcpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memcpy.c +@@ -45,9 +45,12 @@ libc_ifunc (__libc_memcpy, + (hwcap2 & PPC_FEATURE2_ARCH_3_1 && hwcap & PPC_FEATURE_HAS_VSX) + ? __memcpy_power10 : + # endif +- ((hwcap2 & PPC_FEATURE2_ARCH_2_07) && use_cached_memopt) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC ++ && use_cached_memopt) + ? __memcpy_power8_cached : +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __memcpy_power7 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __memcpy_a2 : +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memmove.c b/sysdeps/powerpc/powerpc64/multiarch/memmove.c +index 637b2cbf7f..50253b4554 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memmove.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memmove.c +@@ -41,7 +41,8 @@ libc_ifunc (__libc_memmove, + && hwcap & PPC_FEATURE_HAS_VSX) + ? __memmove_power10 : + #endif +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __memmove_power7 + : __memmove_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/mempcpy.c b/sysdeps/powerpc/powerpc64/multiarch/mempcpy.c +index b37e0f35b5..563095a5ec 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/mempcpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/mempcpy.c +@@ -33,7 +33,8 @@ extern __typeof (__mempcpy) __mempcpy_power7 attribute_hidden; + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect___mempcpy, __mempcpy, +- (hwcap & PPC_FEATURE_HAS_VSX) ++ (hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __mempcpy_power7 + : __mempcpy_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memrchr.c b/sysdeps/powerpc/powerpc64/multiarch/memrchr.c +index 16bb6f0042..a8b985b06a 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memrchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memrchr.c +@@ -28,7 +28,8 @@ extern __typeof (__memrchr) __memrchr_power8 attribute_hidden; + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc (__memrchr, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __memrchr_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __memrchr_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/memset.c b/sysdeps/powerpc/powerpc64/multiarch/memset.c +index 056e911699..a2bc223bcc 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/memset.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/memset.c +@@ -48,6 +48,7 @@ libc_ifunc (__libc_memset, + ? __memset_power10 : + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC + && GLRO(dl_cache_line_size) == 128) + ? __memset_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c +index b5d2d3a635..43eb459e02 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c +@@ -38,7 +38,8 @@ libc_ifunc_redirected (__redirect___rawmemchr, __rawmemchr, + (hwcap2 & PPC_FEATURE2_ARCH_3_1) + && (hwcap & PPC_FEATURE_HAS_VSX) + ? __rawmemchr_power10 : +- (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __rawmemchr_power9 : + # endif + (hwcap & PPC_FEATURE_ARCH_2_06) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c b/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c +index d4eb4285fc..5be413405e 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c +@@ -32,12 +32,15 @@ extern __typeof (__stpcpy) __stpcpy_power9 attribute_hidden; + + libc_ifunc_hidden (__stpcpy, __stpcpy, + # ifdef __LITTLE_ENDIAN__ +- (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __stpcpy_power9 : + # endif +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __stpcpy_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) ++ : (hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __stpcpy_power7 + : __stpcpy_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c b/sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c +index 55ca6c85c4..21ce2d279b 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcasecmp.c +@@ -27,7 +27,8 @@ extern __typeof (__strcasecmp) __strcasecmp_power7 attribute_hidden; + extern __typeof (__strcasecmp) __strcasecmp_power8 attribute_hidden; + + libc_ifunc (__libc_strcasecmp, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strcasecmp_power8: + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strcasecmp_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcasestr.c b/sysdeps/powerpc/powerpc64/multiarch/strcasestr.c +index 7e4bd3b5ac..5bb3016022 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcasestr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcasestr.c +@@ -27,7 +27,8 @@ extern __typeof (__strcasestr) __strcasestr_power8 attribute_hidden; + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc (__strcasestr, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strcasestr_power8 + : __strcasestr_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcat.c b/sysdeps/powerpc/powerpc64/multiarch/strcat.c +index 6d342324c4..d8d9870824 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcat.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcat.c +@@ -28,9 +28,11 @@ extern __typeof (strcat) __strcat_power8 attribute_hidden; + # undef strcat + + libc_ifunc_redirected (__redirect_strcat, strcat, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strcat_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) ++ : (hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strcat_power7 + : __strcat_ppc); + #endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strchr.c b/sysdeps/powerpc/powerpc64/multiarch/strchr.c +index 27c794c6b7..62b202baf9 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strchr.c +@@ -33,7 +33,8 @@ extern __typeof (strchr) __strchr_power8 attribute_hidden; + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect_strchr, strchr, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strchr_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strchr_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strchrnul.c b/sysdeps/powerpc/powerpc64/multiarch/strchrnul.c +index 4a07b4a242..40e529b9d9 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strchrnul.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strchrnul.c +@@ -28,7 +28,8 @@ extern __typeof (__strchrnul) __strchrnul_power8 attribute_hidden; + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc (__strchrnul, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strchrnul_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strchrnul_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c +index 4b0b25fff6..8132682a99 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c +@@ -35,7 +35,8 @@ extern __typeof (strcmp) __strcmp_power9 attribute_hidden; + + libc_ifunc_redirected (__redirect_strcmp, strcmp, + # ifdef __LITTLE_ENDIAN__ +- (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strcmp_power9 : + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcpy.c b/sysdeps/powerpc/powerpc64/multiarch/strcpy.c +index b733fa5a23..5af1d45cc1 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcpy.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcpy.c +@@ -32,12 +32,15 @@ extern __typeof (strcpy) __strcpy_power9 attribute_hidden; + + libc_ifunc_redirected (__redirect_strcpy, strcpy, + # ifdef __LITTLE_ENDIAN__ +- (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strcpy_power9 : + # endif +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strcpy_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) ++ : (hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strcpy_power7 + : __strcpy_ppc); + #endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcspn.c b/sysdeps/powerpc/powerpc64/multiarch/strcspn.c +index 683aa104d7..8ba01c13b1 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strcspn.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strcspn.c +@@ -27,7 +27,8 @@ extern __typeof (strcspn) __strcspn_ppc attribute_hidden; + extern __typeof (strcspn) __strcspn_power8 attribute_hidden; + + libc_ifunc (__libc_strcspn, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strcspn_power8 + : __strcspn_ppc); + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strlen.c b/sysdeps/powerpc/powerpc64/multiarch/strlen.c +index 0cd1c6faff..f1e28414e0 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strlen.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strlen.c +@@ -35,12 +35,15 @@ extern __typeof (__redirect_strlen) __strlen_power10 attribute_hidden; + + libc_ifunc (__libc_strlen, + # ifdef __LITTLE_ENDIAN__ +- (hwcap2 & PPC_FEATURE2_ARCH_3_1) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_1 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strlen_power10 : +- (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strlen_power9 : + # endif +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strlen_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strlen_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncase.c b/sysdeps/powerpc/powerpc64/multiarch/strncase.c +index 644046bd74..2802cf2c3f 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncase.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncase.c +@@ -27,7 +27,8 @@ extern __typeof (__strncasecmp) __strncasecmp_power7 attribute_hidden; + extern __typeof (__strncasecmp) __strncasecmp_power8 attribute_hidden; + + libc_ifunc (__libc_strncasecmp, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strncasecmp_power8: + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strncasecmp_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncat.c b/sysdeps/powerpc/powerpc64/multiarch/strncat.c +index 0036fca91a..9ea294a72d 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncat.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncat.c +@@ -26,9 +26,11 @@ extern __typeof (strncat) __strncat_power7 attribute_hidden; + extern __typeof (strncat) __strncat_power8 attribute_hidden; + + libc_ifunc (strncat, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strncat_power8 +- : (hwcap & PPC_FEATURE_HAS_VSX) ++ : (hwcap & PPC_FEATURE_ARCH_2_06 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strncat_power7 + : __strncat_ppc); + #endif +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +index 1f689e5c05..2d21122854 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +@@ -38,7 +38,8 @@ extern __typeof (strncmp) __strncmp_power9 attribute_hidden; + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect_strncmp, strncmp, + # ifdef __LITTLE_ENDIAN__ +- (hwcap2 & PPC_FEATURE2_ARCH_3_00) ++ (hwcap2 & PPC_FEATURE2_ARCH_3_00 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strncmp_power9 : + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strnlen.c b/sysdeps/powerpc/powerpc64/multiarch/strnlen.c +index baf375a75a..e68e9d9f88 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strnlen.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strnlen.c +@@ -29,7 +29,8 @@ extern __typeof (__strnlen) __strnlen_power8 attribute_hidden; + # undef strnlen + # undef __strnlen + libc_ifunc_redirected (__redirect___strnlen, __strnlen, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strnlen_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strnlen_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strrchr.c b/sysdeps/powerpc/powerpc64/multiarch/strrchr.c +index 1c9eea1817..7f0cf2a1b7 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strrchr.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strrchr.c +@@ -31,7 +31,8 @@ extern __typeof (strrchr) __strrchr_power8 attribute_hidden; + /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle + ifunc symbol properly. */ + libc_ifunc_redirected (__redirect_strrchr, strrchr, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_ALTIVEC) + ? __strrchr_power8 : + (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strrchr_power7 +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strspn.c b/sysdeps/powerpc/powerpc64/multiarch/strspn.c +index 70167a176b..7613ab3d55 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strspn.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strspn.c +@@ -27,7 +27,8 @@ extern __typeof (strspn) __strspn_ppc attribute_hidden; + extern __typeof (strspn) __strspn_power8 attribute_hidden; + + libc_ifunc (__libc_strspn, +- (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ (hwcap2 & PPC_FEATURE2_ARCH_2_07 ++ && hwcap & PPC_FEATURE_HAS_VSX) + ? __strspn_power8 + : __strspn_ppc); + diff --git a/SOURCES/glibc-RHEL-1017-4.patch b/SOURCES/glibc-RHEL-1017-4.patch new file mode 100644 index 0000000..1d327f0 --- /dev/null +++ b/SOURCES/glibc-RHEL-1017-4.patch @@ -0,0 +1,652 @@ +From 21841f0d562f0e944c4d267a28cc3ebd19c847e9 Mon Sep 17 00:00:00 2001 +From: Mahesh Bodapati +Date: Tue, 1 Aug 2023 07:41:17 -0500 +Subject: PowerPC: Influence cpu/arch hwcap features via GLIBC_TUNABLES + +This patch enables the option to influence hwcaps used by PowerPC. +The environment variable, GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,-zzz...., +can be used to enable CPU/ARCH feature yyy, disable CPU/ARCH feature xxx +and zzz, where the feature name is case-sensitive and has to match the ones +mentioned in the file{sysdeps/powerpc/dl-procinfo.c}. + +Note that the hwcap tunables only used in the IFUNC selection. +Reviewed-by: Adhemerval Zanella + +[rebased to c9s by DJ] + +diff -rupN a/manual/tunables.texi b/manual/tunables.texi +--- a/manual/tunables.texi 2023-09-13 01:16:19.979884270 -0400 ++++ b/manual/tunables.texi 2023-09-13 01:17:19.217179994 -0400 +@@ -476,7 +476,10 @@ On s390x, the supported HWCAP and STFLE + @code{sysdeps/s390/cpu-features.c}. In addition the user can also set + a CPU arch-level like @code{z13} instead of single HWCAP and STFLE features. + +-This tunable is specific to i386, x86-64 and s390x. ++On powerpc, the supported HWCAP and HWCAP2 features can be found in ++@code{sysdeps/powerpc/dl-procinfo.c}. ++ ++This tunable is specific to i386, x86-64, s390x and powerpc. + @end deftp + + @deftp Tunable glibc.cpu.cached_memopt +diff -rupN a/sysdeps/powerpc/cpu-features.c b/sysdeps/powerpc/cpu-features.c +--- a/sysdeps/powerpc/cpu-features.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/powerpc/cpu-features.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,39 +0,0 @@ +-/* Initialize cpu feature data. PowerPC version. +- Copyright (C) 2017-2021 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 +- . */ +- +-#include +-#include +- +-#if HAVE_TUNABLES +-# include +-#endif +- +-static inline void +-init_cpu_features (struct cpu_features *cpu_features) +-{ +- /* Default is to use aligned memory access on optimized function unless +- tunables is enable, since for this case user can explicit disable +- unaligned optimizations. */ +-#if HAVE_TUNABLES +- int32_t cached_memfunc = TUNABLE_GET (glibc, cpu, cached_memopt, int32_t, +- NULL); +- cpu_features->use_cached_memopt = (cached_memfunc > 0); +-#else +- cpu_features->use_cached_memopt = false; +-#endif +-} +diff -rupN a/sysdeps/powerpc/cpu-features.h b/sysdeps/powerpc/cpu-features.h +--- a/sysdeps/powerpc/cpu-features.h 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/powerpc/cpu-features.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,28 +0,0 @@ +-/* Initialize cpu feature data. PowerPC version. +- Copyright (C) 2017-2021 Free Software Foundation, Inc. +- +- 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 +- . */ +- +-#ifndef __CPU_FEATURES_POWERPC_H +-# define __CPU_FEATURES_POWERPC_H +- +-#include +- +-struct cpu_features +-{ +- bool use_cached_memopt; +-}; +- +-#endif /* __CPU_FEATURES_H */ +diff -rupN a/sysdeps/powerpc/dl-tunables.list b/sysdeps/powerpc/dl-tunables.list +--- a/sysdeps/powerpc/dl-tunables.list 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/powerpc/dl-tunables.list 2023-09-13 01:17:19.226180343 -0400 +@@ -24,5 +24,8 @@ glibc { + maxval: 1 + default: 0 + } ++ hwcaps { ++ type: STRING ++ } + } + } +diff -rupN a/sysdeps/powerpc/hwcapinfo.c b/sysdeps/powerpc/hwcapinfo.c +--- a/sysdeps/powerpc/hwcapinfo.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/powerpc/hwcapinfo.c 2023-09-13 01:17:19.229180459 -0400 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + uint64_t __tcb_hwcap __attribute__ ((visibility ("hidden"))); + uint32_t __tcb_platform __attribute__ ((visibility ("hidden"))); +@@ -64,6 +65,9 @@ __tcb_parse_hwcap_and_convert_at_platfor + else if (h1 & PPC_FEATURE_POWER5) + h1 |= PPC_FEATURE_POWER4; + ++ uint64_t array_hwcaps[] = { h1, h2 }; ++ init_cpu_features (&GLRO(dl_powerpc_cpu_features), array_hwcaps); ++ + /* Consolidate both HWCAP and HWCAP2 into a single doubleword so that + we can read both in a single load later. */ + __tcb_hwcap = h2; +diff -rupN a/sysdeps/powerpc/powerpc32/power4/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc32/power4/multiarch/ifunc-impl-list.c +--- a/sysdeps/powerpc/powerpc32/power4/multiarch/ifunc-impl-list.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/powerpc/powerpc32/power4/multiarch/ifunc-impl-list.c 2023-09-13 01:17:19.232180575 -0400 +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + /* Maximum number of IFUNC implementations. */ + #define MAX_IFUNC 6 +@@ -33,7 +34,8 @@ __libc_ifunc_impl_list (const char *name + + size_t i = 0; + +- unsigned long int hwcap = GLRO(dl_hwcap); ++ const struct cpu_features *features = &GLRO(dl_powerpc_cpu_features); ++ unsigned long int hwcap = features->hwcap; + /* hwcap contains only the latest supported ISA, the code checks which is + and fills the previous supported ones. */ + if (hwcap & PPC_FEATURE_ARCH_2_06) +diff -rupN a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h +--- a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h 2023-09-13 01:17:19.232180575 -0400 +@@ -16,6 +16,7 @@ + . */ + + #include ++#include + + /* The code checks if _rtld_global_ro was realocated before trying to access + the dl_hwcap field. The assembly is to make the compiler not optimize the +@@ -32,11 +33,12 @@ + # define __GLRO(value) GLRO(value) + #endif + +-/* dl_hwcap contains only the latest supported ISA, the macro checks which is +- and fills the previous ones. */ ++/* Get the hardware information post the tunables set, the macro checks ++ it and fills the previous ones. */ + #define INIT_ARCH() \ +- unsigned long int hwcap = __GLRO(dl_hwcap); \ +- unsigned long int __attribute__((unused)) hwcap2 = __GLRO(dl_hwcap2); \ ++ const struct cpu_features *features = &GLRO(dl_powerpc_cpu_features); \ ++ unsigned long int hwcap = features->hwcap; \ ++ unsigned long int __attribute__((unused)) hwcap2 = features->hwcap2; \ + bool __attribute__((unused)) use_cached_memopt = \ + __GLRO(dl_powerpc_cpu_features.use_cached_memopt); \ + if (hwcap & PPC_FEATURE_ARCH_2_06) \ +diff -rupN a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h +--- a/sysdeps/powerpc/powerpc64/dl-machine.h 2023-09-13 01:16:17.582791395 -0400 ++++ b/sysdeps/powerpc/powerpc64/dl-machine.h 2023-09-13 01:17:19.236180730 -0400 +@@ -27,7 +27,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -293,7 +292,6 @@ static inline void __attribute__ ((unuse + dl_platform_init (void) + { + __tcb_parse_hwcap_and_convert_at_platform (); +- init_cpu_features (&GLRO(dl_powerpc_cpu_features)); + } + #endif + +diff -rupN a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c 2023-09-13 01:16:20.219893569 -0400 ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c 2023-09-13 01:19:17.169756083 -0400 +@@ -17,6 +17,7 @@ + . */ + + #include ++#include + #include + #include + #include +@@ -32,9 +33,9 @@ __libc_ifunc_impl_list (const char *name + assert (max >= MAX_IFUNC); + + size_t i = 0; +- +- unsigned long int hwcap = GLRO(dl_hwcap); +- unsigned long int hwcap2 = GLRO(dl_hwcap2); ++ const struct cpu_features *features = &GLRO(dl_powerpc_cpu_features); ++ unsigned long int hwcap = features->hwcap; ++ unsigned long int hwcap2 = features->hwcap2; + #ifdef SHARED + int cacheline_size = GLRO(dl_cache_line_size); + #endif +diff -rupN a/sysdeps/unix/sysv/linux/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile +--- a/sysdeps/unix/sysv/linux/powerpc/Makefile 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/powerpc/Makefile 2023-09-13 01:17:19.243181002 -0400 +@@ -21,7 +21,12 @@ ifeq ($(subdir),misc) + sysdep_headers += bits/ppc.h + sysdep_routines += get_timebase_freq + tests-static += test-gettimebasefreq-static +-tests += $(tests-static) +-tests += test-gettimebasefreq +-tests += test-powerpc-linux-sysconf ++tests += \ ++ $(tests-static) \ ++ test-gettimebasefreq \ ++ test-powerpc-linux-sysconf \ ++ tst-hwcap-tunables \ ++ # tests ++ ++tst-hwcap-tunables-ARGS = -- $(host-test-program-cmd) + endif +diff -rupN a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c +--- a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c 2023-09-13 01:17:19.247181157 -0400 +@@ -0,0 +1,124 @@ ++/* Initialize cpu feature data. PowerPC version. ++ Copyright (C) 2017-2023 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) ++{ ++ /* The current IFUNC selection is always using the most recent ++ features which are available via AT_HWCAP or AT_HWCAP2. But in ++ some scenarios it is useful to adjust this selection. ++ ++ The environment variable: ++ ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,.... ++ ++ Can be used to enable HWCAP/HWCAP2 feature yyy, disable HWCAP/HWCAP2 ++ feature xxx, where the feature name is case-sensitive and has to match ++ the ones mentioned in the file{sysdeps/powerpc/dl-procinfo.c}. */ ++ ++ /* Copy the features from dl_powerpc_cpu_features, which contains the ++ features provided by AT_HWCAP and AT_HWCAP2. */ ++ struct cpu_features *cpu_features = &GLRO(dl_powerpc_cpu_features); ++ unsigned long int tcbv_hwcap = cpu_features->hwcap; ++ unsigned long int tcbv_hwcap2 = cpu_features->hwcap2; ++ const char *token = valp->strval; ++ do ++ { ++ const char *token_end, *feature; ++ bool disable; ++ size_t token_len, i, feature_len, offset = 0; ++ /* Find token separator or end of string. */ ++ for (token_end = token; *token_end != ','; token_end++) ++ if (*token_end == '\0') ++ break; ++ ++ /* Determine feature. */ ++ token_len = token_end - token; ++ if (*token == '-') ++ { ++ disable = true; ++ feature = token + 1; ++ feature_len = token_len - 1; ++ } ++ else ++ { ++ disable = false; ++ feature = token; ++ feature_len = token_len; ++ } ++ for (i = 0; i < array_length (hwcap_tunables); ++i) ++ { ++ const char *hwcap_name = hwcap_names + offset; ++ size_t hwcap_name_len = strlen (hwcap_name); ++ /* Check the tunable name on the supported list. */ ++ if (hwcap_name_len == feature_len ++ && memcmp (feature, hwcap_name, feature_len) == 0) ++ { ++ /* Update the hwcap and hwcap2 bits. */ ++ if (disable) ++ { ++ /* Id is 1 for hwcap2 tunable. */ ++ if (hwcap_tunables[i].id) ++ cpu_features->hwcap2 &= ~(hwcap_tunables[i].mask); ++ else ++ cpu_features->hwcap &= ~(hwcap_tunables[i].mask); ++ } ++ else ++ { ++ /* Enable the features and also check that no unsupported ++ features were enabled by user. */ ++ if (hwcap_tunables[i].id) ++ cpu_features->hwcap2 |= (tcbv_hwcap2 & hwcap_tunables[i].mask); ++ else ++ cpu_features->hwcap |= (tcbv_hwcap & hwcap_tunables[i].mask); ++ } ++ break; ++ } ++ offset += hwcap_name_len + 1; ++ } ++ token += token_len; ++ /* ... and skip token separator for next round. */ ++ if (*token == ',') ++ token++; ++ } ++ while (*token != '\0'); ++} ++ ++static inline void ++init_cpu_features (struct cpu_features *cpu_features, uint64_t hwcaps[]) ++{ ++ /* Fill the cpu_features with the supported hwcaps ++ which are set by __tcb_parse_hwcap_and_convert_at_platform. */ ++ cpu_features->hwcap = hwcaps[0]; ++ cpu_features->hwcap2 = hwcaps[1]; ++ /* Default is to use aligned memory access on optimized function unless ++ tunables is enable, since for this case user can explicit disable ++ unaligned optimizations. */ ++ int32_t cached_memfunc = TUNABLE_GET (glibc, cpu, cached_memopt, int32_t, ++ NULL); ++ cpu_features->use_cached_memopt = (cached_memfunc > 0); ++ TUNABLE_GET (glibc, cpu, hwcaps, tunable_val_t *, ++ TUNABLE_CALLBACK (set_hwcaps)); ++} +diff -rupN a/sysdeps/unix/sysv/linux/powerpc/cpu-features.h b/sysdeps/unix/sysv/linux/powerpc/cpu-features.h +--- a/sysdeps/unix/sysv/linux/powerpc/cpu-features.h 1969-12-31 19:00:00.000000000 -0500 ++++ b/sysdeps/unix/sysv/linux/powerpc/cpu-features.h 2023-09-13 01:17:19.251181312 -0400 +@@ -0,0 +1,130 @@ ++/* Initialize cpu feature data. PowerPC version. ++ Copyright (C) 2017-2023 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef __CPU_FEATURES_POWERPC_H ++# define __CPU_FEATURES_POWERPC_H ++ ++#include ++#include ++ ++struct cpu_features ++{ ++ bool use_cached_memopt; ++ unsigned long int hwcap; ++ unsigned long int hwcap2; ++}; ++ ++static const char hwcap_names[] = { ++ "4xxmac\0" ++ "altivec\0" ++ "arch_2_05\0" ++ "arch_2_06\0" ++ "archpmu\0" ++ "booke\0" ++ "cellbe\0" ++ "dfp\0" ++ "efpdouble\0" ++ "efpsingle\0" ++ "fpu\0" ++ "ic_snoop\0" ++ "mmu\0" ++ "notb\0" ++ "pa6t\0" ++ "power4\0" ++ "power5\0" ++ "power5+\0" ++ "power6x\0" ++ "ppc32\0" ++ "ppc601\0" ++ "ppc64\0" ++ "ppcle\0" ++ "smt\0" ++ "spe\0" ++ "true_le\0" ++ "ucache\0" ++ "vsx\0" ++ "arch_2_07\0" ++ "dscr\0" ++ "ebb\0" ++ "htm\0" ++ "htm-nosc\0" ++ "htm-no-suspend\0" ++ "isel\0" ++ "tar\0" ++ "vcrypto\0" ++ "arch_3_00\0" ++ "ieee128\0" ++ "darn\0" ++ "scv\0" ++ "arch_3_1\0" ++ "mma\0" ++}; ++ ++static const struct ++{ ++ unsigned int mask; ++ bool id; ++} hwcap_tunables[] = { ++ /* AT_HWCAP tunable masks. */ ++ { PPC_FEATURE_HAS_4xxMAC, 0 }, ++ { PPC_FEATURE_HAS_ALTIVEC, 0 }, ++ { PPC_FEATURE_ARCH_2_05, 0 }, ++ { PPC_FEATURE_ARCH_2_06, 0 }, ++ { PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0 }, ++ { PPC_FEATURE_BOOKE, 0 }, ++ { PPC_FEATURE_CELL_BE, 0 }, ++ { PPC_FEATURE_HAS_DFP, 0 }, ++ { PPC_FEATURE_HAS_EFP_DOUBLE, 0 }, ++ { PPC_FEATURE_HAS_EFP_SINGLE, 0 }, ++ { PPC_FEATURE_HAS_FPU, 0 }, ++ { PPC_FEATURE_ICACHE_SNOOP, 0 }, ++ { PPC_FEATURE_HAS_MMU, 0 }, ++ { PPC_FEATURE_NO_TB, 0 }, ++ { PPC_FEATURE_PA6T, 0 }, ++ { PPC_FEATURE_POWER4, 0 }, ++ { PPC_FEATURE_POWER5, 0 }, ++ { PPC_FEATURE_POWER5_PLUS, 0 }, ++ { PPC_FEATURE_POWER6_EXT, 0 }, ++ { PPC_FEATURE_32, 0 }, ++ { PPC_FEATURE_601_INSTR, 0 }, ++ { PPC_FEATURE_64, 0 }, ++ { PPC_FEATURE_PPC_LE, 0 }, ++ { PPC_FEATURE_SMT, 0 }, ++ { PPC_FEATURE_HAS_SPE, 0 }, ++ { PPC_FEATURE_TRUE_LE, 0 }, ++ { PPC_FEATURE_UNIFIED_CACHE, 0 }, ++ { PPC_FEATURE_HAS_VSX, 0 }, ++ ++ /* AT_HWCAP2 tunable masks. */ ++ { PPC_FEATURE2_ARCH_2_07, 1 }, ++ { PPC_FEATURE2_HAS_DSCR, 1 }, ++ { PPC_FEATURE2_HAS_EBB, 1 }, ++ { PPC_FEATURE2_HAS_HTM, 1 }, ++ { PPC_FEATURE2_HTM_NOSC, 1 }, ++ { PPC_FEATURE2_HTM_NO_SUSPEND, 1 }, ++ { PPC_FEATURE2_HAS_ISEL, 1 }, ++ { PPC_FEATURE2_HAS_TAR, 1 }, ++ { PPC_FEATURE2_HAS_VEC_CRYPTO, 1 }, ++ { PPC_FEATURE2_ARCH_3_00, 1 }, ++ { PPC_FEATURE2_HAS_IEEE128, 1 }, ++ { PPC_FEATURE2_DARN, 1 }, ++ { PPC_FEATURE2_SCV, 1 }, ++ { PPC_FEATURE2_ARCH_3_1, 1 }, ++ { PPC_FEATURE2_MMA, 1 }, ++}; ++ ++#endif /* __CPU_FEATURES_H */ +diff -rupN a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list 2023-09-13 01:16:19.989884657 -0400 ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list 2023-09-13 01:17:19.254181428 -0400 +@@ -28,3 +28,4 @@ + @order glibc.malloc.check + @order glibc.gmon.minarcs + @order glibc.gmon.maxarcs ++@order glibc.cpu.hwcaps +diff -rupN a/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c b/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c +--- a/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c 2023-09-13 01:17:19.258181583 -0400 +@@ -0,0 +1,128 @@ ++/* Tests for powerpc GLIBC_TUNABLES=glibc.cpu.hwcaps filter. ++ Copyright (C) 2023 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Nonzero if the program gets called via `exec'. */ ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++static int restart; ++ ++/* Hold the four initial argument used to respawn the process, plus the extra ++ '--direct', '--restart', and the function to check */ ++static char *spargs[8]; ++static int fc; ++ ++/* Called on process re-execution. */ ++_Noreturn static void ++handle_restart (int argc, char *argv[]) ++{ ++ TEST_VERIFY_EXIT (argc == 1); ++ const char *funcname = argv[0]; ++ ++ struct libc_ifunc_impl impls[32]; ++ int cnt = __libc_ifunc_impl_list ("memcpy", impls, array_length (impls)); ++ if (cnt == 0) ++ _exit (EXIT_SUCCESS); ++ TEST_VERIFY_EXIT (cnt >= 1); ++ for (int i = 0; i < cnt; i++) { ++ if (strcmp (impls[i].name, funcname) == 0) ++ { ++ TEST_COMPARE (impls[i].usable, false); ++ break; ++ } ++ } ++ ++ _exit (EXIT_SUCCESS); ++} ++ ++static void ++run_test (const char *filter, const char *funcname) ++{ ++ printf ("info: checking filter %s (expect %s ifunc selection to be removed)\n", ++ filter, funcname); ++ char *tunable = xasprintf ("GLIBC_TUNABLES=glibc.cpu.hwcaps=%s", filter); ++ char *const newenvs[] = { (char*) tunable, NULL }; ++ spargs[fc] = (char *) funcname; ++ ++ pid_t pid; ++ TEST_COMPARE (posix_spawn (&pid, spargs[0], NULL, NULL, spargs, newenvs), 0); ++ int status; ++ TEST_COMPARE (xwaitpid (pid, &status, 0), pid); ++ TEST_VERIFY (WIFEXITED (status)); ++ TEST_VERIFY (!WIFSIGNALED (status)); ++ TEST_COMPARE (WEXITSTATUS (status), 0); ++ ++ free (tunable); ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ if (restart) ++ handle_restart (argc - 1, &argv[1]); ++ ++ TEST_VERIFY_EXIT (argc == 2 || argc == 5); ++ ++ int i; ++ for (i = 0; i < argc - 1; i++) ++ spargs[i] = argv[i + 1]; ++ spargs[i++] = (char *) "--direct"; ++ spargs[i++] = (char *) "--restart"; ++ fc = i++; ++ spargs[i] = NULL; ++ ++ unsigned long int hwcap = getauxval (AT_HWCAP); ++ unsigned long int hwcap2 = getauxval (AT_HWCAP2); ++ if (__WORDSIZE == 64) ++ { ++ if (hwcap2 & PPC_FEATURE2_ARCH_3_1) ++ run_test ("-arch_3_1", "__memcpy_power10"); ++ if (hwcap2 & PPC_FEATURE2_ARCH_2_07) ++ run_test ("-arch_2_07", "__memcpy_power8_cached"); ++ if (hwcap & PPC_FEATURE_ARCH_2_06) ++ run_test ("-arch_2_06", "__memcpy_power7"); ++ if (hwcap & PPC_FEATURE_ARCH_2_05) ++ run_test ("-arch_2_06,-arch_2_05","__memcpy_power6"); ++ run_test ("-arch_2_06,-arch_2_05,-power5+,-power5,-power4", "__memcpy_power4"); ++ } ++ else ++ { ++ if (hwcap & PPC_FEATURE_HAS_VSX) ++ run_test ("-vsx", "__memcpy_power7"); ++ if (hwcap & PPC_FEATURE_ARCH_2_06) ++ run_test ("-arch_2_06", "__memcpy_a2"); ++ if (hwcap & PPC_FEATURE_ARCH_2_05) ++ run_test ("-arch_2_05", "__memcpy_power6"); ++ } ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include diff --git a/SOURCES/glibc-RHEL-1191.patch b/SOURCES/glibc-RHEL-1191.patch new file mode 100644 index 0000000..3cb6635 --- /dev/null +++ b/SOURCES/glibc-RHEL-1191.patch @@ -0,0 +1,69 @@ +commit 1493622f4f9048ffede3fbedb64695efa49d662a +Author: H.J. Lu +Date: Mon Aug 28 12:08:14 2023 -0700 + + x86: Check the lower byte of EAX of CPUID leaf 2 [BZ #30643] + + The old Intel software developer manual specified that the low byte of + EAX of CPUID leaf 2 returned 1 which indicated the number of rounds of + CPUDID leaf 2 was needed to retrieve the complete cache information. The + newer Intel manual has been changed to that it should always return 1 + and be ignored. If the lower byte isn't 1, CPUID leaf 2 can't be used. + In this case, we ignore CPUID leaf 2 and use CPUID leaf 4 instead. If + CPUID leaf 4 doesn't contain the cache information, cache information + isn't available at all. This addresses BZ #30643. + +diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h +index f950e488cfbe42dd..bd2f2b65f78056ca 100644 +--- a/sysdeps/x86/dl-cacheinfo.h ++++ b/sysdeps/x86/dl-cacheinfo.h +@@ -187,7 +187,7 @@ intel_check_word (int name, unsigned int value, bool *has_level_2, + ++round; + } + /* There is no other cache information anywhere else. */ +- break; ++ return -1; + } + else + { +@@ -257,28 +257,23 @@ handle_intel (int name, const struct cpu_features *cpu_features) + + /* OK, we can use the CPUID instruction to get all info about the + caches. */ +- unsigned int cnt = 0; +- unsigned int max = 1; + long int result = 0; + bool no_level_2_or_3 = false; + bool has_level_2 = false; ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ __cpuid (2, eax, ebx, ecx, edx); + +- while (cnt++ < max) ++ /* The low byte of EAX of CPUID leaf 2 should always return 1 and it ++ should be ignored. If it isn't 1, use CPUID leaf 4 instead. */ ++ if ((eax & 0xff) != 1) ++ return intel_check_word (name, 0xff, &has_level_2, &no_level_2_or_3, ++ cpu_features); ++ else + { +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- __cpuid (2, eax, ebx, ecx, edx); +- +- /* The low byte of EAX in the first round contain the number of +- rounds we have to make. At least one, the one we are already +- doing. */ +- if (cnt == 1) +- { +- max = eax & 0xff; +- eax &= 0xffffff00; +- } ++ eax &= 0xffffff00; + + /* Process the individual registers' value. */ + result = intel_check_word (name, eax, &has_level_2, diff --git a/SOURCES/glibc-RHEL-14383-1.patch b/SOURCES/glibc-RHEL-14383-1.patch new file mode 100644 index 0000000..7a2e8d6 --- /dev/null +++ b/SOURCES/glibc-RHEL-14383-1.patch @@ -0,0 +1,72 @@ +commit 2aa0974d2573441bffd596b07bff8698b1f2f18c +Author: Florian Weimer +Date: Fri Oct 20 14:29:50 2023 +0200 + + elf: ldconfig should skip temporary files created by package managers + + This avoids crashes due to partially written files, after a package + update is interrupted. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/ldconfig.c + (missing alloca removal downstream) + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index be47ad8c2d7f89f3..f0c811001965cc46 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -778,6 +778,31 @@ struct dlib_entry + struct dlib_entry *next; + }; + ++/* Skip some temporary DSO files. These files may be partially written ++ and lead to ldconfig crashes when examined. */ ++static bool ++skip_dso_based_on_name (const char *name, size_t len) ++{ ++ /* Skip temporary files created by the prelink program. Files with ++ names like these are never really DSOs we want to look at. */ ++ if (len >= sizeof (".#prelink#") - 1) ++ { ++ if (strcmp (name + len - sizeof (".#prelink#") + 1, ++ ".#prelink#") == 0) ++ return true; ++ if (len >= sizeof (".#prelink#.XXXXXX") - 1 ++ && memcmp (name + len - sizeof (".#prelink#.XXXXXX") ++ + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0) ++ return true; ++ } ++ /* Skip temporary files created by RPM. */ ++ if (memchr (name, len, ';') != NULL) ++ return true; ++ /* Skip temporary files created by dpkg. */ ++ if (len > 4 && memcmp (name + len - 4, ".tmp", 4) == 0) ++ return true; ++ return false; ++} + + static void + search_dir (const struct dir_entry *entry) +@@ -854,18 +879,8 @@ search_dir (const struct dir_entry *entry) + continue; + + size_t len = strlen (direntry->d_name); +- /* Skip temporary files created by the prelink program. Files with +- names like these are never really DSOs we want to look at. */ +- if (len >= sizeof (".#prelink#") - 1) +- { +- if (strcmp (direntry->d_name + len - sizeof (".#prelink#") + 1, +- ".#prelink#") == 0) +- continue; +- if (len >= sizeof (".#prelink#.XXXXXX") - 1 +- && memcmp (direntry->d_name + len - sizeof (".#prelink#.XXXXXX") +- + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0) +- continue; +- } ++ if (skip_dso_based_on_name (direntry->d_name, len)) ++ continue; + len += strlen (entry->path) + 2; + if (len > file_name_len) + { diff --git a/SOURCES/glibc-RHEL-14383-2.patch b/SOURCES/glibc-RHEL-14383-2.patch new file mode 100644 index 0000000..4f68766 --- /dev/null +++ b/SOURCES/glibc-RHEL-14383-2.patch @@ -0,0 +1,61 @@ +commit cfb5a97a93ea656e3b2263e42142a4032986d9ba +Author: Florian Weimer +Date: Mon Oct 23 12:53:16 2023 +0200 + + ldconfig: Fixes for skipping temporary files. + + Arguments to a memchr call were swapped, causing incorrect skipping + of files. + + Files related to dpkg have different names: they actually end in + .dpkg-new and .dpkg-tmp, not .tmp as I mistakenly assumed. + + Fixes commit 2aa0974d2573441bffd59 ("elf: ldconfig should skip + temporary files created by package managers"). + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index f0c811001965cc46..4a96c409994d96c8 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -778,6 +778,17 @@ struct dlib_entry + struct dlib_entry *next; + }; + ++/* Return true if the N bytes at NAME end with with the characters in ++ the string SUFFIX. (NAME[N + 1] does not have to be a null byte.) ++ Expected to be called with a string literal for SUFFIX. */ ++static inline bool ++endswithn (const char *name, size_t n, const char *suffix) ++{ ++ return (n >= strlen (suffix) ++ && memcmp (name + n - strlen (suffix), suffix, ++ strlen (suffix)) == 0); ++} ++ + /* Skip some temporary DSO files. These files may be partially written + and lead to ldconfig crashes when examined. */ + static bool +@@ -787,8 +798,7 @@ skip_dso_based_on_name (const char *name, size_t len) + names like these are never really DSOs we want to look at. */ + if (len >= sizeof (".#prelink#") - 1) + { +- if (strcmp (name + len - sizeof (".#prelink#") + 1, +- ".#prelink#") == 0) ++ if (endswithn (name, len, ".#prelink#")) + return true; + if (len >= sizeof (".#prelink#.XXXXXX") - 1 + && memcmp (name + len - sizeof (".#prelink#.XXXXXX") +@@ -796,10 +806,11 @@ skip_dso_based_on_name (const char *name, size_t len) + return true; + } + /* Skip temporary files created by RPM. */ +- if (memchr (name, len, ';') != NULL) ++ if (memchr (name, ';', len) != NULL) + return true; + /* Skip temporary files created by dpkg. */ +- if (len > 4 && memcmp (name + len - 4, ".tmp", 4) == 0) ++ if (endswithn (name, len, ".dpkg-new") ++ || endswithn (name, len, ".dpkg-tmp")) + return true; + return false; + } diff --git a/SOURCES/glibc-RHEL-15343-1.patch b/SOURCES/glibc-RHEL-15343-1.patch new file mode 100644 index 0000000..291e770 --- /dev/null +++ b/SOURCES/glibc-RHEL-15343-1.patch @@ -0,0 +1,26 @@ +commit 1626d8a521c7c771d4118b1328421fea113cab64 +Author: Joe Simmons-Talbott +Date: Fri Apr 21 09:24:22 2023 -0400 + + string: Allow use of test-string.h for non-ifunc implementations. + + Mark two variables as unused to silence warning when using + test-string.h for non-ifunc implementations. + + Reviewed-by: Adhemerval Zanella + +diff --git a/string/test-string.h b/string/test-string.h +index 41de973479..8bcb8afd0a 100644 +--- a/string/test-string.h ++++ b/string/test-string.h +@@ -130,8 +130,8 @@ cmdline_process_function (int c) + /* Increase size of FUNC_LIST if assert is triggered at run-time. */ + static struct libc_ifunc_impl func_list[32]; + static int func_count; +-static int impl_count = -1; +-static impl_t *impl_array; ++static int impl_count __attribute__ ((unused)) = -1; ++static impl_t *impl_array __attribute__ ((unused)); + + # define FOR_EACH_IMPL(impl, notall) \ + impl_t *impl; \ diff --git a/SOURCES/glibc-RHEL-15343-2.patch b/SOURCES/glibc-RHEL-15343-2.patch new file mode 100644 index 0000000..2110e90 --- /dev/null +++ b/SOURCES/glibc-RHEL-15343-2.patch @@ -0,0 +1,233 @@ +commit eaaad78db41724e5a18a42becb238bfc4e683998 +Author: Joe Simmons-Talbott +Date: Fri Apr 21 09:24:23 2023 -0400 + + string: Add tests for strdup (BZ #30266) + + Copy strcpy tests for strdup. Covers some basic testcases with random + strings. Add a zero-length string testcase. + + Reviewed-by: Adhemerval Zanella + Conflicts: + string/Makefile + (different test backport order) + + +diff -Nrup a/string/Makefile b/string/Makefile +--- a/string/Makefile 2023-11-30 10:59:16.400251685 -0500 ++++ b/string/Makefile 2023-11-30 11:16:42.829613344 -0500 +@@ -63,7 +63,8 @@ tests := tester inl-tester noinl-tester + tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt \ + test-endian-types test-endian-file-scope \ + test-endian-sign-conversion tst-memmove-overflow \ +- test-sig_np tst-strerror-fail ++ test-sig_np tst-strerror-fail \ ++ test-strdup + + # Both tests require the .mo translation files generated by msgfmt. + tests-translation := tst-strsignal \ +diff -Nrup a/string/test-strdup.c b/string/test-strdup.c +--- a/string/test-strdup.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/string/test-strdup.c 2023-11-30 11:11:32.850447614 -0500 +@@ -0,0 +1,201 @@ ++/* Test and measure strdup functions. ++ Copyright (C) 2023 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 ++ . */ ++ ++#include ++ ++#ifdef WIDE ++# include ++# define CHAR wchar_t ++# define sfmt "ls" ++# define BIG_CHAR WCHAR_MAX ++# define SMALL_CHAR 1273 ++# define STRCMP wcscmp ++# define MEMCMP wmemcmp ++# define MEMSET wmemset ++# define TCS TEST_COMPARE_STRING_WIDE ++#else ++# define CHAR char ++# define sfmt "s" ++# define BIG_CHAR CHAR_MAX ++# define SMALL_CHAR 127 ++# define STRCMP strcmp ++# define MEMCMP memcmp ++# define MEMSET memset ++# define TCS TEST_COMPARE_STRING ++#endif ++ ++#ifndef STRDUP_RESULT ++# define STRDUP_RESULT(dst, len) dst ++# define TEST_MAIN ++# ifndef WIDE ++# define TEST_NAME "strdup" ++# else ++# define TEST_NAME "wcsdup" ++# endif ++# include "test-string.h" ++# ifndef WIDE ++# define STRDUP strdup ++# else ++# define STRDUP wcsdup ++# endif ++#endif ++ ++typedef CHAR *(*proto_t) (const CHAR *); ++ ++static void ++do_zero_len_test (void) ++{ ++ CHAR src[1] = { '\0' }; ++ CHAR *dst = STRDUP (src); ++ ++ TCS (dst, src); ++ free (dst); ++} ++ ++static void ++do_one_test (const CHAR *src, ++ size_t len __attribute__((unused))) ++{ ++ CHAR *dst = STRDUP (src); ++ ++ if (STRCMP (dst, src) != 0) ++ { ++ error (0, 0, ++ "Wrong result in function %s dst \"%" sfmt "\" src \"%" sfmt "\"", ++ TEST_NAME, dst, src); ++ ret = 1; ++ free (dst); ++ return; ++ } ++ free (dst); ++} ++ ++static void ++do_test (size_t align1, size_t align2, size_t len, int max_char) ++{ ++ size_t i; ++ CHAR *s1; ++/* For wcsdup: align1 and align2 here mean alignment not in bytes, ++ but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t)) ++ len for wcschr here isn't in bytes but it's number of wchar_t symbols. */ ++ align1 &= 7; ++ if ((align1 + len) * sizeof (CHAR) >= page_size) ++ return; ++ ++ align2 &= 7; ++ if ((align2 + len) * sizeof (CHAR) >= page_size) ++ return; ++ ++ s1 = (CHAR *) (buf1) + align1; ++ ++ for (i = 0; i < len; i++) ++ s1[i] = 32 + 23 * i % (max_char - 32); ++ s1[len] = 0; ++ ++ do_one_test (s1, len); ++} ++ ++static void ++do_random_tests (void) ++{ ++ size_t i, j, n, align1, align2, len; ++ CHAR *p1 = (CHAR *)(buf1 + page_size) - 512; ++ CHAR *res; ++ ++ for (n = 0; n < ITERATIONS; n++) ++ { ++ /* align1 and align2 are expressed as wchar_t and not in bytes for wide ++ char test, and thus it will be equal to align times wchar_t size. ++ ++ For non wide version we need to check all alignments from 0 to 63 ++ since some assembly implementations have separate prolog for alignments ++ more 48. */ ++ ++ align1 = random () & (63 / sizeof (CHAR)); ++ if (random () & 1) ++ align2 = random () & (63 / sizeof (CHAR)); ++ else ++ align2 = align1 + (random () & 24); ++ len = random () & 511; ++ j = align1; ++ if (align2 > j) ++ j = align2; ++ if (len + j >= 511) ++ len = 510 - j - (random () & 7); ++ j = len + align1 + 64; ++ if (j > 512) ++ j = 512; ++ for (i = 0; i < j; i++) ++ { ++ if (i == len + align1) ++ p1[i] = 0; ++ else ++ { ++ p1[i] = random () & BIG_CHAR; ++ if (i >= align1 && i < len + align1 && !p1[i]) ++ p1[i] = (random () & SMALL_CHAR) + 3; ++ } ++ } ++ ++ res = STRDUP(p1 + align1); ++ TCS (res, (p1 + align1)); ++ free (res); ++ } ++} ++ ++ ++int ++test_main (void) ++{ ++ size_t i; ++ ++ test_init (); ++ ++ printf ("%23s", ""); ++ printf ("\t%s", TEST_NAME); ++ putchar ('\n'); ++ ++ for (i = 0; i < 16; ++i) ++ { ++ do_test (0, 0, i, SMALL_CHAR); ++ do_test (0, 0, i, BIG_CHAR); ++ do_test (0, i, i, SMALL_CHAR); ++ do_test (i, 0, i, BIG_CHAR); ++ } ++ ++ for (i = 1; i < 8; ++i) ++ { ++ do_test (0, 0, 8 << i, SMALL_CHAR); ++ do_test (8 - i, 2 * i, 8 << i, SMALL_CHAR); ++ } ++ ++ for (i = 1; i < 8; ++i) ++ { ++ do_test (i, 2 * i, 8 << i, SMALL_CHAR); ++ do_test (2 * i, i, 8 << i, BIG_CHAR); ++ do_test (i, i, 8 << i, SMALL_CHAR); ++ do_test (i, i, 8 << i, BIG_CHAR); ++ } ++ ++ do_zero_len_test (); ++ do_random_tests (); ++ ++ return ret; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-15343-3.patch b/SOURCES/glibc-RHEL-15343-3.patch new file mode 100644 index 0000000..8cac6d9 --- /dev/null +++ b/SOURCES/glibc-RHEL-15343-3.patch @@ -0,0 +1,232 @@ +commit 0c48aa0551151ea201f7f528492e89a0b08a6890 +Author: Joe Simmons-Talbott +Date: Fri Apr 21 09:24:24 2023 -0400 + + string: Add tests for strndup (BZ #30266) + + Copy strncpy tests for strndup. Covers some basic testcases with random + strings. Remove tests that set the destination's bytes and checked the + resulting buffer's bytes. Remove wide character test support since + wcsndup() doesn't exist. + + Reviewed-by: Adhemerval Zanella + Conflicts: + string/Makefile + (different test backport order) + +diff -Nrup a/string/Makefile b/string/Makefile +--- a/string/Makefile 2023-11-30 11:55:02.263010916 -0500 ++++ b/string/Makefile 2023-11-30 11:58:29.238954539 -0500 +@@ -64,7 +64,7 @@ tests := tester inl-tester noinl-tester + test-endian-types test-endian-file-scope \ + test-endian-sign-conversion tst-memmove-overflow \ + test-sig_np tst-strerror-fail \ +- test-strdup ++ test-strdup test-strndup + + # Both tests require the .mo translation files generated by msgfmt. + tests-translation := tst-strsignal \ +diff -Nrup a/string/test-strndup.c b/string/test-strndup.c +--- a/string/test-strndup.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/string/test-strndup.c 2023-11-30 11:56:24.986388053 -0500 +@@ -0,0 +1,200 @@ ++/* Test strndup functions. ++ Copyright (C) 2023 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 ++ . */ ++ ++#include ++ ++#define TEST_MAIN ++#include "test-string.h" ++ ++static void ++do_one_test (const char *src, size_t len, size_t n) ++{ ++ char *dst = strndup (src, n); ++ size_t s = (len > n ? n: len) * sizeof (char); ++ ++ TEST_COMPARE_BLOB (dst, s, src, s); ++ ++ free (dst); ++} ++ ++static void ++do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char) ++{ ++ size_t i; ++ char *s1; ++ ++ align1 &= 7; ++ if ((align1 + len) * sizeof (char) >= page_size) ++ return; ++ ++ align2 &= 7; ++ if ((align2 + len) * sizeof (char) >= page_size) ++ return; ++ ++ s1 = (char *) (buf1) + align1; ++ ++ for (i = 0; i < len; ++i) ++ s1[i] = 32 + 23 * i % (max_char - 32); ++ s1[len] = 0; ++ for (i = len + 1; (i + align1) * sizeof (char) < page_size && i < len + 64; ++ ++i) ++ s1[i] = 32 + 32 * i % (max_char - 32); ++ ++ do_one_test (s1, len, n); ++} ++ ++static void ++do_page_tests (void) ++{ ++ char *s1; ++ const size_t maxoffset = 64; ++ ++ /* Put s1 at the maxoffset from the edge of buf1's last page. */ ++ s1 = (char *) buf1 + BUF1PAGES * page_size / sizeof (char) - maxoffset; ++ ++ memset (s1, 'a', maxoffset - 1); ++ s1[maxoffset - 1] = '\0'; ++ ++ /* Both strings are bounded to a page with read/write access and the next ++ page is protected with PROT_NONE (meaning that any access outside of the ++ page regions will trigger an invalid memory access). ++ ++ The loop copies the string s1 for all possible offsets up to maxoffset ++ for both inputs with a size larger than s1 (so memory access outside the ++ expected memory regions might trigger invalid access). */ ++ ++ for (size_t off1 = 0; off1 < maxoffset; off1++) ++ for (size_t off2 = 0; off2 < maxoffset; off2++) ++ do_one_test (s1 + off1, maxoffset - off1 - 1, ++ maxoffset + (maxoffset - off2)); ++} ++ ++static void ++do_random_tests (void) ++{ ++ size_t i, j, n, align1, align2, len, size, mode; ++ char *p1 = (char *) (buf1 + page_size) - 512; ++ char *res; ++ ++ for (n = 0; n < ITERATIONS; n++) ++ { ++ mode = random (); ++ if (mode & 1) ++ { ++ size = random () & 255; ++ align1 = 512 - size - (random () & 15); ++ if (mode & 2) ++ align2 = align1 - (random () & 24); ++ else ++ align2 = align1 - (random () & 31); ++ if (mode & 4) ++ { ++ j = align1; ++ align1 = align2; ++ align2 = j; ++ } ++ if (mode & 8) ++ len = size - (random () & 31); ++ else ++ len = 512; ++ if (len >= 512) ++ len = random () & 511; ++ } ++ else ++ { ++ align1 = random () & 31; ++ if (mode & 2) ++ align2 = random () & 31; ++ else ++ align2 = align1 + (random () & 24); ++ len = random () & 511; ++ j = align1; ++ if (align2 > j) ++ j = align2; ++ if (mode & 4) ++ { ++ size = random () & 511; ++ if (size + j > 512) ++ size = 512 - j - (random () & 31); ++ } ++ else ++ size = 512 - j; ++ if ((mode & 8) && len + j >= 512) ++ len = 512 - j - (random () & 7); ++ } ++ j = len + align1 + 64; ++ if (j > 512) ++ j = 512; ++ for (i = 0; i < j; i++) ++ { ++ if (i == len + align1) ++ p1[i] = 0; ++ else ++ { ++ p1[i] = random () & CHAR_MAX; ++ if (i >= align1 && i < len + align1 && !p1[i]) ++ p1[i] = (random () & 127) + 3; ++ } ++ } ++ ++ res = (char *) strndup ((char *) (p1 + align1), size); ++ j = len + 1; ++ if (size < j) ++ j = size; ++ TEST_COMPARE_BLOB (res, j, (char *) (p1 + align1), j); ++ free (res); ++ } ++} ++ ++int ++test_main (void) ++{ ++ size_t i; ++ ++ test_init (); ++ ++ printf ("%28s", ""); ++ printf ("\t%s", "strndup"); ++ putchar ('\n'); ++ ++ for (i = 1; i < 8; ++i) ++ { ++ do_test (i, i, 16, 16, 127); ++ do_test (i, i, 16, 16, CHAR_MAX); ++ do_test (i, 2 * i, 16, 16, 127); ++ do_test (2 * i, i, 16, 16, CHAR_MAX); ++ do_test (8 - i, 2 * i, 1 << i, 2 << i, 127); ++ do_test (2 * i, 8 - i, 2 << i, 1 << i, 127); ++ do_test (8 - i, 2 * i, 1 << i, 2 << i, CHAR_MAX); ++ do_test (2 * i, 8 - i, 2 << i, 1 << i, CHAR_MAX); ++ } ++ ++ for (i = 1; i < 8; ++i) ++ { ++ do_test (0, 0, 4 << i, 8 << i, 127); ++ do_test (0, 0, 16 << i, 8 << i, 127); ++ do_test (8 - i, 2 * i, 4 << i, 8 << i, 127); ++ do_test (8 - i, 2 * i, 16 << i, 8 << i, 127); ++ } ++ ++ do_random_tests (); ++ do_page_tests (); ++ return ret; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-15343-4.patch b/SOURCES/glibc-RHEL-15343-4.patch new file mode 100644 index 0000000..cd2a826 --- /dev/null +++ b/SOURCES/glibc-RHEL-15343-4.patch @@ -0,0 +1,33 @@ +commit 0aa5b28a504c6f1f17b387d8147715d1496fff62 +Author: Joe Simmons-Talbott +Date: Fri Apr 21 09:24:25 2023 -0400 + + wcsmbs: Add wcsdup() tests. (BZ #30266) + + Enable wide character testcases for wcsdup(). + + Reviewed-by: Adhemerval Zanella + Conflicts: + wcsmbs/Makefile + (different test backport order) + + +diff -Nrup a/wcsmbs/Makefile b/wcsmbs/Makefile +--- a/wcsmbs/Makefile 2023-11-30 14:14:18.755010508 -0500 ++++ b/wcsmbs/Makefile 2023-11-30 14:38:18.511131851 -0500 +@@ -53,7 +53,8 @@ tests := tst-wcstof wcsmbs-tst1 tst-wcsn + tst-c16c32-1 wcsatcliff tst-wcstol-locale tst-wcstod-nan-locale \ + tst-wcstod-round test-char-types tst-fgetwc-after-eof \ + tst-wcstod-nan-sign tst-c16-surrogate tst-c32-state \ +- $(addprefix test-,$(strop-tests)) tst-mbstowcs ++ $(addprefix test-,$(strop-tests)) tst-mbstowcs \ ++ test-wcsdup + + include ../Rules + +diff -Nrup a/wcsmbs/test-wcsdup.c b/wcsmbs/test-wcsdup.c +--- a/wcsmbs/test-wcsdup.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/wcsmbs/test-wcsdup.c 2023-11-30 14:14:48.869138712 -0500 +@@ -0,0 +1,2 @@ ++#define WIDE 1 ++#include "../string/test-strdup.c" diff --git a/SOURCES/glibc-RHEL-16016-1.patch b/SOURCES/glibc-RHEL-16016-1.patch new file mode 100644 index 0000000..4dc5c5f --- /dev/null +++ b/SOURCES/glibc-RHEL-16016-1.patch @@ -0,0 +1,26 @@ +commit 919b9bfaa969c9517fe86c753c001b96ee4ea840 +Author: Joseph Myers +Date: Wed Oct 5 14:33:14 2022 +0000 + + Update syscall lists for Linux 6.0 + + Linux 6.0 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 6.0. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 028ad3107a..4a78258646 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.19. +-kernel 5.19 ++# The list of system calls is current as of Linux 6.0. ++kernel 6.0 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-RHEL-16016-2.patch b/SOURCES/glibc-RHEL-16016-2.patch new file mode 100644 index 0000000..18ce2c3 --- /dev/null +++ b/SOURCES/glibc-RHEL-16016-2.patch @@ -0,0 +1,24 @@ +commit 5ab9b2c92411eb52f7b7a8e6074f0740d9bd727b +Author: Joseph Myers +Date: Tue Dec 20 15:24:29 2022 +0000 + + Update syscall lists for Linux 6.1 + + Linux 6.1 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 6.1. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 4a78258646..1274d9cd4a 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.0. +-kernel 6.0 ++# The list of system calls is current as of Linux 6.1. ++kernel 6.1 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-RHEL-16016-3.patch b/SOURCES/glibc-RHEL-16016-3.patch new file mode 100644 index 0000000..9e9fd03 --- /dev/null +++ b/SOURCES/glibc-RHEL-16016-3.patch @@ -0,0 +1,26 @@ +commit f8e8effa2629c74769a3552aba33175746b710bb +Author: Joseph Myers +Date: Thu Feb 23 22:53:17 2023 +0000 + + Update syscall lists for Linux 6.2 + + Linux 6.2 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 6.2. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 822498d3e3..5d27b5279c 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.1. +-kernel 6.1 ++# The list of system calls is current as of Linux 6.2. ++kernel 6.2 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-RHEL-16016-4.patch b/SOURCES/glibc-RHEL-16016-4.patch new file mode 100644 index 0000000..b043c5c --- /dev/null +++ b/SOURCES/glibc-RHEL-16016-4.patch @@ -0,0 +1,26 @@ +commit eeef96f56ce399f2c3fc1d93c0ba1dde34f3ae41 +Author: Joseph Myers +Date: Mon May 15 22:26:56 2023 +0000 + + Update syscall lists for Linux 6.3 + + Linux 6.3 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 6.3. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 5d27b5279c..72fe1d5efe 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.2. +-kernel 6.2 ++# The list of system calls is current as of Linux 6.3. ++kernel 6.3 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-RHEL-16016-5.patch b/SOURCES/glibc-RHEL-16016-5.patch new file mode 100644 index 0000000..8bf1ec7 --- /dev/null +++ b/SOURCES/glibc-RHEL-16016-5.patch @@ -0,0 +1,83 @@ +commit 1a21693e16a3f3d10f41c486b97fbecb53dd2087 +Author: Joseph Myers +Date: Wed Jun 28 21:22:14 2023 +0000 + + Update syscall lists for Linux 6.4 + + Linux 6.4 adds the riscv_hwprobe syscall on riscv and enables + memfd_secret on s390. Update syscall-names.list and regenerate the + arch-syscall.h headers with build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index 202520ee25..2416e041c8 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -198,6 +198,7 @@ + #define __NR_request_key 218 + #define __NR_restart_syscall 128 + #define __NR_riscv_flush_icache 259 ++#define __NR_riscv_hwprobe 258 + #define __NR_rseq 293 + #define __NR_rt_sigaction 134 + #define __NR_rt_sigpending 136 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index 4e65f337d4..a32bc82f60 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -205,6 +205,7 @@ + #define __NR_request_key 218 + #define __NR_restart_syscall 128 + #define __NR_riscv_flush_icache 259 ++#define __NR_riscv_hwprobe 258 + #define __NR_rseq 293 + #define __NR_rt_sigaction 134 + #define __NR_rt_sigpending 136 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +index 57025107e8..2288f20e45 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +@@ -178,6 +178,7 @@ + #define __NR_mbind 268 + #define __NR_membarrier 356 + #define __NR_memfd_create 350 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 287 + #define __NR_mincore 218 + #define __NR_mkdir 39 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +index 72e19c6d56..05e6d8428e 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +@@ -152,6 +152,7 @@ + #define __NR_mbind 268 + #define __NR_membarrier 356 + #define __NR_memfd_create 350 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 287 + #define __NR_mincore 218 + #define __NR_mkdir 39 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 72fe1d5efe..5b69106434 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.3. +-kernel 6.3 ++# The list of system calls is current as of Linux 6.4. ++kernel 6.4 + + FAST_atomic_update + FAST_cmpxchg +@@ -477,6 +477,7 @@ renameat2 + request_key + restart_syscall + riscv_flush_icache ++riscv_hwprobe + rmdir + rseq + rt_sigaction diff --git a/SOURCES/glibc-RHEL-16016-6.patch b/SOURCES/glibc-RHEL-16016-6.patch new file mode 100644 index 0000000..342a502 --- /dev/null +++ b/SOURCES/glibc-RHEL-16016-6.patch @@ -0,0 +1,338 @@ +commit 72511f539cc34681ec61c6a0dc2fe6d684760ffe +Author: Joseph Myers +Date: Tue Sep 12 14:08:53 2023 +0000 + + Update syscall lists for Linux 6.5 + + Linux 6.5 has one new syscall, cachestat, and also enables the + cacheflush syscall for hppa. Update syscall-names.list and regenerate + the arch-syscall.h headers with build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + + Conflicts: Removed loongarch, or1k + +diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +index 4fcb6da80a..8f21ee66a0 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +@@ -7,6 +7,7 @@ + #define __NR_bind 200 + #define __NR_bpf 280 + #define __NR_brk 214 ++#define __NR_cachestat 451 + #define __NR_capget 90 + #define __NR_capset 91 + #define __NR_chdir 49 +diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +index 0cf74c1a96..c5802a5fec 100644 +--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +@@ -11,6 +11,7 @@ + #define __NR_bind 104 + #define __NR_bpf 515 + #define __NR_brk 17 ++#define __NR_cachestat 561 + #define __NR_capget 368 + #define __NR_capset 369 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +index c1207aaa12..f23f9e1154 100644 +--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +@@ -11,6 +11,7 @@ + #define __NR_bpf 280 + #define __NR_brk 214 + #define __NR_cacheflush 244 ++#define __NR_cachestat 451 + #define __NR_capget 90 + #define __NR_capset 91 + #define __NR_chdir 49 +diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +index e7ba04c106..7edf574899 100644 +--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +@@ -15,6 +15,7 @@ + #define __NR_bpf 386 + #define __NR_brk 45 + #define __NR_cacheflush 983042 ++#define __NR_cachestat 451 + #define __NR_capget 184 + #define __NR_capset 185 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +index dc9383758e..d74a06e063 100644 +--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +@@ -8,6 +8,7 @@ + #define __NR_bpf 280 + #define __NR_brk 214 + #define __NR_cacheflush 245 ++#define __NR_cachestat 451 + #define __NR_capget 90 + #define __NR_capset 91 + #define __NR_chdir 49 +diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +index 767f1287a3..5568b94cd3 100644 +--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +@@ -13,6 +13,8 @@ + #define __NR_bind 22 + #define __NR_bpf 341 + #define __NR_brk 45 ++#define __NR_cacheflush 356 ++#define __NR_cachestat 451 + #define __NR_capget 106 + #define __NR_capset 107 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +index 1998f0d76a..3af21a15cb 100644 +--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +@@ -15,6 +15,7 @@ + #define __NR_bpf 357 + #define __NR_break 17 + #define __NR_brk 45 ++#define __NR_cachestat 451 + #define __NR_capget 184 + #define __NR_capset 185 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h +index b2eab1b93d..39b270e642 100644 +--- a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h +@@ -11,6 +11,7 @@ + #define __NR_bind 1191 + #define __NR_bpf 1341 + #define __NR_brk 1060 ++#define __NR_cachestat 1475 + #define __NR_capget 1185 + #define __NR_capset 1186 + #define __NR_chdir 1034 +diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +index 5fc3723772..315e49cd33 100644 +--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +@@ -15,6 +15,7 @@ + #define __NR_bpf 354 + #define __NR_brk 45 + #define __NR_cacheflush 123 ++#define __NR_cachestat 451 + #define __NR_capget 184 + #define __NR_capset 185 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +index b6e9b007e4..54af12780c 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +@@ -15,6 +15,7 @@ + #define __NR_bpf 387 + #define __NR_break 17 + #define __NR_brk 45 ++#define __NR_cachestat 451 + #define __NR_capget 184 + #define __NR_capset 185 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +index b3a3871f8a..a2aa1ffa1b 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +@@ -17,6 +17,7 @@ + #define __NR_brk 4045 + #define __NR_cachectl 4148 + #define __NR_cacheflush 4147 ++#define __NR_cachestat 4451 + #define __NR_capget 4204 + #define __NR_capset 4205 + #define __NR_chdir 4012 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +index b462182723..5bec858040 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +@@ -14,6 +14,7 @@ + #define __NR_brk 6012 + #define __NR_cachectl 6198 + #define __NR_cacheflush 6197 ++#define __NR_cachestat 6451 + #define __NR_capget 6123 + #define __NR_capset 6124 + #define __NR_chdir 6078 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +index a9d6b94572..0166371ee2 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +@@ -14,6 +14,7 @@ + #define __NR_brk 5012 + #define __NR_cachectl 5198 + #define __NR_cacheflush 5197 ++#define __NR_cachestat 5451 + #define __NR_capget 5123 + #define __NR_capset 5124 + #define __NR_chdir 5078 +diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +index 809a219ef3..29a4cfa988 100644 +--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +@@ -8,6 +8,7 @@ + #define __NR_bpf 280 + #define __NR_brk 214 + #define __NR_cacheflush 244 ++#define __NR_cachestat 451 + #define __NR_capget 90 + #define __NR_capset 91 + #define __NR_chdir 49 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +index 627831ebae..3a212a0269 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +@@ -15,6 +15,7 @@ + #define __NR_bpf 361 + #define __NR_break 17 + #define __NR_brk 45 ++#define __NR_cachestat 451 + #define __NR_capget 183 + #define __NR_capset 184 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +index bae597199d..1038ead227 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +@@ -15,6 +15,7 @@ + #define __NR_bpf 361 + #define __NR_break 17 + #define __NR_brk 45 ++#define __NR_cachestat 451 + #define __NR_capget 183 + #define __NR_capset 184 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index 2416e041c8..57b043ffb5 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -6,6 +6,7 @@ + #define __NR_bind 200 + #define __NR_bpf 280 + #define __NR_brk 214 ++#define __NR_cachestat 451 + #define __NR_capget 90 + #define __NR_capset 91 + #define __NR_chdir 49 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index a32bc82f60..1041a0f8c9 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -7,6 +7,7 @@ + #define __NR_bind 200 + #define __NR_bpf 280 + #define __NR_brk 214 ++#define __NR_cachestat 451 + #define __NR_capget 90 + #define __NR_capset 91 + #define __NR_chdir 49 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +index 2288f20e45..70d4c6782e 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +@@ -13,6 +13,7 @@ + #define __NR_bind 361 + #define __NR_bpf 351 + #define __NR_brk 45 ++#define __NR_cachestat 451 + #define __NR_capget 184 + #define __NR_capset 185 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +index 05e6d8428e..65a8a9e316 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +@@ -11,6 +11,7 @@ + #define __NR_bind 361 + #define __NR_bpf 351 + #define __NR_brk 45 ++#define __NR_cachestat 451 + #define __NR_capget 184 + #define __NR_capset 185 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +index d52b522d9c..94aad0f119 100644 +--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +@@ -14,6 +14,7 @@ + #define __NR_bpf 375 + #define __NR_brk 45 + #define __NR_cacheflush 123 ++#define __NR_cachestat 451 + #define __NR_capget 184 + #define __NR_capset 185 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +index d3f4d8aa3e..d630306c75 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +@@ -14,6 +14,7 @@ + #define __NR_bind 353 + #define __NR_bpf 349 + #define __NR_brk 17 ++#define __NR_cachestat 451 + #define __NR_capget 21 + #define __NR_capset 22 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +index 2cc03d7a24..930f29b4d2 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +@@ -14,6 +14,7 @@ + #define __NR_bind 353 + #define __NR_bpf 349 + #define __NR_brk 17 ++#define __NR_cachestat 451 + #define __NR_capget 21 + #define __NR_capset 22 + #define __NR_chdir 12 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 5b69106434..cf6f70ecd9 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.4. +-kernel 6.4 ++# The list of system calls is current as of Linux 6.5. ++kernel 6.5 + + FAST_atomic_update + FAST_cmpxchg +@@ -58,6 +58,7 @@ breakpoint + brk + cachectl + cacheflush ++cachestat + capget + capset + chdir +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index b4ab892ec1..58646cf0bd 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -12,6 +12,7 @@ + #define __NR_bind 49 + #define __NR_bpf 321 + #define __NR_brk 12 ++#define __NR_cachestat 451 + #define __NR_capget 125 + #define __NR_capset 126 + #define __NR_chdir 80 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index 772559c87b..604bcdfa5b 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -11,6 +11,7 @@ + #define __NR_bind 1073741873 + #define __NR_bpf 1073742145 + #define __NR_brk 1073741836 ++#define __NR_cachestat 1073742275 + #define __NR_capget 1073741949 + #define __NR_capset 1073741950 + #define __NR_chdir 1073741904 diff --git a/SOURCES/glibc-RHEL-16016-7.patch b/SOURCES/glibc-RHEL-16016-7.patch new file mode 100644 index 0000000..0257087 --- /dev/null +++ b/SOURCES/glibc-RHEL-16016-7.patch @@ -0,0 +1,350 @@ +commit 582383b37d95b133c1ee6855ffaa2b1f5cb3d3b8 +Author: Adhemerval Zanella +Date: Tue Oct 31 13:32:33 2023 -0300 + + Update syscall lists for Linux 6.6 + + Linux 6.6 has one new syscall for all architectures, fchmodat2, and + the map_shadow_stack on x86_64. + + Conflicts: Removed loongarch, or1k + +diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +index 8f21ee66a0..746991aa2f 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +@@ -44,6 +44,7 @@ + #define __NR_fchdir 50 + #define __NR_fchmod 52 + #define __NR_fchmodat 53 ++#define __NR_fchmodat2 452 + #define __NR_fchown 55 + #define __NR_fchownat 54 + #define __NR_fcntl 25 +diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +index c5802a5fec..32efe51267 100644 +--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +@@ -56,6 +56,7 @@ + #define __NR_fchdir 13 + #define __NR_fchmod 124 + #define __NR_fchmodat 461 ++#define __NR_fchmodat2 562 + #define __NR_fchown 123 + #define __NR_fchownat 453 + #define __NR_fcntl 92 +diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +index f23f9e1154..1d2879e877 100644 +--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +@@ -48,6 +48,7 @@ + #define __NR_fchdir 50 + #define __NR_fchmod 52 + #define __NR_fchmodat 53 ++#define __NR_fchmodat2 452 + #define __NR_fchown 55 + #define __NR_fchownat 54 + #define __NR_fcntl64 25 +diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +index 7edf574899..6711981e78 100644 +--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +@@ -64,6 +64,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 333 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchown32 207 + #define __NR_fchownat 325 +diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +index d74a06e063..92d9a703ea 100644 +--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +@@ -50,6 +50,7 @@ + #define __NR_fchdir 50 + #define __NR_fchmod 52 + #define __NR_fchmodat 53 ++#define __NR_fchmodat2 452 + #define __NR_fchown 55 + #define __NR_fchownat 54 + #define __NR_fcntl64 25 +diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +index 5568b94cd3..fbac124b70 100644 +--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +@@ -63,6 +63,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 286 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchownat 278 + #define __NR_fcntl 55 +diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +index 3af21a15cb..8961788a96 100644 +--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +@@ -67,6 +67,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 306 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchown32 207 + #define __NR_fchownat 298 +diff --git a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h +index 39b270e642..1ef762d693 100644 +--- a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h +@@ -55,6 +55,7 @@ + #define __NR_fchdir 1035 + #define __NR_fchmod 1099 + #define __NR_fchmodat 1292 ++#define __NR_fchmodat2 1476 + #define __NR_fchown 1100 + #define __NR_fchownat 1284 + #define __NR_fcntl 1066 +diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +index 315e49cd33..2053d5d392 100644 +--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +@@ -67,6 +67,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 299 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchown32 207 + #define __NR_fchownat 291 +diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +index 54af12780c..6865b1693c 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +@@ -67,6 +67,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 306 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchown32 207 + #define __NR_fchownat 298 +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +index a2aa1ffa1b..b13ace8e1c 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +@@ -67,6 +67,7 @@ + #define __NR_fchdir 4133 + #define __NR_fchmod 4094 + #define __NR_fchmodat 4299 ++#define __NR_fchmodat2 4452 + #define __NR_fchown 4095 + #define __NR_fchownat 4291 + #define __NR_fcntl 4055 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +index 5bec858040..b7a7c0dfa7 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +@@ -64,6 +64,7 @@ + #define __NR_fchdir 6079 + #define __NR_fchmod 6089 + #define __NR_fchmodat 6262 ++#define __NR_fchmodat2 6452 + #define __NR_fchown 6091 + #define __NR_fchownat 6254 + #define __NR_fcntl 6070 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +index 0166371ee2..e5d7f91f48 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +@@ -59,6 +59,7 @@ + #define __NR_fchdir 5079 + #define __NR_fchmod 5089 + #define __NR_fchmodat 5258 ++#define __NR_fchmodat2 5452 + #define __NR_fchown 5091 + #define __NR_fchownat 5250 + #define __NR_fcntl 5070 +diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +index 29a4cfa988..89950cc33a 100644 +--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +@@ -49,6 +49,7 @@ + #define __NR_fchdir 50 + #define __NR_fchmod 52 + #define __NR_fchmodat 53 ++#define __NR_fchmodat2 452 + #define __NR_fchown 55 + #define __NR_fchownat 54 + #define __NR_fcntl64 25 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +index 3a212a0269..64683bcb76 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +@@ -66,6 +66,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 297 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchownat 289 + #define __NR_fcntl 55 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +index 1038ead227..af1bbf32e8 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +@@ -60,6 +60,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 297 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchownat 289 + #define __NR_fcntl 55 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index 57b043ffb5..56e3088cbf 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -43,6 +43,7 @@ + #define __NR_fchdir 50 + #define __NR_fchmod 52 + #define __NR_fchmodat 53 ++#define __NR_fchmodat2 452 + #define __NR_fchown 55 + #define __NR_fchownat 54 + #define __NR_fcntl64 25 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index 1041a0f8c9..508161b47a 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -44,6 +44,7 @@ + #define __NR_fchdir 50 + #define __NR_fchmod 52 + #define __NR_fchmodat 53 ++#define __NR_fchmodat2 452 + #define __NR_fchown 55 + #define __NR_fchownat 54 + #define __NR_fcntl 25 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +index 70d4c6782e..1498ebf42e 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +@@ -65,6 +65,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 299 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchown32 207 + #define __NR_fchownat 291 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +index 65a8a9e316..624d71b56d 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +@@ -56,6 +56,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 299 ++#define __NR_fchmodat2 452 + #define __NR_fchown 207 + #define __NR_fchownat 291 + #define __NR_fcntl 55 +diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +index 94aad0f119..37211f5f8c 100644 +--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +@@ -64,6 +64,7 @@ + #define __NR_fchdir 133 + #define __NR_fchmod 94 + #define __NR_fchmodat 306 ++#define __NR_fchmodat2 452 + #define __NR_fchown 95 + #define __NR_fchown32 207 + #define __NR_fchownat 298 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +index d630306c75..8093abcc9c 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +@@ -66,6 +66,7 @@ + #define __NR_fchdir 176 + #define __NR_fchmod 124 + #define __NR_fchmodat 295 ++#define __NR_fchmodat2 452 + #define __NR_fchown 123 + #define __NR_fchown32 32 + #define __NR_fchownat 287 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +index 930f29b4d2..d25ccfb571 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +@@ -60,6 +60,7 @@ + #define __NR_fchdir 176 + #define __NR_fchmod 124 + #define __NR_fchmodat 295 ++#define __NR_fchmodat2 452 + #define __NR_fchown 123 + #define __NR_fchownat 287 + #define __NR_fcntl 92 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index cf6f70ecd9..c3627fcd7f 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.5. +-kernel 6.5 ++# The list of system calls is current as of Linux 6.6. ++kernel 6.6 + + FAST_atomic_update + FAST_cmpxchg +@@ -117,6 +117,7 @@ fanotify_mark + fchdir + fchmod + fchmodat ++fchmodat2 + fchown + fchown32 + fchownat +@@ -246,6 +247,7 @@ lsetxattr + lstat + lstat64 + madvise ++map_shadow_stack + mbind + membarrier + memfd_create +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index 58646cf0bd..5e4c9e901c 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -59,6 +59,7 @@ + #define __NR_fchdir 81 + #define __NR_fchmod 91 + #define __NR_fchmodat 268 ++#define __NR_fchmodat2 452 + #define __NR_fchown 93 + #define __NR_fchownat 260 + #define __NR_fcntl 72 +@@ -153,6 +154,7 @@ + #define __NR_lsetxattr 189 + #define __NR_lstat 6 + #define __NR_madvise 28 ++#define __NR_map_shadow_stack 453 + #define __NR_mbind 237 + #define __NR_membarrier 324 + #define __NR_memfd_create 319 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index 604bcdfa5b..dd5e196272 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -55,6 +55,7 @@ + #define __NR_fchdir 1073741905 + #define __NR_fchmod 1073741915 + #define __NR_fchmodat 1073742092 ++#define __NR_fchmodat2 1073742276 + #define __NR_fchown 1073741917 + #define __NR_fchownat 1073742084 + #define __NR_fcntl 1073741896 diff --git a/SOURCES/glibc-RHEL-16275.patch b/SOURCES/glibc-RHEL-16275.patch new file mode 100644 index 0000000..c773796 --- /dev/null +++ b/SOURCES/glibc-RHEL-16275.patch @@ -0,0 +1,16 @@ +Downstream-only patch to refer to /run instead of the legacy /var/run +directory in the downstream nscd systemd socket file. + +diff --git a/nscd/nscd.socket b/nscd/nscd.socket +index 7e512d5339fa1136..52a67608c7c55475 100644 +--- a/nscd/nscd.socket ++++ b/nscd/nscd.socket +@@ -2,7 +2,7 @@ + Description=Name Service Cache Daemon Socket + + [Socket] +-ListenDatagram=/var/run/nscd/socket ++ListenDatagram=/run/nscd/socket + + [Install] + WantedBy=sockets.target diff --git a/SOURCES/glibc-RHEL-16643-1.patch b/SOURCES/glibc-RHEL-16643-1.patch new file mode 100644 index 0000000..d8d33c3 --- /dev/null +++ b/SOURCES/glibc-RHEL-16643-1.patch @@ -0,0 +1,211 @@ +commit 06890c7ba553e82393413c59bb3131db5815a337 +Author: Siddhesh Poyarekar +Date: Tue Jul 27 22:49:53 2021 +0530 + + gaiconf_init: Refactor some bits for readability + + Split out line processing for `label`, `precedence` and `scopev4` into + separate functions instead of the gotos. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index d6046a707f1d742a..3bf9a8bae16a5b02 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -1858,6 +1858,66 @@ scopecmp (const void *p1, const void *p2) + return 1; + } + ++static bool ++add_prefixlist (struct prefixlist **listp, size_t *lenp, bool *nullbitsp, ++ char *val1, char *val2, char **pos) ++{ ++ struct in6_addr prefix; ++ unsigned long int bits; ++ unsigned long int val; ++ char *endp; ++ ++ bits = 128; ++ __set_errno (0); ++ char *cp = strchr (val1, '/'); ++ if (cp != NULL) ++ *cp++ = '\0'; ++ *pos = cp; ++ if (inet_pton (AF_INET6, val1, &prefix) ++ && (cp == NULL ++ || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX ++ || errno != ERANGE) ++ && *endp == '\0' ++ && bits <= 128 ++ && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX ++ || errno != ERANGE) ++ && *endp == '\0' ++ && val <= INT_MAX) ++ { ++ struct prefixlist *newp = malloc (sizeof (*newp)); ++ if (newp == NULL) ++ return false; ++ ++ memcpy (&newp->entry.prefix, &prefix, sizeof (prefix)); ++ newp->entry.bits = bits; ++ newp->entry.val = val; ++ newp->next = *listp; ++ *listp = newp; ++ ++*lenp; ++ *nullbitsp |= bits == 0; ++ } ++ return true; ++} ++ ++static bool ++add_scopelist (struct scopelist **listp, size_t *lenp, bool *nullbitsp, ++ const struct in6_addr *prefixp, unsigned long int bits, ++ unsigned long int val) ++{ ++ struct scopelist *newp = malloc (sizeof (*newp)); ++ if (newp == NULL) ++ return false; ++ ++ newp->entry.netmask = htonl (bits != 96 ? (0xffffffff << (128 - bits)) : 0); ++ newp->entry.addr32 = (prefixp->s6_addr32[3] & newp->entry.netmask); ++ newp->entry.scope = val; ++ newp->next = *listp; ++ *listp = newp; ++ ++*lenp; ++ *nullbitsp |= bits == 96; ++ ++ return true; ++} + + static void + gaiconf_init (void) +@@ -1933,55 +1993,17 @@ gaiconf_init (void) + /* Ignore the rest of the line. */ + *cp = '\0'; + +- struct prefixlist **listp; +- size_t *lenp; +- bool *nullbitsp; + switch (cmdlen) + { + case 5: + if (strcmp (cmd, "label") == 0) + { +- struct in6_addr prefix; +- unsigned long int bits; +- unsigned long int val; +- char *endp; +- +- listp = &labellist; +- lenp = &nlabellist; +- nullbitsp = &labellist_nullbits; +- +- new_elem: +- bits = 128; +- __set_errno (0); +- cp = strchr (val1, '/'); +- if (cp != NULL) +- *cp++ = '\0'; +- if (inet_pton (AF_INET6, val1, &prefix) +- && (cp == NULL +- || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX +- || errno != ERANGE) +- && *endp == '\0' +- && bits <= 128 +- && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX +- || errno != ERANGE) +- && *endp == '\0' +- && val <= INT_MAX) ++ if (!add_prefixlist (&labellist, &nlabellist, ++ &labellist_nullbits, val1, val2, &cp)) + { +- struct prefixlist *newp = malloc (sizeof (*newp)); +- if (newp == NULL) +- { +- free (line); +- fclose (fp); +- goto no_file; +- } +- +- memcpy (&newp->entry.prefix, &prefix, sizeof (prefix)); +- newp->entry.bits = bits; +- newp->entry.val = val; +- newp->next = *listp; +- *listp = newp; +- ++*lenp; +- *nullbitsp |= bits == 0; ++ free (line); ++ fclose (fp); ++ goto no_file; + } + } + break; +@@ -2023,27 +2045,14 @@ gaiconf_init (void) + && *endp == '\0' + && val <= INT_MAX) + { +- struct scopelist *newp; +- new_scope: +- newp = malloc (sizeof (*newp)); +- if (newp == NULL) ++ if (!add_scopelist (&scopelist, &nscopelist, ++ &scopelist_nullbits, &prefix, ++ bits, val)) + { + free (line); + fclose (fp); + goto no_file; + } +- +- newp->entry.netmask = htonl (bits != 96 +- ? (0xffffffff +- << (128 - bits)) +- : 0); +- newp->entry.addr32 = (prefix.s6_addr32[3] +- & newp->entry.netmask); +- newp->entry.scope = val; +- newp->next = scopelist; +- scopelist = newp; +- ++nscopelist; +- scopelist_nullbits |= bits == 96; + } + } + else if (inet_pton (AF_INET, val1, &prefix.s6_addr32[3]) +@@ -2057,8 +2066,14 @@ gaiconf_init (void) + && *endp == '\0' + && val <= INT_MAX) + { +- bits += 96; +- goto new_scope; ++ if (!add_scopelist (&scopelist, &nscopelist, ++ &scopelist_nullbits, &prefix, ++ bits + 96, val)) ++ { ++ free (line); ++ fclose (fp); ++ goto no_file; ++ } + } + } + break; +@@ -2066,10 +2081,14 @@ gaiconf_init (void) + case 10: + if (strcmp (cmd, "precedence") == 0) + { +- listp = &precedencelist; +- lenp = &nprecedencelist; +- nullbitsp = &precedencelist_nullbits; +- goto new_elem; ++ if (!add_prefixlist (&precedencelist, &nprecedencelist, ++ &precedencelist_nullbits, val1, val2, ++ &cp)) ++ { ++ free (line); ++ fclose (fp); ++ goto no_file; ++ } + } + break; + } diff --git a/SOURCES/glibc-RHEL-16643-2.patch b/SOURCES/glibc-RHEL-16643-2.patch new file mode 100644 index 0000000..ed0a98c --- /dev/null +++ b/SOURCES/glibc-RHEL-16643-2.patch @@ -0,0 +1,584 @@ +commit bc0d18d873abf2cda6842ad8bb4df2a31dc0fbac +Author: Siddhesh Poyarekar +Date: Tue Aug 3 21:29:23 2021 +0530 + + gai_init: Avoid jumping from if condition to its else counterpart + + Clean up another antipattern where code flows from an if condition to + its else counterpart with a goto. + + Most of the change in this patch is whitespace-only; a `git diff -b` + ought to show the actual logic changes. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 3bf9a8bae16a5b02..1635a09837351068 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -1933,142 +1933,122 @@ gaiconf_init (void) + bool scopelist_nullbits = false; + + FILE *fp = fopen (GAICONF_FNAME, "rce"); +- if (fp != NULL) ++ if (fp == NULL) ++ goto no_file; ++ ++ struct __stat64_t64 st; ++ if (__fstat64_time64 (fileno (fp), &st) != 0) + { +- struct __stat64_t64 st; +- if (__fstat64_time64 (fileno (fp), &st) != 0) +- { +- fclose (fp); +- goto no_file; +- } ++ fclose (fp); ++ goto no_file; ++ } + +- char *line = NULL; +- size_t linelen = 0; ++ char *line = NULL; ++ size_t linelen = 0; + +- __fsetlocking (fp, FSETLOCKING_BYCALLER); ++ __fsetlocking (fp, FSETLOCKING_BYCALLER); + +- while (!feof_unlocked (fp)) +- { +- ssize_t n = __getline (&line, &linelen, fp); +- if (n <= 0) +- break; ++ while (!feof_unlocked (fp)) ++ { ++ ssize_t n = __getline (&line, &linelen, fp); ++ if (n <= 0) ++ break; + +- /* Handle comments. No escaping possible so this is easy. */ +- char *cp = strchr (line, '#'); +- if (cp != NULL) +- *cp = '\0'; ++ /* Handle comments. No escaping possible so this is easy. */ ++ char *cp = strchr (line, '#'); ++ if (cp != NULL) ++ *cp = '\0'; + +- cp = line; +- while (isspace (*cp)) +- ++cp; ++ cp = line; ++ while (isspace (*cp)) ++ ++cp; + +- char *cmd = cp; +- while (*cp != '\0' && !isspace (*cp)) +- ++cp; +- size_t cmdlen = cp - cmd; ++ char *cmd = cp; ++ while (*cp != '\0' && !isspace (*cp)) ++ ++cp; ++ size_t cmdlen = cp - cmd; + +- if (*cp != '\0') +- *cp++ = '\0'; +- while (isspace (*cp)) +- ++cp; ++ if (*cp != '\0') ++ *cp++ = '\0'; ++ while (isspace (*cp)) ++ ++cp; + +- char *val1 = cp; +- while (*cp != '\0' && !isspace (*cp)) +- ++cp; +- size_t val1len = cp - cmd; ++ char *val1 = cp; ++ while (*cp != '\0' && !isspace (*cp)) ++ ++cp; ++ size_t val1len = cp - cmd; + +- /* We always need at least two values. */ +- if (val1len == 0) +- continue; ++ /* We always need at least two values. */ ++ if (val1len == 0) ++ continue; + +- if (*cp != '\0') +- *cp++ = '\0'; +- while (isspace (*cp)) +- ++cp; ++ if (*cp != '\0') ++ *cp++ = '\0'; ++ while (isspace (*cp)) ++ ++cp; + +- char *val2 = cp; +- while (*cp != '\0' && !isspace (*cp)) +- ++cp; ++ char *val2 = cp; ++ while (*cp != '\0' && !isspace (*cp)) ++ ++cp; + +- /* Ignore the rest of the line. */ +- *cp = '\0'; ++ /* Ignore the rest of the line. */ ++ *cp = '\0'; + +- switch (cmdlen) ++ switch (cmdlen) ++ { ++ case 5: ++ if (strcmp (cmd, "label") == 0) + { +- case 5: +- if (strcmp (cmd, "label") == 0) ++ if (!add_prefixlist (&labellist, &nlabellist, ++ &labellist_nullbits, val1, val2, &cp)) + { +- if (!add_prefixlist (&labellist, &nlabellist, +- &labellist_nullbits, val1, val2, &cp)) +- { +- free (line); +- fclose (fp); +- goto no_file; +- } ++ free (line); ++ fclose (fp); ++ goto no_file; + } +- break; ++ } ++ break; + +- case 6: +- if (strcmp (cmd, "reload") == 0) +- { +- gaiconf_reload_flag = strcmp (val1, "yes") == 0; +- if (gaiconf_reload_flag) +- gaiconf_reload_flag_ever_set = 1; +- } +- break; ++ case 6: ++ if (strcmp (cmd, "reload") == 0) ++ { ++ gaiconf_reload_flag = strcmp (val1, "yes") == 0; ++ if (gaiconf_reload_flag) ++ gaiconf_reload_flag_ever_set = 1; ++ } ++ break; + +- case 7: +- if (strcmp (cmd, "scopev4") == 0) ++ case 7: ++ if (strcmp (cmd, "scopev4") == 0) ++ { ++ struct in6_addr prefix; ++ unsigned long int bits; ++ unsigned long int val; ++ char *endp; ++ ++ bits = 32; ++ __set_errno (0); ++ cp = strchr (val1, '/'); ++ if (cp != NULL) ++ *cp++ = '\0'; ++ if (inet_pton (AF_INET6, val1, &prefix)) + { +- struct in6_addr prefix; +- unsigned long int bits; +- unsigned long int val; +- char *endp; +- +- bits = 32; +- __set_errno (0); +- cp = strchr (val1, '/'); +- if (cp != NULL) +- *cp++ = '\0'; +- if (inet_pton (AF_INET6, val1, &prefix)) +- { +- bits = 128; +- if (IN6_IS_ADDR_V4MAPPED (&prefix) +- && (cp == NULL +- || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX +- || errno != ERANGE) +- && *endp == '\0' +- && bits >= 96 +- && bits <= 128 +- && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX +- || errno != ERANGE) +- && *endp == '\0' +- && val <= INT_MAX) +- { +- if (!add_scopelist (&scopelist, &nscopelist, +- &scopelist_nullbits, &prefix, +- bits, val)) +- { +- free (line); +- fclose (fp); +- goto no_file; +- } +- } +- } +- else if (inet_pton (AF_INET, val1, &prefix.s6_addr32[3]) +- && (cp == NULL +- || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX +- || errno != ERANGE) +- && *endp == '\0' +- && bits <= 32 +- && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX +- || errno != ERANGE) +- && *endp == '\0' +- && val <= INT_MAX) ++ bits = 128; ++ if (IN6_IS_ADDR_V4MAPPED (&prefix) ++ && (cp == NULL ++ || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX ++ || errno != ERANGE) ++ && *endp == '\0' ++ && bits >= 96 ++ && bits <= 128 ++ && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX ++ || errno != ERANGE) ++ && *endp == '\0' ++ && val <= INT_MAX) + { + if (!add_scopelist (&scopelist, &nscopelist, + &scopelist_nullbits, &prefix, +- bits + 96, val)) ++ bits, val)) + { + free (line); + fclose (fp); +@@ -2076,173 +2056,191 @@ gaiconf_init (void) + } + } + } +- break; +- +- case 10: +- if (strcmp (cmd, "precedence") == 0) ++ else if (inet_pton (AF_INET, val1, &prefix.s6_addr32[3]) ++ && (cp == NULL ++ || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX ++ || errno != ERANGE) ++ && *endp == '\0' ++ && bits <= 32 ++ && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX ++ || errno != ERANGE) ++ && *endp == '\0' ++ && val <= INT_MAX) + { +- if (!add_prefixlist (&precedencelist, &nprecedencelist, +- &precedencelist_nullbits, val1, val2, +- &cp)) ++ if (!add_scopelist (&scopelist, &nscopelist, ++ &scopelist_nullbits, &prefix, ++ bits + 96, val)) + { + free (line); + fclose (fp); + goto no_file; + } + } +- break; +- } +- } +- +- free (line); +- +- fclose (fp); +- +- /* Create the array for the labels. */ +- struct prefixentry *new_labels; +- if (nlabellist > 0) +- { +- if (!labellist_nullbits) +- ++nlabellist; +- new_labels = malloc (nlabellist * sizeof (*new_labels)); +- if (new_labels == NULL) +- goto no_file; +- +- int i = nlabellist; +- if (!labellist_nullbits) +- { +- --i; +- memset (&new_labels[i].prefix, '\0', sizeof (struct in6_addr)); +- new_labels[i].bits = 0; +- new_labels[i].val = 1; + } ++ break; + +- struct prefixlist *l = labellist; +- while (i-- > 0) ++ case 10: ++ if (strcmp (cmd, "precedence") == 0) + { +- new_labels[i] = l->entry; +- l = l->next; ++ if (!add_prefixlist (&precedencelist, &nprecedencelist, ++ &precedencelist_nullbits, val1, val2, ++ &cp)) ++ { ++ free (line); ++ fclose (fp); ++ goto no_file; ++ } + } +- free_prefixlist (labellist); +- labellist = NULL; +- +- /* Sort the entries so that the most specific ones are at +- the beginning. */ +- qsort (new_labels, nlabellist, sizeof (*new_labels), prefixcmp); ++ break; + } +- else +- new_labels = (struct prefixentry *) default_labels; +- +- struct prefixentry *new_precedence; +- if (nprecedencelist > 0) +- { +- if (!precedencelist_nullbits) +- ++nprecedencelist; +- new_precedence = malloc (nprecedencelist * sizeof (*new_precedence)); +- if (new_precedence == NULL) +- { +- if (new_labels != default_labels) +- free (new_labels); +- goto no_file; +- } ++ } + +- int i = nprecedencelist; +- if (!precedencelist_nullbits) +- { +- --i; +- memset (&new_precedence[i].prefix, '\0', +- sizeof (struct in6_addr)); +- new_precedence[i].bits = 0; +- new_precedence[i].val = 40; +- } ++ free (line); + +- struct prefixlist *l = precedencelist; +- while (i-- > 0) +- { +- new_precedence[i] = l->entry; +- l = l->next; +- } +- free_prefixlist (precedencelist); +- precedencelist = NULL; ++ fclose (fp); + +- /* Sort the entries so that the most specific ones are at +- the beginning. */ +- qsort (new_precedence, nprecedencelist, sizeof (*new_precedence), +- prefixcmp); ++ /* Create the array for the labels. */ ++ struct prefixentry *new_labels; ++ if (nlabellist > 0) ++ { ++ if (!labellist_nullbits) ++ ++nlabellist; ++ new_labels = malloc (nlabellist * sizeof (*new_labels)); ++ if (new_labels == NULL) ++ goto no_file; ++ ++ int i = nlabellist; ++ if (!labellist_nullbits) ++ { ++ --i; ++ memset (&new_labels[i].prefix, '\0', sizeof (struct in6_addr)); ++ new_labels[i].bits = 0; ++ new_labels[i].val = 1; + } +- else +- new_precedence = (struct prefixentry *) default_precedence; + +- struct scopeentry *new_scopes; +- if (nscopelist > 0) ++ struct prefixlist *l = labellist; ++ while (i-- > 0) + { +- if (!scopelist_nullbits) +- ++nscopelist; +- new_scopes = malloc (nscopelist * sizeof (*new_scopes)); +- if (new_scopes == NULL) +- { +- if (new_labels != default_labels) +- free (new_labels); +- if (new_precedence != default_precedence) +- free (new_precedence); +- goto no_file; +- } +- +- int i = nscopelist; +- if (!scopelist_nullbits) +- { +- --i; +- new_scopes[i].addr32 = 0; +- new_scopes[i].netmask = 0; +- new_scopes[i].scope = 14; +- } ++ new_labels[i] = l->entry; ++ l = l->next; ++ } ++ free_prefixlist (labellist); ++ labellist = NULL; + +- struct scopelist *l = scopelist; +- while (i-- > 0) +- { +- new_scopes[i] = l->entry; +- l = l->next; +- } +- free_scopelist (scopelist); ++ /* Sort the entries so that the most specific ones are at ++ the beginning. */ ++ qsort (new_labels, nlabellist, sizeof (*new_labels), prefixcmp); ++ } ++ else ++ new_labels = (struct prefixentry *) default_labels; + +- /* Sort the entries so that the most specific ones are at +- the beginning. */ +- qsort (new_scopes, nscopelist, sizeof (*new_scopes), +- scopecmp); ++ struct prefixentry *new_precedence; ++ if (nprecedencelist > 0) ++ { ++ if (!precedencelist_nullbits) ++ ++nprecedencelist; ++ new_precedence = malloc (nprecedencelist * sizeof (*new_precedence)); ++ if (new_precedence == NULL) ++ { ++ if (new_labels != default_labels) ++ free (new_labels); ++ goto no_file; + } +- else +- new_scopes = (struct scopeentry *) default_scopes; +- +- /* Now we are ready to replace the values. */ +- const struct prefixentry *old = labels; +- labels = new_labels; +- if (old != default_labels) +- free ((void *) old); + +- old = precedence; +- precedence = new_precedence; +- if (old != default_precedence) +- free ((void *) old); ++ int i = nprecedencelist; ++ if (!precedencelist_nullbits) ++ { ++ --i; ++ memset (&new_precedence[i].prefix, '\0', ++ sizeof (struct in6_addr)); ++ new_precedence[i].bits = 0; ++ new_precedence[i].val = 40; ++ } + +- const struct scopeentry *oldscope = scopes; +- scopes = new_scopes; +- if (oldscope != default_scopes) +- free ((void *) oldscope); ++ struct prefixlist *l = precedencelist; ++ while (i-- > 0) ++ { ++ new_precedence[i] = l->entry; ++ l = l->next; ++ } ++ free_prefixlist (precedencelist); ++ precedencelist = NULL; + +- save_gaiconf_mtime (&st); ++ /* Sort the entries so that the most specific ones are at ++ the beginning. */ ++ qsort (new_precedence, nprecedencelist, sizeof (*new_precedence), ++ prefixcmp); + } + else ++ new_precedence = (struct prefixentry *) default_precedence; ++ ++ struct scopeentry *new_scopes; ++ if (nscopelist > 0) + { +- no_file: +- free_prefixlist (labellist); +- free_prefixlist (precedencelist); ++ if (!scopelist_nullbits) ++ ++nscopelist; ++ new_scopes = malloc (nscopelist * sizeof (*new_scopes)); ++ if (new_scopes == NULL) ++ { ++ if (new_labels != default_labels) ++ free (new_labels); ++ if (new_precedence != default_precedence) ++ free (new_precedence); ++ goto no_file; ++ } ++ ++ int i = nscopelist; ++ if (!scopelist_nullbits) ++ { ++ --i; ++ new_scopes[i].addr32 = 0; ++ new_scopes[i].netmask = 0; ++ new_scopes[i].scope = 14; ++ } ++ ++ struct scopelist *l = scopelist; ++ while (i-- > 0) ++ { ++ new_scopes[i] = l->entry; ++ l = l->next; ++ } + free_scopelist (scopelist); + +- /* If we previously read the file but it is gone now, free the +- old data and use the builtin one. Leave the reload flag +- alone. */ +- fini (); ++ /* Sort the entries so that the most specific ones are at ++ the beginning. */ ++ qsort (new_scopes, nscopelist, sizeof (*new_scopes), ++ scopecmp); + } ++ else ++ new_scopes = (struct scopeentry *) default_scopes; ++ ++ /* Now we are ready to replace the values. */ ++ const struct prefixentry *old = labels; ++ labels = new_labels; ++ if (old != default_labels) ++ free ((void *) old); ++ ++ old = precedence; ++ precedence = new_precedence; ++ if (old != default_precedence) ++ free ((void *) old); ++ ++ const struct scopeentry *oldscope = scopes; ++ scopes = new_scopes; ++ if (oldscope != default_scopes) ++ free ((void *) oldscope); ++ ++ save_gaiconf_mtime (&st); ++ return; ++ ++no_file: ++ free_prefixlist (labellist); ++ free_prefixlist (precedencelist); ++ free_scopelist (scopelist); ++ ++ /* If we previously read the file but it is gone now, free the old data and ++ use the builtin one. Leave the reload flag alone. */ ++ fini (); + } + + diff --git a/SOURCES/glibc-RHEL-16643-3.patch b/SOURCES/glibc-RHEL-16643-3.patch new file mode 100644 index 0000000..c9f092a --- /dev/null +++ b/SOURCES/glibc-RHEL-16643-3.patch @@ -0,0 +1,90 @@ +commit d3f2c2c8b57bdf9d963db8fa2372d6c1b86a337e +Author: Siddhesh Poyarekar +Date: Tue Mar 22 22:40:05 2022 +0530 + + getaddrinfo: Refactor code for readability + + The close_retry goto jump is confusing and clumsy to read, so refactor + the code a bit to make it easier to follow. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 1635a09837351068..5e9bd17eb949974c 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -2253,6 +2253,36 @@ gaiconf_reload (void) + gaiconf_init (); + } + ++static bool ++try_connect (int *fdp, int *afp, struct sockaddr_in6 *source_addrp, ++ const struct sockaddr *addr, socklen_t addrlen, int family) ++{ ++ int fd = *fdp; ++ int af = *afp; ++ socklen_t sl = sizeof (*source_addrp); ++ ++ while (true) ++ { ++ if (fd != -1 && __connect (fd, addr, addrlen) == 0 ++ && __getsockname (fd, (struct sockaddr *) source_addrp, &sl) == 0) ++ return true; ++ ++ if (errno == EAFNOSUPPORT && af == AF_INET6 && family == AF_INET) ++ { ++ /* This could mean IPv6 sockets are IPv6-only. */ ++ if (fd != -1) ++ __close_nocancel_nostatus (fd); ++ *afp = af = AF_INET; ++ *fdp = fd = __socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, ++ IPPROTO_IP); ++ continue; ++ } ++ ++ return false; ++ } ++ ++ __builtin_unreachable (); ++} + + int + getaddrinfo (const char *name, const char *service, +@@ -2443,7 +2473,6 @@ getaddrinfo (const char *name, const char *service, + if (fd == -1 || (af == AF_INET && q->ai_family == AF_INET6)) + { + if (fd != -1) +- close_retry: + __close_nocancel_nostatus (fd); + af = q->ai_family; + fd = __socket (af, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP); +@@ -2455,14 +2484,10 @@ getaddrinfo (const char *name, const char *service, + __connect (fd, &sa, sizeof (sa)); + } + +- socklen_t sl = sizeof (results[i].source_addr); +- if (fd != -1 +- && __connect (fd, q->ai_addr, q->ai_addrlen) == 0 +- && __getsockname (fd, +- (struct sockaddr *) &results[i].source_addr, +- &sl) == 0) ++ if (try_connect (&fd, &af, &results[i].source_addr, q->ai_addr, ++ q->ai_addrlen, q->ai_family)) + { +- results[i].source_addr_len = sl; ++ results[i].source_addr_len = sizeof (results[i].source_addr); + results[i].got_source_addr = true; + + if (in6ai != NULL) +@@ -2527,10 +2552,6 @@ getaddrinfo (const char *name, const char *service, + results[i].source_addr_len = sizeof (struct sockaddr_in); + } + } +- else if (errno == EAFNOSUPPORT && af == AF_INET6 +- && q->ai_family == AF_INET) +- /* This could mean IPv6 sockets are IPv6-only. */ +- goto close_retry; + else + /* Just make sure that if we have to process the same + address again we do not copy any memory. */ diff --git a/SOURCES/glibc-RHEL-16643-4.patch b/SOURCES/glibc-RHEL-16643-4.patch new file mode 100644 index 0000000..53429e7 --- /dev/null +++ b/SOURCES/glibc-RHEL-16643-4.patch @@ -0,0 +1,32 @@ +commit c9226c03da0276593a0918eaa9a14835183343e8 +Author: Jörg Sonnenberger +Date: Mon Sep 26 13:59:16 2022 -0400 + + get_nscd_addresses: Fix subscript typos [BZ #29605] + + Fix the subscript on air->family, which was accidentally set to COUNT + when it should have remained as I. + + Resolves: BZ #29605 + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 5e9bd17eb949974c..40a32a3de30cb294 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -549,11 +549,11 @@ get_nscd_addresses (const char *name, const struct addrinfo *req, + at[count].addr[2] = htonl (0xffff); + } + else if (req->ai_family == AF_UNSPEC +- || air->family[count] == req->ai_family) ++ || air->family[i] == req->ai_family) + { +- at[count].family = air->family[count]; ++ at[count].family = air->family[i]; + memcpy (at[count].addr, addrs, size); +- if (air->family[count] == AF_INET6) ++ if (air->family[i] == AF_INET6) + res->got_ipv6 = true; + } + at[count].next = at + count + 1; diff --git a/SOURCES/glibc-RHEL-16643-5.patch b/SOURCES/glibc-RHEL-16643-5.patch new file mode 100644 index 0000000..8b16670 --- /dev/null +++ b/SOURCES/glibc-RHEL-16643-5.patch @@ -0,0 +1,25 @@ +commit 3bf7bab88b0da01d4f5ef20afbbb45203185501e +Author: Siddhesh Poyarekar +Date: Tue Sep 5 17:04:05 2023 -0400 + + getcanonname: Fix a typo + + This code is generally unused in practice since there don't seem to be + any NSS modules that only implement _nss_MOD_gethostbyname2_r and not + _nss_MOD_gethostbyname3_r. + + Signed-off-by: Siddhesh Poyarekar + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 40a32a3de30cb294..e9f47aea358a3351 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -346,7 +346,7 @@ getcanonname (nss_action_list nip, const char *hname, const char *name) + string. */ + s = (char *) name; + } +- return __strdup (name); ++ return __strdup (s); + } + + /* Process looked up canonical name and if necessary, decode to IDNA. Result diff --git a/SOURCES/glibc-RHEL-16643-6.patch b/SOURCES/glibc-RHEL-16643-6.patch new file mode 100644 index 0000000..dd72b79 --- /dev/null +++ b/SOURCES/glibc-RHEL-16643-6.patch @@ -0,0 +1,23 @@ +commit 61bac1a9d2ab80ebcbc51484722e6ea43414bec7 +Author: Florian Weimer +Date: Wed Dec 20 16:14:33 2023 +0100 + + nss: Remove unused allocation from get_nscd_addresses in getaddrinfo + + No bug because this is not visible if glibc is built with + optimization. Otherwise this would be a critical resource leak. + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index e9f47aea358a3351..321a6679d46494a3 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -514,7 +514,6 @@ get_nscd_addresses (const char *name, const struct addrinfo *req, + int result = 0; + char *addrs = air->addrs; + +- struct gaih_addrtuple *addrfree = calloc (air->naddrs, sizeof (*addrfree)); + struct gaih_addrtuple *at = calloc (air->naddrs, sizeof (*at)); + if (at == NULL) + { diff --git a/SOURCES/glibc-RHEL-17319-1.patch b/SOURCES/glibc-RHEL-17319-1.patch new file mode 100644 index 0000000..513c4e0 --- /dev/null +++ b/SOURCES/glibc-RHEL-17319-1.patch @@ -0,0 +1,35 @@ +commit b893410be304ddcea0bd43f537a13e8b18d37cf2 +Author: Florian Weimer +Date: Mon Nov 27 11:28:07 2023 +0100 + + elf: In _dl_relocate_object, skip processing if object is relocated + + This is just a minor optimization. It also makes it more obvious that + _dl_relocate_object can be called multiple times. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index be3e09e36835ed23..0254e589c06fbf4c 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -192,6 +192,9 @@ void + _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + int reloc_mode, int consider_profiling) + { ++ if (l->l_relocated) ++ return; ++ + struct textrels + { + caddr_t start; +@@ -229,9 +232,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + # define consider_symbind 0 + #endif + +- if (l->l_relocated) +- return; +- + /* If DT_BIND_NOW is set relocate all references in this object. We + do not do this if we are profiling, of course. */ + // XXX Correct for auditing? diff --git a/SOURCES/glibc-RHEL-17319-2.patch b/SOURCES/glibc-RHEL-17319-2.patch new file mode 100644 index 0000000..e93db42 --- /dev/null +++ b/SOURCES/glibc-RHEL-17319-2.patch @@ -0,0 +1,121 @@ +commit a74c2e1cbc8673dd7e97aae2f2705392e2ccc3f6 +Author: Florian Weimer +Date: Mon Nov 27 11:28:10 2023 +0100 + + elf: Introduce the _dl_open_relocate_one_object function + + It is extracted from dl_open_worker_begin. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index c8a5d88161441031..cf3baccccb461878 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -467,6 +467,50 @@ activate_nodelete (struct link_map *new) + } + } + ++/* Relocate the object L. *RELOCATION_IN_PROGRESS controls whether ++ the debugger is notified of the start of relocation processing. */ ++static void ++_dl_open_relocate_one_object (struct dl_open_args *args, struct r_debug *r, ++ struct link_map *l, int reloc_mode, ++ bool *relocation_in_progress) ++{ ++ if (l->l_real->l_relocated) ++ return; ++ ++ if (!*relocation_in_progress) ++ { ++ /* Notify the debugger that relocations are about to happen. */ ++ LIBC_PROBE (reloc_start, 2, args->nsid, r); ++ *relocation_in_progress = true; ++ } ++ ++#ifdef SHARED ++ if (__glibc_unlikely (GLRO(dl_profile) != NULL)) ++ { ++ /* If this here is the shared object which we want to profile ++ make sure the profile is started. We can find out whether ++ this is necessary or not by observing the `_dl_profile_map' ++ variable. If it was NULL but is not NULL afterwards we must ++ start the profiling. */ ++ struct link_map *old_profile_map = GL(dl_profile_map); ++ ++ _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1); ++ ++ if (old_profile_map == NULL && GL(dl_profile_map) != NULL) ++ { ++ /* We must prepare the profiling. */ ++ _dl_start_profile (); ++ ++ /* Prevent unloading the object. */ ++ GL(dl_profile_map)->l_nodelete_active = true; ++ } ++ } ++ else ++#endif ++ _dl_relocate_object (l, l->l_scope, reloc_mode, 0); ++} ++ ++ + /* struct dl_init_args and call_dl_init are used to call _dl_init with + exception handling disabled. */ + struct dl_init_args +@@ -651,7 +695,7 @@ dl_open_worker_begin (void *a) + } + while (l != NULL); + +- int relocation_in_progress = 0; ++ bool relocation_in_progress = false; + + /* Perform relocation. This can trigger lazy binding in IFUNC + resolvers. For NODELETE mappings, these dependencies are not +@@ -662,44 +706,8 @@ dl_open_worker_begin (void *a) + are undefined anyway, so this is not a problem. */ + + for (unsigned int i = last; i-- > first; ) +- { +- l = new->l_initfini[i]; +- +- if (l->l_real->l_relocated) +- continue; +- +- if (! relocation_in_progress) +- { +- /* Notify the debugger that relocations are about to happen. */ +- LIBC_PROBE (reloc_start, 2, args->nsid, r); +- relocation_in_progress = 1; +- } +- +-#ifdef SHARED +- if (__glibc_unlikely (GLRO(dl_profile) != NULL)) +- { +- /* If this here is the shared object which we want to profile +- make sure the profile is started. We can find out whether +- this is necessary or not by observing the `_dl_profile_map' +- variable. If it was NULL but is not NULL afterwards we must +- start the profiling. */ +- struct link_map *old_profile_map = GL(dl_profile_map); +- +- _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1); +- +- if (old_profile_map == NULL && GL(dl_profile_map) != NULL) +- { +- /* We must prepare the profiling. */ +- _dl_start_profile (); +- +- /* Prevent unloading the object. */ +- GL(dl_profile_map)->l_nodelete_active = true; +- } +- } +- else +-#endif +- _dl_relocate_object (l, l->l_scope, reloc_mode, 0); +- } ++ _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode, ++ &relocation_in_progress); + + /* This only performs the memory allocations. The actual update of + the scopes happens below, after failure is impossible. */ diff --git a/SOURCES/glibc-RHEL-17319-3.patch b/SOURCES/glibc-RHEL-17319-3.patch new file mode 100644 index 0000000..fc0eb28 --- /dev/null +++ b/SOURCES/glibc-RHEL-17319-3.patch @@ -0,0 +1,224 @@ +commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec +Author: Florian Weimer +Date: Mon Nov 27 11:28:13 2023 +0100 + + elf: Relocate libc.so early during startup and dlmopen (bug 31083) + + This makes it more likely that objects without dependencies can + use IFUNC resolvers in libc.so. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (test backport differences) + elf/rtld.c + (prelink support was removed upstream) + +diff --git a/elf/Makefile b/elf/Makefile +index 8e1f91bcd917fd4e..7b7c6c171ce23247 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -419,6 +419,8 @@ tests += \ + tst-nodelete2 \ + tst-nodelete-dlclose \ + tst-nodelete-opened \ ++ tst-nodeps1 \ ++ tst-nodeps2 \ + tst-noload \ + tst-null-argv \ + tst-relsort1 \ +@@ -777,6 +779,8 @@ modules-names = \ + tst-nodelete-dlclose-dso \ + tst-nodelete-dlclose-plugin \ + tst-nodelete-opened-lib \ ++ tst-nodeps1-mod \ ++ tst-nodeps2-mod \ + tst-null-argv-lib \ + tst-relsort1mod1 \ + tst-relsort1mod2 \ +@@ -931,8 +935,15 @@ extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + + # filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special + # rules. +-modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod \ +- tst-audit24bmod1 tst-audit24bmod2 ++modules-names-nobuild += \ ++ filtmod1 \ ++ tst-audit24bmod1 \ ++ tst-audit24bmod2 \ ++ tst-big-note-lib \ ++ tst-nodeps1-mod \ ++ tst-nodeps2-mod \ ++ tst-ro-dynamic-mod \ ++ # modules-names-nobuild + + tests += $(tests-static) + +@@ -2684,3 +2695,18 @@ LDFLAGS-tst-dlclose-lazy-mod1.so = -Wl,-z,lazy,--no-as-needed + $(objpfx)tst-dlclose-lazy-mod1.so: $(objpfx)tst-dlclose-lazy-mod2.so + $(objpfx)tst-dlclose-lazy.out: \ + $(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so ++ ++# The object tst-nodeps1-mod.so has no explicit dependencies on libc.so. ++$(objpfx)tst-nodeps1-mod.so: $(objpfx)tst-nodeps1-mod.os ++ $(LINK.o) -nostartfiles -nostdlib -shared -o $@ $^ ++tst-nodeps1.so-no-z-defs = yes ++# Link libc.so before the test module with the IFUNC resolver reference. ++LDFLAGS-tst-nodeps1 = $(common-objpfx)libc.so $(objpfx)tst-nodeps1-mod.so ++$(objpfx)tst-nodeps1: $(objpfx)tst-nodeps1-mod.so ++# Reuse the tst-nodeps1 module. Link libc.so before the test module ++# with the IFUNC resolver reference. ++$(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \ ++ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.os ++ $(LINK.o) -Wl,--no-as-needed -nostartfiles -nostdlib -shared -o $@ $^ ++$(objpfx)tst-nodeps2.out: \ ++ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so +diff --git a/elf/dl-open.c b/elf/dl-open.c +index cf3baccccb461878..4b58bdd668634130 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -705,6 +705,17 @@ dl_open_worker_begin (void *a) + them. However, such relocation dependencies in IFUNC resolvers + are undefined anyway, so this is not a problem. */ + ++ /* Ensure that libc is relocated first. This helps with the ++ execution of IFUNC resolvers in libc, and matters only to newly ++ created dlmopen namespaces. Do not do this for static dlopen ++ because libc has relocations against ld.so, which may not have ++ been relocated at this point. */ ++#ifdef SHARED ++ if (GL(dl_ns)[args->nsid].libc_map != NULL) ++ _dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map, ++ reloc_mode, &relocation_in_progress); ++#endif ++ + for (unsigned int i = last; i-- > first; ) + _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode, + &relocation_in_progress); +diff --git a/elf/rtld.c b/elf/rtld.c +index 9de53ccaed420a57..a638d14e77745baa 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2421,11 +2421,17 @@ dl_main (const ElfW(Phdr) *phdr, + objects. We do not re-relocate the dynamic linker itself in this + loop because that could result in the GOT entries for functions we + call being changed, and that would break us. It is safe to relocate +- the dynamic linker out of order because it has no copy relocs (we +- know that because it is self-contained). */ ++ the dynamic linker out of order because it has no copy relocations. ++ Likewise for libc, which is relocated early to ensure that IFUNC ++ resolvers in libc work. */ + + int consider_profiling = GLRO(dl_profile) != NULL; + ++ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) ++ _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, ++ GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, ++ GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); ++ + /* If we are profiling we also must do lazy reloaction. */ + GLRO(dl_lazy) |= consider_profiling; + +diff --git a/elf/tst-nodeps1-mod.c b/elf/tst-nodeps1-mod.c +new file mode 100644 +index 0000000000000000..45c8e3c631251a89 +--- /dev/null ++++ b/elf/tst-nodeps1-mod.c +@@ -0,0 +1,25 @@ ++/* Test module with no libc.so dependency and string function references. ++ Copyright (C) 2023 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 ++ . */ ++ ++#include ++ ++/* Some references to libc symbols which are likely to have IFUNC ++ resolvers. If they do not, this module does not exercise bug 31083. */ ++void *memcpy_pointer = memcpy; ++void *memmove_pointer = memmove; ++void *memset_pointer = memset; +diff --git a/elf/tst-nodeps1.c b/elf/tst-nodeps1.c +new file mode 100644 +index 0000000000000000..1a8bde36cdb71446 +--- /dev/null ++++ b/elf/tst-nodeps1.c +@@ -0,0 +1,23 @@ ++/* Test initially loaded module with implicit libc.so dependency (bug 31083). ++ Copyright (C) 2023 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 ++ . */ ++ ++/* Testing happens before main. */ ++int ++main (void) ++{ ++} +diff --git a/elf/tst-nodeps2-mod.c b/elf/tst-nodeps2-mod.c +new file mode 100644 +index 0000000000000000..4913feee9b56e0e1 +--- /dev/null ++++ b/elf/tst-nodeps2-mod.c +@@ -0,0 +1 @@ ++/* Empty test module which depends on tst-nodeps1-mod.so. */ +diff --git a/elf/tst-nodeps2.c b/elf/tst-nodeps2.c +new file mode 100644 +index 0000000000000000..0bdc8eeb8cba3a99 +--- /dev/null ++++ b/elf/tst-nodeps2.c +@@ -0,0 +1,29 @@ ++/* Test dlmopen with implicit libc.so dependency (bug 31083). ++ Copyright (C) 2023 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 ++ . */ ++ ++#include ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-nodeps2-mod.so", RTLD_NOW); ++ xdlclose (handle); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-17319-4.patch b/SOURCES/glibc-RHEL-17319-4.patch new file mode 100644 index 0000000..2c34cf6 --- /dev/null +++ b/SOURCES/glibc-RHEL-17319-4.patch @@ -0,0 +1,41 @@ +commit b3bee76c5f59498b9c189608f0a3132e2013fa1a +Author: Florian Weimer +Date: Fri Dec 8 09:51:34 2023 +0100 + + elf: Initialize GLRO(dl_lazy) before relocating libc in dynamic startup + + GLRO(dl_lazy) is used to set the parameters for the early + _dl_relocate_object call, so the consider_profiling setting has to + be applied before the call. + + Fixes commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec ("elf: Relocate + libc.so early during startup and dlmopen (bug 31083)"). + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/rtld.c + (prelink was removed upstream) + +diff --git a/elf/rtld.c b/elf/rtld.c +index a638d14e77745baa..d973c385b312ea16 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2427,14 +2427,14 @@ dl_main (const ElfW(Phdr) *phdr, + + int consider_profiling = GLRO(dl_profile) != NULL; + ++ /* If we are profiling we also must do lazy reloaction. */ ++ GLRO(dl_lazy) |= consider_profiling; ++ + if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) + _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, + GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, + GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); + +- /* If we are profiling we also must do lazy reloaction. */ +- GLRO(dl_lazy) |= consider_profiling; +- + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); + unsigned i = main_map->l_searchlist.r_nlist; diff --git a/SOURCES/glibc-RHEL-17465-1.patch b/SOURCES/glibc-RHEL-17465-1.patch new file mode 100644 index 0000000..45dd3a6 --- /dev/null +++ b/SOURCES/glibc-RHEL-17465-1.patch @@ -0,0 +1,47 @@ +commit 3921c5b40f293c57cb326f58713c924b0662ef59 +Author: Hector Martin +Date: Tue Nov 28 15:23:07 2023 +0900 + + elf: Fix TLS modid reuse generation assignment (BZ 29039) + + _dl_assign_tls_modid() assigns a slotinfo entry for a new module, but + does *not* do anything to the generation counter. The first time this + happens, the generation is zero and map_generation() returns the current + generation to be used during relocation processing. However, if + a slotinfo entry is later reused, it will already have a generation + assigned. If this generation has fallen behind the current global max + generation, then this causes an obsolete generation to be assigned + during relocation processing, as map_generation() returns this + generation if nonzero. _dl_add_to_slotinfo() eventually resets the + generation, but by then it is too late. This causes DTV updates to be + skipped, leading to NULL or broken TLS slot pointers and segfaults. + + Fix this by resetting the generation to zero in _dl_assign_tls_modid(), + so it behaves the same as the first time a slot is assigned. + _dl_add_to_slotinfo() will still assign the correct static generation + later during module load, but relocation processing will no longer use + an obsolete generation. + + Note that slotinfo entry (aka modid) reuse typically happens after a + dlclose and only TLS access via dynamic tlsdesc is affected. Because + tlsdesc is optimized to use the optional part of static TLS, dynamic + tlsdesc can be avoided by increasing the glibc.rtld.optional_static_tls + tunable to a large enough value, or by LD_PRELOAD-ing the affected + modules. + + Fixes bug 29039. + + Reviewed-by: Szabolcs Nagy + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index b8ada16f1637c910..b9dc56e81a3b43db 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -160,6 +160,7 @@ _dl_assign_tls_modid (struct link_map *l) + { + /* Mark the entry as used, so any dependency see it. */ + atomic_store_relaxed (&runp->slotinfo[result - disp].map, l); ++ atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0); + break; + } + diff --git a/SOURCES/glibc-RHEL-17465-2.patch b/SOURCES/glibc-RHEL-17465-2.patch new file mode 100644 index 0000000..e3abb0f --- /dev/null +++ b/SOURCES/glibc-RHEL-17465-2.patch @@ -0,0 +1,198 @@ +commit 980450f12685326729d63ff72e93a996113bf073 +Author: Szabolcs Nagy +Date: Wed Nov 29 11:31:37 2023 +0000 + + elf: Add TLS modid reuse test for bug 29039 + + This is a minimal regression test for bug 29039 which only affects + targets with TLSDESC and a reproducer requires that + + 1) Have modid gaps (closed modules) with old generation. + 2) Update a DTV to a newer generation (needs a newer dlopen). + 3) But do not update the closed gap entry in that DTV. + 4) Reuse the modid gap for a new module (another dlopen). + 5) Use dynamic TLSDESC in that new module with old generation (bug). + 6) Access TLS via this TLSDESC and the now outdated DTV. + + However step (3) in practice rarely happens: during DTV update the + entries for closed modids are initialized to "unallocated" and then + dynamic TLSDESC calls __tls_get_addr independently of its generation. + The only exception to this is DTV setup at thread creation (gaps are + initialized to NULL instead of unallocated) or DTV resize where the + gap entries are outside the previous DTV array (again NULL instead + of unallocated, and this requires loading > DTV_SURPLUS modules). + + So the bug can only cause NULL (+ offset) dereference, not use after + free. And the easiest way to get (3) is via thread creation. + + Note that step (5) requires that the newly loaded module has larger + TLS than the remaining optional static TLS. And for (6) there cannot + be other TLS access or dlopen in the thread that updates the DTV. + + Tested on aarch64-linux-gnu. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + (Resolve test case ordering conflict.) + +diff --git a/elf/Makefile b/elf/Makefile +index 7b7c6c171ce23247..7d55e68a55b54bd6 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -447,6 +447,7 @@ tests += \ + tst-tls5 \ + tst-tlsalign \ + tst-tlsalign-extern \ ++ tst-tlsgap \ + tst-tls-dlinfo \ + tst-tls-ie \ + tst-tls-ie-dlmopen \ +@@ -798,6 +799,9 @@ modules-names = \ + tst-tls20mod-bad \ + tst-tls21mod \ + tst-tlsalign-lib \ ++ tst-tlsgap-mod0 \ ++ tst-tlsgap-mod1 \ ++ tst-tlsgap-mod2 \ + tst-tls-ie-mod0 \ + tst-tls-ie-mod1 \ + tst-tls-ie-mod2 \ +@@ -2710,3 +2714,14 @@ $(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \ + $(LINK.o) -Wl,--no-as-needed -nostartfiles -nostdlib -shared -o $@ $^ + $(objpfx)tst-nodeps2.out: \ + $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so ++ ++$(objpfx)tst-tlsgap: $(shared-thread-library) ++$(objpfx)tst-tlsgap.out: \ ++ $(objpfx)tst-tlsgap-mod0.so \ ++ $(objpfx)tst-tlsgap-mod1.so \ ++ $(objpfx)tst-tlsgap-mod2.so ++ifeq (yes,$(have-mtls-dialect-gnu2)) ++CFLAGS-tst-tlsgap-mod0.c += -mtls-dialect=gnu2 ++CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=gnu2 ++CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=gnu2 ++endif +diff --git a/elf/tst-tlsgap-mod0.c b/elf/tst-tlsgap-mod0.c +new file mode 100644 +index 0000000000000000..1478b0beac5faf98 +--- /dev/null ++++ b/elf/tst-tlsgap-mod0.c +@@ -0,0 +1,2 @@ ++int __thread tls0; ++int *f0(void) { return &tls0; } +diff --git a/elf/tst-tlsgap-mod1.c b/elf/tst-tlsgap-mod1.c +new file mode 100644 +index 0000000000000000..b10fc3702c43e478 +--- /dev/null ++++ b/elf/tst-tlsgap-mod1.c +@@ -0,0 +1,2 @@ ++int __thread tls1[100]; /* Size > glibc.rtld.optional_static_tls / 2. */ ++int *f1(void) { return tls1; } +diff --git a/elf/tst-tlsgap-mod2.c b/elf/tst-tlsgap-mod2.c +new file mode 100644 +index 0000000000000000..166c27d7f3fac252 +--- /dev/null ++++ b/elf/tst-tlsgap-mod2.c +@@ -0,0 +1,2 @@ ++int __thread tls2; ++int *f2(void) { return &tls2; } +diff --git a/elf/tst-tlsgap.c b/elf/tst-tlsgap.c +new file mode 100644 +index 0000000000000000..49328850769c5609 +--- /dev/null ++++ b/elf/tst-tlsgap.c +@@ -0,0 +1,92 @@ ++/* TLS modid gap reuse regression test for bug 29039. ++ Copyright (C) 2023 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void *mod[3]; ++#define MOD(i) "tst-tlsgap-mod" #i ".so" ++static const char *modname[3] = { MOD(0), MOD(1), MOD(2) }; ++#undef MOD ++ ++static void ++open_mod (int i) ++{ ++ mod[i] = xdlopen (modname[i], RTLD_LAZY); ++ printf ("open %s\n", modname[i]); ++} ++ ++static void ++close_mod (int i) ++{ ++ xdlclose (mod[i]); ++ mod[i] = NULL; ++ printf ("close %s\n", modname[i]); ++} ++ ++static void ++access_mod (int i, const char *sym) ++{ ++ int *(*f) (void) = xdlsym (mod[i], sym); ++ int *p = f (); ++ printf ("access %s: %s() = %p\n", modname[i], sym, p); ++ TEST_VERIFY_EXIT (p != NULL); ++ ++*p; ++} ++ ++static void * ++start (void *arg) ++{ ++ /* The DTV generation is at the last dlopen of mod0 and the ++ entry for mod1 is NULL. */ ++ ++ open_mod (1); /* Reuse modid of mod1. Uses dynamic TLS. */ ++ ++ /* DTV is unchanged: dlopen only updates the DTV to the latest ++ generation if static TLS is allocated for a loaded module. ++ ++ With bug 29039, the TLSDESC relocation in mod1 uses the old ++ dlclose generation of mod1 instead of the new dlopen one so ++ DTV is not updated on TLS access. */ ++ ++ access_mod (1, "f1"); ++ ++ return arg; ++} ++ ++static int ++do_test (void) ++{ ++ open_mod (0); ++ open_mod (1); ++ open_mod (2); ++ close_mod (0); ++ close_mod (1); /* Create modid gap at mod1. */ ++ open_mod (0); /* Reuse modid of mod0, bump generation count. */ ++ ++ /* Create a thread where DTV of mod1 is NULL. */ ++ pthread_t t = xpthread_create (NULL, start, NULL); ++ xpthread_join (t); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-19444.patch b/SOURCES/glibc-RHEL-19444.patch new file mode 100644 index 0000000..2c03560 --- /dev/null +++ b/SOURCES/glibc-RHEL-19444.patch @@ -0,0 +1,29 @@ +commit 5eabdb6a6ac1599d23dd5966a37417215950245f +Author: Andreas Schwab +Date: Wed Dec 6 14:48:22 2023 +0100 + + getaddrinfo: translate ENOMEM to EAI_MEMORY (bug 31163) + + When __resolv_context_get returns NULL due to out of memory, translate it + to a return value of EAI_MEMORY. + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 321a6679d46494a3..8fe879c5420337a4 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -615,7 +615,14 @@ get_nss_addresses (const char *name, const struct addrinfo *req, + function variant. */ + res_ctx = __resolv_context_get (); + if (res_ctx == NULL) +- no_more = 1; ++ { ++ if (errno == ENOMEM) ++ { ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ no_more = 1; ++ } + + while (!no_more) + { diff --git a/SOURCES/glibc-RHEL-19862.patch b/SOURCES/glibc-RHEL-19862.patch new file mode 100644 index 0000000..f3aa27c --- /dev/null +++ b/SOURCES/glibc-RHEL-19862.patch @@ -0,0 +1,27 @@ +commit ecc7c3deb9f347649c2078fcc0f94d4cedf92d60 +Author: Florian Weimer +Date: Tue Jan 2 14:36:17 2024 +0100 + + libio: Check remaining buffer size in _IO_wdo_write (bug 31183) + + The multibyte character needs to fit into the remaining buffer space, + not the already-written buffer space. Without the fix, we were never + moving the write pointer from the start of the buffer, always using + the single-character fallback buffer. + + Fixes commit 04b76b5aa8b2d1d19066e42dd1 ("Don't error out writing + a multibyte character to an unbuffered stream (bug 17522)"). + +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 37f44780f811bd38..6cbc3c7c968f9136 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -57,7 +57,7 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do) + char mb_buf[MB_LEN_MAX]; + char *write_base, *write_ptr, *buf_end; + +- if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf)) ++ if (fp->_IO_buf_end - fp->_IO_write_ptr < sizeof (mb_buf)) + { + /* Make sure we have room for at least one multibyte + character. */ diff --git a/SOURCES/glibc-RHEL-2123.patch b/SOURCES/glibc-RHEL-2123.patch new file mode 100644 index 0000000..682d02b --- /dev/null +++ b/SOURCES/glibc-RHEL-2123.patch @@ -0,0 +1,317 @@ +commit d2123d68275acc0f061e73d5f86ca504e0d5a344 +Author: Szabolcs Nagy +Date: Tue Feb 16 12:55:13 2021 +0000 + + elf: Fix slow tls access after dlopen [BZ #19924] + + In short: __tls_get_addr checks the global generation counter and if + the current dtv is older then _dl_update_slotinfo updates dtv up to the + generation of the accessed module. So if the global generation is newer + than generation of the module then __tls_get_addr keeps hitting the + slow dtv update path. The dtv update path includes a number of checks + to see if any update is needed and this already causes measurable tls + access slow down after dlopen. + + It may be possible to detect up-to-date dtv faster. But if there are + many modules loaded (> TLS_SLOTINFO_SURPLUS) then this requires at + least walking the slotinfo list. + + This patch tries to update the dtv to the global generation instead, so + after a dlopen the tls access slow path is only hit once. The modules + with larger generation than the accessed one were not necessarily + synchronized before, so additional synchronization is needed. + + This patch uses acquire/release synchronization when accessing the + generation counter. + + Note: in the x86_64 version of dl-tls.c the generation is only loaded + once, since relaxed mo is not faster than acquire mo load. + + I have not benchmarked this. Tested by Adhemerval Zanella on aarch64, + powerpc, sparc, x86 who reported that it fixes the performance issue + of bug 19924. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 985cd4e2821436af..95a03c9616c6a786 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -739,7 +739,7 @@ _dl_close_worker (struct link_map *map, bool force) + if (__glibc_unlikely (newgen == 0)) + _dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n"); + /* Can be read concurrently. */ +- atomic_store_relaxed (&GL(dl_tls_generation), newgen); ++ atomic_store_release (&GL(dl_tls_generation), newgen); + + if (tls_free_end == GL(dl_tls_static_used)) + GL(dl_tls_static_used) = tls_free_start; +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 633b047ad2497296..c8a5d88161441031 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -404,7 +404,7 @@ update_tls_slotinfo (struct link_map *new) + _dl_fatal_printf (N_("\ + TLS generation counter wrapped! Please report this.")); + /* Can be read concurrently. */ +- atomic_store_relaxed (&GL(dl_tls_generation), newgen); ++ atomic_store_release (&GL(dl_tls_generation), newgen); + + /* We need a second pass for static tls data, because + _dl_update_slotinfo must not be run while calls to +@@ -421,8 +421,8 @@ TLS generation counter wrapped! Please report this.")); + now, but we can delay updating the DTV. */ + imap->l_need_tls_init = 0; + #ifdef SHARED +- /* Update the slot information data for at least the +- generation of the DSO we are allocating data for. */ ++ /* Update the slot information data for the current ++ generation. */ + + /* FIXME: This can terminate the process on memory + allocation failure. It is not possible to raise +@@ -430,7 +430,7 @@ TLS generation counter wrapped! Please report this.")); + _dl_update_slotinfo would have to be split into two + operations, similar to resize_scopes and update_scopes + above. This is related to bug 16134. */ +- _dl_update_slotinfo (imap->l_tls_modid); ++ _dl_update_slotinfo (imap->l_tls_modid, newgen); + #endif + + dl_init_static_tls (imap); +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index 5b69321bda1f2b27..be3e09e36835ed23 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -111,11 +111,11 @@ _dl_try_allocate_static_tls (struct link_map *map, bool optional) + if (map->l_real->l_relocated) + { + #ifdef SHARED ++ /* Update the DTV of the current thread. Note: GL(dl_load_tls_lock) ++ is held here so normal load of the generation counter is valid. */ + if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation), + 0)) +- /* Update the slot information data for at least the generation of +- the DSO we are allocating data for. */ +- (void) _dl_update_slotinfo (map->l_tls_modid); ++ (void) _dl_update_slotinfo (map->l_tls_modid, GL(dl_tls_generation)); + #endif + + dl_init_static_tls (map); +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index fab6546e2d31edd4..b8ada16f1637c910 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -721,57 +721,57 @@ allocate_and_init (struct link_map *map) + + + struct link_map * +-_dl_update_slotinfo (unsigned long int req_modid) ++_dl_update_slotinfo (unsigned long int req_modid, size_t new_gen) + { + struct link_map *the_map = NULL; + dtv_t *dtv = THREAD_DTV (); + +- /* The global dl_tls_dtv_slotinfo array contains for each module +- index the generation counter current when the entry was created. ++ /* CONCURRENCY NOTES: ++ ++ The global dl_tls_dtv_slotinfo_list array contains for each module ++ index the generation counter current when that entry was updated. + This array never shrinks so that all module indices which were +- valid at some time can be used to access it. Before the first +- use of a new module index in this function the array was extended +- appropriately. Access also does not have to be guarded against +- modifications of the array. It is assumed that pointer-size +- values can be read atomically even in SMP environments. It is +- possible that other threads at the same time dynamically load +- code and therefore add to the slotinfo list. This is a problem +- since we must not pick up any information about incomplete work. +- The solution to this is to ignore all dtv slots which were +- created after the one we are currently interested. We know that +- dynamic loading for this module is completed and this is the last +- load operation we know finished. */ +- unsigned long int idx = req_modid; ++ valid at some time can be used to access it. Concurrent loading ++ and unloading of modules can update slotinfo entries or extend ++ the array. The updates happen under the GL(dl_load_tls_lock) and ++ finish with the release store of the generation counter to ++ GL(dl_tls_generation) which is synchronized with the load of ++ new_gen in the caller. So updates up to new_gen are synchronized ++ but updates for later generations may not be. ++ ++ Here we update the thread dtv from old_gen (== dtv[0].counter) to ++ new_gen generation. For this, each dtv[i] entry is either set to ++ an unallocated state (set), or left unmodified (nop). Where (set) ++ may resize the dtv first if modid i >= dtv[-1].counter. The rules ++ for the decision between (set) and (nop) are ++ ++ (1) If slotinfo entry i is concurrently updated then either (set) ++ or (nop) is valid: TLS access cannot use dtv[i] unless it is ++ synchronized with a generation > new_gen. ++ ++ Otherwise, if the generation of slotinfo entry i is gen and the ++ loaded module for this entry is map then ++ ++ (2) If gen <= old_gen then do (nop). ++ ++ (3) If old_gen < gen <= new_gen then ++ (3.1) if map != 0 then (set) ++ (3.2) if map == 0 then either (set) or (nop). ++ ++ Note that (1) cannot be reliably detected, but since both actions ++ are valid it does not have to be. Only (2) and (3.1) cases need ++ to be distinguished for which relaxed mo access of gen and map is ++ enough: their value is synchronized when it matters. ++ ++ Note that a relaxed mo load may give an out-of-thin-air value since ++ it is used in decisions that can affect concurrent stores. But this ++ should only happen if the OOTA value causes UB that justifies the ++ concurrent store of the value. This is not expected to be an issue ++ in practice. */ + struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + +- while (idx >= listp->len) ++ if (dtv[0].counter < new_gen) + { +- idx -= listp->len; +- listp = listp->next; +- } +- +- if (dtv[0].counter < listp->slotinfo[idx].gen) +- { +- /* CONCURRENCY NOTES: +- +- Here the dtv needs to be updated to new_gen generation count. +- +- This code may be called during TLS access when GL(dl_load_tls_lock) +- is not held. In that case the user code has to synchronize with +- dlopen and dlclose calls of relevant modules. A module m is +- relevant if the generation of m <= new_gen and dlclose of m is +- synchronized: a memory access here happens after the dlopen and +- before the dlclose of relevant modules. The dtv entries for +- relevant modules need to be updated, other entries can be +- arbitrary. +- +- This e.g. means that the first part of the slotinfo list can be +- accessed race free, but the tail may be concurrently extended. +- Similarly relevant slotinfo entries can be read race free, but +- other entries are racy. However updating a non-relevant dtv +- entry does not affect correctness. For a relevant module m, +- max_modid >= modid of m. */ +- size_t new_gen = listp->slotinfo[idx].gen; + size_t total = 0; + size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx)); + assert (max_modid >= req_modid); +@@ -784,31 +784,33 @@ _dl_update_slotinfo (unsigned long int req_modid) + { + size_t modid = total + cnt; + +- /* Later entries are not relevant. */ ++ /* Case (1) for all later modids. */ + if (modid > max_modid) + break; + + size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen); + ++ /* Case (1). */ + if (gen > new_gen) +- /* Not relevant. */ + continue; + +- /* If the entry is older than the current dtv layout we +- know we don't have to handle it. */ ++ /* Case (2) or (1). */ + if (gen <= dtv[0].counter) + continue; + ++ /* Case (3) or (1). */ ++ + /* If there is no map this means the entry is empty. */ + struct link_map *map + = atomic_load_relaxed (&listp->slotinfo[cnt].map); + /* Check whether the current dtv array is large enough. */ + if (dtv[-1].counter < modid) + { ++ /* Case (3.2) or (1). */ + if (map == NULL) + continue; + +- /* Resize the dtv. */ ++ /* Resizing the dtv aborts on failure: bug 16134. */ + dtv = _dl_resize_dtv (dtv, max_modid); + + assert (modid <= dtv[-1].counter); +@@ -819,7 +821,7 @@ _dl_update_slotinfo (unsigned long int req_modid) + } + + /* If there is currently memory allocate for this +- dtv entry free it. */ ++ dtv entry free it. Note: this is not AS-safe. */ + /* XXX Ideally we will at some point create a memory + pool. */ + free (dtv[modid].pointer.to_free); +@@ -914,9 +916,9 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + + static struct link_map * + __attribute_noinline__ +-update_get_addr (GET_ADDR_ARGS) ++update_get_addr (GET_ADDR_ARGS, size_t gen) + { +- struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE); ++ struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE, gen); + dtv_t *dtv = THREAD_DTV (); + + void *p = dtv[GET_ADDR_MODULE].pointer.val; +@@ -946,12 +948,17 @@ __tls_get_addr (GET_ADDR_ARGS) + dtv_t *dtv = THREAD_DTV (); + + /* Update is needed if dtv[0].counter < the generation of the accessed +- module. The global generation counter is used here as it is easier +- to check. Synchronization for the relaxed MO access is guaranteed +- by user code, see CONCURRENCY NOTES in _dl_update_slotinfo. */ ++ module, but the global generation counter is easier to check (which ++ must be synchronized up to the generation of the accessed module by ++ user code doing the TLS access so relaxed mo read is enough). */ + size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); + if (__glibc_unlikely (dtv[0].counter != gen)) +- return update_get_addr (GET_ADDR_PARAM); ++ { ++ /* Update DTV up to the global generation, see CONCURRENCY NOTES ++ in _dl_update_slotinfo. */ ++ gen = atomic_load_acquire (&GL(dl_tls_generation)); ++ return update_get_addr (GET_ADDR_PARAM, gen); ++ } + + void *p = dtv[GET_ADDR_MODULE].pointer.val; + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 8c0fe98f69a88f1e..7964e133e4930e88 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1304,7 +1304,8 @@ extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add) + + /* Update slot information data for at least the generation of the + module with the given index. */ +-extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid) ++extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid, ++ size_t gen) + attribute_hidden; + + /* Look up the module's TLS block as for __tls_get_addr, +diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c +index 24ef560b718275a2..4ded8dd6b94edc81 100644 +--- a/sysdeps/x86_64/dl-tls.c ++++ b/sysdeps/x86_64/dl-tls.c +@@ -40,9 +40,9 @@ __tls_get_addr_slow (GET_ADDR_ARGS) + { + dtv_t *dtv = THREAD_DTV (); + +- size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); ++ size_t gen = atomic_load_acquire (&GL(dl_tls_generation)); + if (__glibc_unlikely (dtv[0].counter != gen)) +- return update_get_addr (GET_ADDR_PARAM); ++ return update_get_addr (GET_ADDR_PARAM, gen); + + return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL); + } diff --git a/SOURCES/glibc-RHEL-21556.patch b/SOURCES/glibc-RHEL-21556.patch new file mode 100644 index 0000000..31edb08 --- /dev/null +++ b/SOURCES/glibc-RHEL-21556.patch @@ -0,0 +1,33 @@ +commit c06c8aeb61708249d8eb0b17a676d16771ea640b +Author: Dennis Brendel +Date: Mon Jan 15 09:55:37 2024 +0100 + + manual: fix order of arguments of memalign and aligned_alloc (Bug 27547) + + On the summary page the order of the function arguments was reversed, but it is + in correct order in the other places of the manual. + + Reviewed-by: Carlos O'Donell + +diff --git a/manual/memory.texi b/manual/memory.texi +index fb875f4c3c..3710d7ec66 100644 +--- a/manual/memory.texi ++++ b/manual/memory.texi +@@ -1502,7 +1502,7 @@ Space}. + Allocate a block of @var{size} bytes, starting on a page boundary. + @xref{Aligned Memory Blocks}. + +-@item void *aligned_alloc (size_t @var{size}, size_t @var{alignment}) ++@item void *aligned_alloc (size_t @var{alignment}, size_t @var{size}) + Allocate a block of @var{size} bytes, starting on an address that is a + multiple of @var{alignment}. @xref{Aligned Memory Blocks}. + +@@ -1510,7 +1510,7 @@ multiple of @var{alignment}. @xref{Aligned Memory Blocks}. + Allocate a block of @var{size} bytes, starting on an address that is a + multiple of @var{alignment}. @xref{Aligned Memory Blocks}. + +-@item void *memalign (size_t @var{size}, size_t @var{boundary}) ++@item void *memalign (size_t @var{boundary}, size_t @var{size}) + Allocate a block of @var{size} bytes, starting on an address that is a + multiple of @var{boundary}. @xref{Aligned Memory Blocks}. + diff --git a/SOURCES/glibc-RHEL-2338-1.patch b/SOURCES/glibc-RHEL-2338-1.patch new file mode 100644 index 0000000..6dcac65 --- /dev/null +++ b/SOURCES/glibc-RHEL-2338-1.patch @@ -0,0 +1,47 @@ +commit c3b023a7822185c9176cfb96eeca4ada3d662c4b +Author: Adhemerval Zanella +Date: Wed Nov 24 12:57:57 2021 -0300 + + linux: Only build fstatat fallback if required + + For 32-bit architecture with __ASSUME_STATX there is no need to + build fstatat64_time64_stat. + + Checked on i686-linux-gnu. + +diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c +index f968e4ef0594852e..50ae5ad74832efe1 100644 +--- a/sysdeps/unix/sysv/linux/fstatat64.c ++++ b/sysdeps/unix/sysv/linux/fstatat64.c +@@ -74,6 +74,17 @@ fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf, + return r; + } + ++#if (__WORDSIZE == 32 \ ++ && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) \ ++ || defined STAT_HAS_TIME32 ++# define FSTATAT_USE_STATX 1 ++#else ++# define FSTATAT_USE_STATX 0 ++#endif ++ ++/* Only statx supports 64-bit timestamps for 32-bit architectures with ++ __ASSUME_STATX, so there is no point in building the fallback. */ ++#if !FSTATAT_USE_STATX || (FSTATAT_USE_STATX && !defined __ASSUME_STATX) + static inline int + fstatat64_time64_stat (int fd, const char *file, struct __stat64_t64 *buf, + int flag) +@@ -134,13 +145,6 @@ fstatat64_time64_stat (int fd, const char *file, struct __stat64_t64 *buf, + + return r; + } +- +-#if (__WORDSIZE == 32 \ +- && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) \ +- || defined STAT_HAS_TIME32 +-# define FSTATAT_USE_STATX 1 +-#else +-# define FSTATAT_USE_STATX 0 + #endif + + int diff --git a/SOURCES/glibc-RHEL-2338-2.patch b/SOURCES/glibc-RHEL-2338-2.patch new file mode 100644 index 0000000..5372910 --- /dev/null +++ b/SOURCES/glibc-RHEL-2338-2.patch @@ -0,0 +1,36 @@ +commit c7f05bd5342517f3f751e6ea8dec1916b80bee8a +Author: Adhemerval Zanella +Date: Wed Mar 9 18:35:39 2022 -0300 + + Fix ununsed fstatat64_time64_statx + + It is only called for legacy ABIs. + +diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c +index 50ae5ad74832efe1..45221bbdf901fa47 100644 +--- a/sysdeps/unix/sysv/linux/fstatat64.c ++++ b/sysdeps/unix/sysv/linux/fstatat64.c +@@ -40,6 +40,11 @@ _Static_assert (sizeof (__blkcnt_t) == sizeof (__blkcnt64_t), + "__blkcnt_t and __blkcnt64_t must match"); + #endif + ++#if (__WORDSIZE == 32 \ ++ && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) \ ++ || defined STAT_HAS_TIME32 ++# define FSTATAT_USE_STATX 1 ++ + static inline int + fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf, + int flag) +@@ -73,11 +78,6 @@ fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf, + + return r; + } +- +-#if (__WORDSIZE == 32 \ +- && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) \ +- || defined STAT_HAS_TIME32 +-# define FSTATAT_USE_STATX 1 + #else + # define FSTATAT_USE_STATX 0 + #endif diff --git a/SOURCES/glibc-RHEL-2338-3.patch b/SOURCES/glibc-RHEL-2338-3.patch new file mode 100644 index 0000000..9ed0a1a --- /dev/null +++ b/SOURCES/glibc-RHEL-2338-3.patch @@ -0,0 +1,30 @@ +commit e6547d635b991651600fab31f788ed5facd77610 +Author: WANG Xuerui +Date: Wed Jun 1 10:12:28 2022 +0800 + + linux: use statx for fstat if neither newfstatat nor fstatat64 is present + + LoongArch is going to be the first architecture supported by Linux that + has neither fstat* nor newfstatat [1], instead exclusively relying on + statx. So in fstatat64's implementation, we need to also enable statx + usage if neither fstatat64 nor newfstatat is present, to prepare for + this new case of kernel ABI. + + [1]: https://lore.kernel.org/all/20220518092619.1269111-1-chenhuacai@loongson.cn/ + + Reviewed-by: Adhemerval Zanella + +diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c +index 45221bbdf901fa47..ded431257bf3450f 100644 +--- a/sysdeps/unix/sysv/linux/fstatat64.c ++++ b/sysdeps/unix/sysv/linux/fstatat64.c +@@ -42,7 +42,8 @@ _Static_assert (sizeof (__blkcnt_t) == sizeof (__blkcnt64_t), + + #if (__WORDSIZE == 32 \ + && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) \ +- || defined STAT_HAS_TIME32 ++ || defined STAT_HAS_TIME32 \ ++ || (!defined __NR_newfstatat && !defined __NR_fstatat64) + # define FSTATAT_USE_STATX 1 + + static inline int diff --git a/SOURCES/glibc-RHEL-2338-4.patch b/SOURCES/glibc-RHEL-2338-4.patch new file mode 100644 index 0000000..4534dfd --- /dev/null +++ b/SOURCES/glibc-RHEL-2338-4.patch @@ -0,0 +1,157 @@ +commit 551101e8240b7514fc646d1722f8b79c90362b8f +Author: Adhemerval Zanella +Date: Mon Sep 11 10:25:48 2023 -0300 + + io: Do not implement fstat with fstatat + + AT_EMPTY_PATH is a requirement to implement fstat over fstatat, + however it does not prevent the kernel to read the path argument. + It is not an issue, but on x86-64 with SMAP-capable CPUs the kernel is + forced to perform expensive user memory access. After that regular + lookup is performed which adds even more overhead. + + Instead, issue the fstat syscall directly on LFS fstat implementation + (32 bit architectures will still continue to use statx, which is + required to have 64 bit time_t support). it should be even a + small performance gain on non x86_64, since there is no need + to handle the path argument. + + Checked on x86_64-linux-gnu. + +diff --git a/sysdeps/unix/sysv/linux/fstat64.c b/sysdeps/unix/sysv/linux/fstat64.c +index 46de80b663b9c1c4..fe4f57065f8713d2 100644 +--- a/sysdeps/unix/sysv/linux/fstat64.c ++++ b/sysdeps/unix/sysv/linux/fstat64.c +@@ -19,20 +19,53 @@ + #define __fstat __redirect___fstat + #define fstat __redirect_fstat + #include ++#undef __fstat ++#undef fstat + #include +-#include +-#include ++#include + #include + + int + __fstat64_time64 (int fd, struct __stat64_t64 *buf) + { ++#if !FSTATAT_USE_STATX ++# if XSTAT_IS_XSTAT64 ++# ifdef __NR_fstat ++ /* 64-bit kABI, e.g. aarch64, ia64, powerpc64*, s390x, riscv64, and ++ x86_64. */ ++ return INLINE_SYSCALL_CALL (fstat, fd, buf); ++# elif defined __NR_fstat64 ++# if STAT64_IS_KERNEL_STAT64 ++ /* 64-bit kABI outlier, e.g. alpha */ ++ return INLINE_SYSCALL_CALL (fstat64, fd, buf); ++# else ++ /* 64-bit kABI outlier, e.g. sparc64. */ ++ struct kernel_stat64 kst64; ++ int r = INLINE_SYSCALL_CALL (fstat64, fd, &kst64); ++ if (r == 0) ++ __cp_stat64_kstat64 (buf, &kst64); ++ return r; ++# endif /* STAT64_IS_KERNEL_STAT64 */ ++# endif ++# else /* XSTAT_IS_XSTAT64 */ ++ /* 64-bit kabi outlier, e.g. mips64 and mips64-n32. */ ++ struct kernel_stat kst; ++ int r = INLINE_SYSCALL_CALL (fstat, fd, &kst); ++ if (r == 0) ++ __cp_kstat_stat64_t64 (&kst, buf); ++ return r; ++# endif ++#else /* !FSTATAT_USE_STATX */ ++ /* All kABIs with non-LFS support and with old 32-bit time_t support ++ e.g. arm, csky, i386, hppa, m68k, microblaze, nios2, sh, powerpc32, ++ and sparc32. */ + if (fd < 0) + { + __set_errno (EBADF); + return -1; + } + return __fstatat64_time64 (fd, "", buf, AT_EMPTY_PATH); ++#endif + } + #if __TIMESIZE != 64 + hidden_def (__fstat64_time64) +diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c +index ded431257bf3450f..8e9db7b11f0e1cf3 100644 +--- a/sysdeps/unix/sysv/linux/fstatat64.c ++++ b/sysdeps/unix/sysv/linux/fstatat64.c +@@ -21,12 +21,10 @@ + #include + #include + #include +-#include + #include + #include +-#include +-#include + #include ++#include + + #if __TIMESIZE == 64 \ + && (__WORDSIZE == 32 \ +@@ -40,11 +38,7 @@ _Static_assert (sizeof (__blkcnt_t) == sizeof (__blkcnt64_t), + "__blkcnt_t and __blkcnt64_t must match"); + #endif + +-#if (__WORDSIZE == 32 \ +- && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) \ +- || defined STAT_HAS_TIME32 \ +- || (!defined __NR_newfstatat && !defined __NR_fstatat64) +-# define FSTATAT_USE_STATX 1 ++#if FSTATAT_USE_STATX + + static inline int + fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf, +@@ -79,8 +73,6 @@ fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf, + + return r; + } +-#else +-# define FSTATAT_USE_STATX 0 + #endif + + /* Only statx supports 64-bit timestamps for 32-bit architectures with +diff --git a/sysdeps/unix/sysv/linux/internal-stat.h b/sysdeps/unix/sysv/linux/internal-stat.h +new file mode 100644 +index 0000000000000000..e3b05698532fb185 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/internal-stat.h +@@ -0,0 +1,31 @@ ++/* Internal stat definitions. ++ Copyright (C) 2023 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#if (__WORDSIZE == 32 \ ++ && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) \ ++ || defined STAT_HAS_TIME32 \ ++ || (!defined __NR_newfstatat && !defined __NR_fstatat64) ++# define FSTATAT_USE_STATX 1 ++#else ++# define FSTATAT_USE_STATX 0 ++#endif diff --git a/SOURCES/glibc-RHEL-2426-1.patch b/SOURCES/glibc-RHEL-2426-1.patch new file mode 100644 index 0000000..5f5b0c4 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-1.patch @@ -0,0 +1,41 @@ +commit 01671608a3bddde369cdd42aed12e1c019b87158 +Author: Siddhesh Poyarekar +Date: Wed Aug 4 02:21:01 2021 +0530 + + gethosts: Remove unused argument _type + + The generated code is unchanged. + + (cherry picked from commit b17e842a60819098d2a203ecc8b8371b7e1d6c65) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index f391dc0a59849aab..702d8a50e0c218d2 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -239,7 +239,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + return true; + } + +-#define gethosts(_family, _type) \ ++#define gethosts(_family) \ + { \ + struct hostent th; \ + char *localcanon = NULL; \ +@@ -864,7 +864,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + if (req->ai_family == AF_INET6 + || req->ai_family == AF_UNSPEC) + { +- gethosts (AF_INET6, struct in6_addr); ++ gethosts (AF_INET6); + no_inet6_data = no_data; + inet6_status = status; + } +@@ -876,7 +876,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + know we are not going to need them. */ + && ((req->ai_flags & AI_ALL) || !got_ipv6))) + { +- gethosts (AF_INET, struct in_addr); ++ gethosts (AF_INET); + + if (req->ai_family == AF_INET) + { diff --git a/SOURCES/glibc-RHEL-2426-10.patch b/SOURCES/glibc-RHEL-2426-10.patch new file mode 100644 index 0000000..18763f1 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-10.patch @@ -0,0 +1,178 @@ +commit 6e3fed9d20d6b7ef4b69dd7cfcdd7bbaf1c9a9cb +Author: Siddhesh Poyarekar +Date: Mon Mar 7 20:24:37 2022 +0530 + + gaih_inet: split loopback lookup into its own function + + Flatten the condition nesting and replace the alloca for RET.AT/ATR with + a single array LOCAL_AT[2]. This gets rid of alloca and alloca + accounting. + + `git diff -b` is probably the best way to view this change since much of + the diff is whitespace changes. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit 657472b2a50f67b12e5bbe5827582c9c2bb82dc3) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 6be109d07f7fcce0..827c43b369836de9 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -1004,6 +1004,32 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req, + return -EAI_NODATA; + } + ++/* Add local address information into RES. RES->AT is assumed to have enough ++ space for two tuples and is zeroed out. */ ++ ++static void ++get_local_addresses (const struct addrinfo *req, struct gaih_result *res) ++{ ++ struct gaih_addrtuple *atr = res->at; ++ if (req->ai_family == AF_UNSPEC) ++ res->at->next = res->at + 1; ++ ++ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) ++ { ++ res->at->family = AF_INET6; ++ if ((req->ai_flags & AI_PASSIVE) == 0) ++ memcpy (res->at->addr, &in6addr_loopback, sizeof (struct in6_addr)); ++ atr = res->at->next; ++ } ++ ++ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) ++ { ++ atr->family = AF_INET; ++ if ((req->ai_flags & AI_PASSIVE) == 0) ++ atr->addr[0] = htonl (INADDR_LOOPBACK); ++ } ++} ++ + static int + gaih_inet (const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai, +@@ -1014,10 +1040,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + + const char *orig_name = name; + +- /* Reserve stack memory for the scratch buffer in the getaddrinfo +- function. */ +- size_t alloca_used = sizeof (struct scratch_buffer); +- + int rc; + if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0) + return rc; +@@ -1027,76 +1049,51 @@ gaih_inet (const char *name, const struct gaih_service *service, + int result = 0; + + struct gaih_result res = {0}; +- if (name != NULL) ++ struct gaih_addrtuple local_at[2] = {0}; ++ ++ res.at = local_at; ++ ++ if (__glibc_unlikely (name == NULL)) + { +- if (req->ai_flags & AI_IDN) +- { +- char *out; +- result = __idna_to_dns_encoding (name, &out); +- if (result != 0) +- return -result; +- name = out; +- malloc_name = true; +- } ++ get_local_addresses (req, &res); ++ goto process_list; ++ } + +- res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); +- res.at->scopeid = 0; +- res.at->next = NULL; ++ if (req->ai_flags & AI_IDN) ++ { ++ char *out; ++ result = __idna_to_dns_encoding (name, &out); ++ if (result != 0) ++ return -result; ++ name = out; ++ malloc_name = true; ++ } + +- if ((result = text_to_binary_address (name, req, &res)) != 0) +- goto free_and_return; +- else if (res.at != NULL) +- goto process_list; ++ if ((result = text_to_binary_address (name, req, &res)) != 0) ++ goto free_and_return; ++ else if (res.at != NULL) ++ goto process_list; + +- if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0) +- goto free_and_return; +- else if (res.at != NULL) +- goto process_list; ++ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0) ++ goto free_and_return; ++ else if (res.at != NULL) ++ goto process_list; + + #ifdef USE_NSCD +- if ((result = get_nscd_addresses (name, req, &res)) != 0) +- goto free_and_return; +- else if (res.at != NULL) +- goto process_list; ++ if ((result = get_nscd_addresses (name, req, &res)) != 0) ++ goto free_and_return; ++ else if (res.at != NULL) ++ goto process_list; + #endif + +- if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0) +- goto free_and_return; +- else if (res.at != NULL) +- goto process_list; +- +- /* None of the lookups worked, so name not found. */ +- result = -EAI_NONAME; +- goto free_and_return; +- } +- else +- { +- struct gaih_addrtuple *atr; +- atr = res.at = alloca_account (sizeof (struct gaih_addrtuple), +- alloca_used); +- memset (res.at, '\0', sizeof (struct gaih_addrtuple)); +- +- if (req->ai_family == AF_UNSPEC) +- { +- res.at->next = __alloca (sizeof (struct gaih_addrtuple)); +- memset (res.at->next, '\0', sizeof (struct gaih_addrtuple)); +- } +- +- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) +- { +- res.at->family = AF_INET6; +- if ((req->ai_flags & AI_PASSIVE) == 0) +- memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr)); +- atr = res.at->next; +- } ++ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0) ++ goto free_and_return; ++ else if (res.at != NULL) ++ goto process_list; + +- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) +- { +- atr->family = AF_INET; +- if ((req->ai_flags & AI_PASSIVE) == 0) +- atr->addr[0] = htonl (INADDR_LOOPBACK); +- } +- } ++ /* None of the lookups worked, so name not found. */ ++ result = -EAI_NONAME; ++ goto free_and_return; + + process_list: + { diff --git a/SOURCES/glibc-RHEL-2426-11.patch b/SOURCES/glibc-RHEL-2426-11.patch new file mode 100644 index 0000000..4b7d019 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-11.patch @@ -0,0 +1,208 @@ +commit 92478a808f477480adbc5ca3d9a4a1bc27fc13ae +Author: Siddhesh Poyarekar +Date: Mon Mar 7 20:38:31 2022 +0530 + + gaih_inet: Split result generation into its own function + + Simplify the loop a wee bit and clean up variable names too. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit ac4653ef503d1e87893d1a6714748a1cdf4bf7ad) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 827c43b369836de9..1008f247365ea009 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -1030,6 +1030,87 @@ get_local_addresses (const struct addrinfo *req, struct gaih_result *res) + } + } + ++/* Generate results in PAI and its count in NADDRS. Return 0 on success or an ++ error code on failure. */ ++ ++static int ++generate_addrinfo (const struct addrinfo *req, struct gaih_result *res, ++ const struct gaih_servtuple *st, struct addrinfo **pai, ++ unsigned int *naddrs) ++{ ++ size_t socklen; ++ sa_family_t family; ++ ++ /* Buffer is the size of an unformatted IPv6 address in printable format. */ ++ for (struct gaih_addrtuple *at = res->at; at != NULL; at = at->next) ++ { ++ family = at->family; ++ if (family == AF_INET6) ++ { ++ socklen = sizeof (struct sockaddr_in6); ++ ++ /* If we looked up IPv4 mapped address discard them here if ++ the caller isn't interested in all address and we have ++ found at least one IPv6 address. */ ++ if (res->got_ipv6 ++ && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED ++ && IN6_IS_ADDR_V4MAPPED (at->addr)) ++ continue; ++ } ++ else ++ socklen = sizeof (struct sockaddr_in); ++ ++ for (int i = 0; st[i].set; i++) ++ { ++ struct addrinfo *ai; ++ ai = *pai = malloc (sizeof (struct addrinfo) + socklen); ++ if (ai == NULL) ++ return -EAI_MEMORY; ++ ++ ai->ai_flags = req->ai_flags; ++ ai->ai_family = family; ++ ai->ai_socktype = st[i].socktype; ++ ai->ai_protocol = st[i].protocol; ++ ai->ai_addrlen = socklen; ++ ai->ai_addr = (void *) (ai + 1); ++ ++ /* We only add the canonical name once. */ ++ ai->ai_canonname = res->canon; ++ res->canon = NULL; ++ ++#ifdef _HAVE_SA_LEN ++ ai->ai_addr->sa_len = socklen; ++#endif /* _HAVE_SA_LEN */ ++ ai->ai_addr->sa_family = family; ++ ++ /* In case of an allocation error the list must be NULL ++ terminated. */ ++ ai->ai_next = NULL; ++ ++ if (family == AF_INET6) ++ { ++ struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) ai->ai_addr; ++ sin6p->sin6_port = st[i].port; ++ sin6p->sin6_flowinfo = 0; ++ memcpy (&sin6p->sin6_addr, at->addr, sizeof (struct in6_addr)); ++ sin6p->sin6_scope_id = at->scopeid; ++ } ++ else ++ { ++ struct sockaddr_in *sinp = (struct sockaddr_in *) ai->ai_addr; ++ sinp->sin_port = st[i].port; ++ memcpy (&sinp->sin_addr, at->addr, sizeof (struct in_addr)); ++ memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero)); ++ } ++ ++ pai = &(ai->ai_next); ++ } ++ ++ ++*naddrs; ++ } ++ return 0; ++} ++ + static int + gaih_inet (const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai, +@@ -1096,98 +1177,13 @@ gaih_inet (const char *name, const struct gaih_service *service, + goto free_and_return; + + process_list: +- { +- /* Set up the canonical name if we need it. */ +- if ((result = process_canonname (req, orig_name, &res)) != 0) +- goto free_and_return; +- +- struct gaih_addrtuple *at2 = res.at; +- size_t socklen; +- sa_family_t family; +- +- /* +- buffer is the size of an unformatted IPv6 address in printable format. +- */ +- while (at2 != NULL) +- { +- family = at2->family; +- if (family == AF_INET6) +- { +- socklen = sizeof (struct sockaddr_in6); +- +- /* If we looked up IPv4 mapped address discard them here if +- the caller isn't interested in all address and we have +- found at least one IPv6 address. */ +- if (res.got_ipv6 +- && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED +- && IN6_IS_ADDR_V4MAPPED (at2->addr)) +- goto ignore; +- } +- else +- socklen = sizeof (struct sockaddr_in); +- +- for (int i = 0; st[i].set; i++) +- { +- struct addrinfo *ai; +- ai = *pai = malloc (sizeof (struct addrinfo) + socklen); +- if (ai == NULL) +- { +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- +- ai->ai_flags = req->ai_flags; +- ai->ai_family = family; +- ai->ai_socktype = st[i].socktype; +- ai->ai_protocol = st[i].protocol; +- ai->ai_addrlen = socklen; +- ai->ai_addr = (void *) (ai + 1); +- +- /* We only add the canonical name once. */ +- ai->ai_canonname = res.canon; +- res.canon = NULL; +- +-#ifdef _HAVE_SA_LEN +- ai->ai_addr->sa_len = socklen; +-#endif /* _HAVE_SA_LEN */ +- ai->ai_addr->sa_family = family; +- +- /* In case of an allocation error the list must be NULL +- terminated. */ +- ai->ai_next = NULL; +- +- if (family == AF_INET6) +- { +- struct sockaddr_in6 *sin6p = +- (struct sockaddr_in6 *) ai->ai_addr; +- +- sin6p->sin6_port = st[i].port; +- sin6p->sin6_flowinfo = 0; +- memcpy (&sin6p->sin6_addr, +- at2->addr, sizeof (struct in6_addr)); +- sin6p->sin6_scope_id = at2->scopeid; +- } +- else +- { +- struct sockaddr_in *sinp = +- (struct sockaddr_in *) ai->ai_addr; +- sinp->sin_port = st[i].port; +- memcpy (&sinp->sin_addr, +- at2->addr, sizeof (struct in_addr)); +- memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero)); +- } +- +- pai = &(ai->ai_next); +- } +- +- ++*naddrs; ++ /* Set up the canonical name if we need it. */ ++ if ((result = process_canonname (req, orig_name, &res)) != 0) ++ goto free_and_return; + +- ignore: +- at2 = at2->next; +- } +- } ++ result = generate_addrinfo (req, &res, st, pai, naddrs); + +- free_and_return: ++free_and_return: + if (malloc_name) + free ((char *) name); + free (addrmem); diff --git a/SOURCES/glibc-RHEL-2426-12.patch b/SOURCES/glibc-RHEL-2426-12.patch new file mode 100644 index 0000000..7e31ade --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-12.patch @@ -0,0 +1,34 @@ +commit cc4544ef8069a14c67a46b7e8e28eff1dc102050 +Author: Siddhesh Poyarekar +Date: Wed Mar 2 11:45:29 2022 +0530 + + gethosts: Return EAI_MEMORY on allocation failure + + All other cases of failures due to lack of memory return EAI_MEMORY, so + it seems wrong to return EAI_SYSTEM here. The only reason + convert_hostent_to_gaih_addrtuple could fail is on calloc failure. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit b587456c0e7b59dcfdbd2d44db000a3bc8244e57) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 1008f247365ea009..37260d6e6f292186 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -303,13 +303,13 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name, + else if (status == NSS_STATUS_SUCCESS) + { + if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res)) +- return -EAI_SYSTEM; ++ return -EAI_MEMORY; + + if (localcanon != NULL && res->canon == NULL) + { + char *canonbuf = __strdup (localcanon); + if (canonbuf == NULL) +- return -EAI_SYSTEM; ++ return -EAI_MEMORY; + res->canon = canonbuf; + } + } diff --git a/SOURCES/glibc-RHEL-2426-13.patch b/SOURCES/glibc-RHEL-2426-13.patch new file mode 100644 index 0000000..d288e17 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-13.patch @@ -0,0 +1,316 @@ +commit e09ee267c03e3150c2c9ba28625ab130705a485e +Author: Siddhesh Poyarekar +Date: Fri Sep 15 13:51:12 2023 -0400 + + getaddrinfo: Fix use after free in getcanonname (CVE-2023-4806) + + When an NSS plugin only implements the _gethostbyname2_r and + _getcanonname_r callbacks, getaddrinfo could use memory that was freed + during tmpbuf resizing, through h_name in a previous query response. + + The backing store for res->at->name when doing a query with + gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in + gethosts during the query. For AF_INET6 lookup with AI_ALL | + AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second + for a v4 lookup. In this case, if the first call reallocates tmpbuf + enough number of times, resulting in a malloc, th->h_name (that + res->at->name refers to) ends up on a heap allocated storage in tmpbuf. + Now if the second call to gethosts also causes the plugin callback to + return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF + reference in res->at->name. This then gets dereferenced in the + getcanonname_r plugin call, resulting in the use after free. + + Fix this by copying h_name over and freeing it at the end. This + resolves BZ #30843, which is assigned CVE-2023-4806. + + Signed-off-by: Siddhesh Poyarekar + (cherry picked from commit 973fe93a5675c42798b2161c6f29c01b0e243994) + +diff --git a/nss/Makefile b/nss/Makefile +index 333edb1588ede881..64b29745131d3cf5 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -81,6 +81,7 @@ tests-container := \ + tst-nss-test3 \ + tst-reload1 \ + tst-reload2 \ ++ tst-nss-gai-hv2-canonname \ + # tests-container + + # Tests which need libdl +@@ -144,7 +145,8 @@ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) + ifeq ($(build-static-nss),yes) + tests-static += tst-nss-static + endif +-extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os ++extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \ ++ nss_test_gai_hv2_canonname.os + + include ../Rules + +@@ -179,12 +181,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver + libof-nss_test1 = extramodules + libof-nss_test2 = extramodules + libof-nss_test_errno = extramodules ++libof-nss_test_gai_hv2_canonname = extramodules + $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) + $(build-module) ++$(objpfx)/libnss_test_gai_hv2_canonname.so: \ ++ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps) ++ $(build-module) + $(objpfx)nss_test2.os : nss_test1.c + # Use the nss_files suffix for these objects as well. + $(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so +@@ -194,10 +200,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so + $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ + $(objpfx)/libnss_test_errno.so + $(make-link) ++$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so ++ $(make-link) + $(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \ + $(objpfx)/libnss_test1.so$(libnss_files.so-version) \ + $(objpfx)/libnss_test2.so$(libnss_files.so-version) \ +- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) ++ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version) + + ifeq (yes,$(have-thread-library)) + $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c +new file mode 100644 +index 0000000000000000..4439c83c9f40cf43 +--- /dev/null ++++ b/nss/nss_test_gai_hv2_canonname.c +@@ -0,0 +1,56 @@ ++/* NSS service provider that only provides gethostbyname2_r. ++ Copyright 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 ++ . */ ++ ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++/* Catch misnamed and functions. */ ++#pragma GCC diagnostic error "-Wmissing-prototypes" ++NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname) ++ ++extern enum nss_status _nss_files_gethostbyname2_r (const char *, int, ++ struct hostent *, char *, ++ size_t, int *, int *); ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af, ++ struct hostent *result, ++ char *buffer, size_t buflen, ++ int *errnop, int *herrnop) ++{ ++ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop, ++ herrnop); ++} ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer, ++ size_t buflen, char **result, ++ int *errnop, int *h_errnop) ++{ ++ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail ++ the test. */ ++ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME)) ++ || buflen < sizeof (QUERYNAME)) ++ abort (); ++ ++ strncpy (buffer, name, buflen); ++ *result = buffer; ++ return NSS_STATUS_SUCCESS; ++} +diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c +new file mode 100644 +index 0000000000000000..d5f10c07d6a90773 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.c +@@ -0,0 +1,63 @@ ++/* Test NSS query path for plugins that only implement gethostbyname2 ++ (#30843). ++ Copyright 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++#define PREPARE do_prepare ++ ++static void do_prepare (int a, char **av) ++{ ++ FILE *hosts = xfopen ("/etc/hosts", "w"); ++ for (unsigned i = 2; i < 255; i++) ++ { ++ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i); ++ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i); ++ } ++ xfclose (hosts); ++} ++ ++static int ++do_test (void) ++{ ++ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); ++ ++ struct addrinfo hints = {}; ++ struct addrinfo *result = NULL; ++ ++ hints.ai_family = AF_INET6; ++ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME; ++ ++ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result); ++ ++ if (ret != 0) ++ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret)); ++ ++ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME); ++ ++ freeaddrinfo(result); ++ return 0; ++} ++ ++#include +diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h +new file mode 100644 +index 0000000000000000..14f2a9cb0867dff9 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.h +@@ -0,0 +1 @@ ++#define QUERYNAME "test.example.com" +diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 +diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +new file mode 100644 +index 0000000000000000..31848b4a28524af6 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +@@ -0,0 +1,2 @@ ++cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2 ++su +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 37260d6e6f292186..10dc63542f337693 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -120,6 +120,7 @@ struct gaih_result + { + struct gaih_addrtuple *at; + char *canon; ++ char *h_name; + bool free_at; + bool got_ipv6; + }; +@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res) + if (res->free_at) + free (res->at); + free (res->canon); ++ free (res->h_name); + memset (res, 0, sizeof (*res)); + } + +@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + return 0; + } + +-/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name +- is not copied, and the struct hostent object must not be deallocated +- prematurely. The new addresses are appended to the tuple array in RES. */ ++/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new ++ addresses are appended to the tuple array in RES. */ + static bool + convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + struct hostent *h, struct gaih_result *res) +@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + res->at = array; + res->free_at = true; + ++ /* Duplicate h_name because it may get reclaimed when the underlying storage ++ is freed. */ ++ if (res->h_name == NULL) ++ { ++ res->h_name = __strdup (h->h_name); ++ if (res->h_name == NULL) ++ return false; ++ } ++ + /* Update the next pointers on reallocation. */ + for (size_t i = 0; i < old; i++) + array[i].next = array + i + 1; +@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + } + array[i].next = array + i + 1; + } +- array[0].name = h->h_name; + array[count - 1].next = NULL; + + return true; +@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name, + memory allocation failure. The returned string is allocated on the + heap; the caller has to free it. */ + static char * +-getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) ++getcanonname (nss_action_list nip, const char *hname, const char *name) + { + nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r"); + char *s = (char *) name; + if (cfct != NULL) + { + char buf[256]; +- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf), +- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS) ++ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno, ++ &h_errno)) != NSS_STATUS_SUCCESS) + /* If the canonical name cannot be determined, use the passed + string. */ + s = (char *) name; +@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req, + if ((req->ai_flags & AI_CANONNAME) != 0 + && res->canon == NULL) + { +- char *canonbuf = getcanonname (nip, res->at, name); ++ char *canonbuf = getcanonname (nip, res->h_name, name); + if (canonbuf == NULL) + { + __resolv_context_put (res_ctx); diff --git a/SOURCES/glibc-RHEL-2426-14.patch b/SOURCES/glibc-RHEL-2426-14.patch new file mode 100644 index 0000000..0a4d027 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-14.patch @@ -0,0 +1,37 @@ +commit 57e349b1b0df1aee2dcd19dae1f324bde25ff8f0 +Author: H.J. Lu +Date: Wed Dec 8 07:02:27 2021 -0800 + + Disable DT_RUNPATH on NSS tests [BZ #28455] + + The glibc internal NSS functions should always load NSS modules from + the system. For testing purpose, disable DT_RUNPATH on NSS tests so + that the glibc internal NSS functions can load testing NSS modules + via DT_RPATH. + + This partially fixes BZ #28455. + + Reviewed-by: Carlos O'Donell + +Conflicts: + nss/Makefile + (different test backport order) + +diff --git a/nss/Makefile b/nss/Makefile +index 64b29745131d3cf5..9af46fb3a8195809 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -215,3 +215,13 @@ endif + + $(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so + $(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so ++ ++# Disable DT_RUNPATH on NSS tests so that the glibc internal NSS ++# functions can load testing NSS modules via DT_RPATH. ++LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test2 = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags diff --git a/SOURCES/glibc-RHEL-2426-15.patch b/SOURCES/glibc-RHEL-2426-15.patch new file mode 100644 index 0000000..fc8d4b4 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-15.patch @@ -0,0 +1,84 @@ +commit ec6b95c3303c700eb89eebeda2d7264cc184a796 +Author: Romain Geissler +Date: Mon Sep 25 01:21:51 2023 +0100 + + Fix leak in getaddrinfo introduced by the fix for CVE-2023-4806 [BZ #30843] + + This patch fixes a very recently added leak in getaddrinfo. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/nss/Makefile b/nss/Makefile +index 9af46fb3a8195809..62a68880198c243c 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -148,6 +148,15 @@ endif + extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \ + nss_test_gai_hv2_canonname.os + ++ifeq ($(run-built-tests),yes) ++ifneq (no,$(PERL)) ++tests-special += $(objpfx)mtrace-tst-nss-gai-hv2-canonname.out ++endif ++endif ++ ++generated += mtrace-tst-nss-gai-hv2-canonname.out \ ++ tst-nss-gai-hv2-canonname.mtrace ++ + include ../Rules + + ifeq (yes,$(have-selinux)) +@@ -216,6 +225,17 @@ endif + $(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so + $(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so + ++tst-nss-gai-hv2-canonname-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \ ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++$(objpfx)mtrace-tst-nss-gai-hv2-canonname.out: \ ++ $(objpfx)tst-nss-gai-hv2-canonname.out ++ { test -r $(objpfx)tst-nss-gai-hv2-canonname.mtrace \ ++ || ( echo "tst-nss-gai-hv2-canonname.mtrace does not exist"; exit 77; ) \ ++ && $(common-objpfx)malloc/mtrace \ ++ $(objpfx)tst-nss-gai-hv2-canonname.mtrace; } > $@; \ ++ $(evaluate-test) ++ + # Disable DT_RUNPATH on NSS tests so that the glibc internal NSS + # functions can load testing NSS modules via DT_RPATH. + LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags +diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c +index d5f10c07d6a90773..7db53cf09da8dcb6 100644 +--- a/nss/tst-nss-gai-hv2-canonname.c ++++ b/nss/tst-nss-gai-hv2-canonname.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include "nss/tst-nss-gai-hv2-canonname.h" +@@ -41,6 +42,8 @@ static void do_prepare (int a, char **av) + static int + do_test (void) + { ++ mtrace (); ++ + __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); + + struct addrinfo hints = {}; +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 10dc63542f337693..d6046a707f1d742a 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -1196,9 +1196,7 @@ free_and_return: + if (malloc_name) + free ((char *) name); + free (addrmem); +- if (res.free_at) +- free (res.at); +- free (res.canon); ++ gaih_result_reset (&res); + + return result; + } diff --git a/SOURCES/glibc-RHEL-2426-2.patch b/SOURCES/glibc-RHEL-2426-2.patch new file mode 100644 index 0000000..c431d61 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-2.patch @@ -0,0 +1,248 @@ +commit b195fd86c616b147dad3a63498b79e0dedb4662b +Author: Siddhesh Poyarekar +Date: Mon Mar 7 22:17:36 2022 +0530 + + gaih_inet: Simplify canon name resolution + + Simplify logic for allocation of canon to remove the canonbuf variable; + canon now always points to an allocated block. Also pull the canon name + set into a separate function. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit d01411f6bc61429fc027c38827bf3103b48eef2e) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 702d8a50e0c218d2..5c0d873e1d766099 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -285,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + \ + if (localcanon != NULL && canon == NULL) \ + { \ +- canonbuf = __strdup (localcanon); \ ++ char *canonbuf = __strdup (localcanon); \ + if (canonbuf == NULL) \ + { \ + __resolv_context_put (res_ctx); \ +@@ -323,6 +323,41 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) + return __strdup (name); + } + ++/* Process looked up canonical name and if necessary, decode to IDNA. Result ++ is a new string written to CANONP and the earlier string is freed. */ ++ ++static int ++process_canonname (const struct addrinfo *req, const char *orig_name, ++ char **canonp) ++{ ++ char *canon = *canonp; ++ ++ if ((req->ai_flags & AI_CANONNAME) != 0) ++ { ++ bool do_idn = req->ai_flags & AI_CANONIDN; ++ if (do_idn) ++ { ++ char *out; ++ int rc = __idna_from_dns_encoding (canon ?: orig_name, &out); ++ if (rc == 0) ++ { ++ free (canon); ++ canon = out; ++ } ++ else if (rc == EAI_IDN_ENCODE) ++ /* Use the punycode name as a fallback. */ ++ do_idn = false; ++ else ++ return -rc; ++ } ++ if (!do_idn && canon == NULL && (canon = __strdup (orig_name)) == NULL) ++ return -EAI_MEMORY; ++ } ++ ++ *canonp = canon; ++ return 0; ++} ++ + static int + gaih_inet (const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai, +@@ -332,7 +367,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv; + struct gaih_addrtuple *at = NULL; + bool got_ipv6 = false; +- const char *canon = NULL; ++ char *canon = NULL; + const char *orig_name = name; + + /* Reserve stack memory for the scratch buffer in the getaddrinfo +@@ -453,7 +488,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + + bool malloc_name = false; + struct gaih_addrtuple *addrmem = NULL; +- char *canonbuf = NULL; + int result = 0; + + if (name != NULL) +@@ -495,7 +529,15 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + + if (req->ai_flags & AI_CANONNAME) +- canon = name; ++ { ++ char *canonbuf = __strdup (name); ++ if (canonbuf == NULL) ++ { ++ result = -EAI_MEMORY; ++ goto free_and_return; ++ } ++ canon = canonbuf; ++ } + + goto process_list; + } +@@ -545,7 +587,15 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + + if (req->ai_flags & AI_CANONNAME) +- canon = name; ++ { ++ char *canonbuf = __strdup (name); ++ if (canonbuf == NULL) ++ { ++ result = -EAI_MEMORY; ++ goto free_and_return; ++ } ++ canon = canonbuf; ++ } + + goto process_list; + } +@@ -676,9 +726,9 @@ gaih_inet (const char *name, const struct gaih_service *service, + (*pat)->next = NULL; + if (added_canon || air->canon == NULL) + (*pat)->name = NULL; +- else if (canonbuf == NULL) ++ else if (canon == NULL) + { +- canonbuf = __strdup (air->canon); ++ char *canonbuf = __strdup (air->canon); + if (canonbuf == NULL) + { + result = -EAI_MEMORY; +@@ -748,9 +798,9 @@ gaih_inet (const char *name, const struct gaih_service *service, + /* Always start afresh; continue should discard previous results + and the hosts database does not support merge. */ + at = NULL; +- free (canonbuf); ++ free (canon); + free (addrmem); +- canon = canonbuf = NULL; ++ canon = NULL; + addrmem = NULL; + got_ipv6 = false; + +@@ -805,7 +855,16 @@ gaih_inet (const char *name, const struct gaih_service *service, + no_data = 1; + + if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) +- canon = at->name; ++ { ++ char *canonbuf = __strdup (at->name); ++ if (canonbuf == NULL) ++ { ++ __resolv_context_put (res_ctx); ++ result = -EAI_MEMORY; ++ goto free_and_return; ++ } ++ canon = canonbuf; ++ } + + struct gaih_addrtuple **pat = &at; + +@@ -893,7 +952,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + if ((req->ai_flags & AI_CANONNAME) != 0 + && canon == NULL) + { +- canonbuf = getcanonname (nip, at, name); ++ char *canonbuf = getcanonname (nip, at, name); + if (canonbuf == NULL) + { + __resolv_context_put (res_ctx); +@@ -1004,6 +1063,10 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + + { ++ /* Set up the canonical name if we need it. */ ++ if ((result = process_canonname (req, orig_name, &canon)) != 0) ++ goto free_and_return; ++ + struct gaih_servtuple *st2; + struct gaih_addrtuple *at2 = at; + size_t socklen; +@@ -1014,48 +1077,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + */ + while (at2 != NULL) + { +- /* Only the first entry gets the canonical name. */ +- if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0) +- { +- if (canon == NULL) +- /* If the canonical name cannot be determined, use +- the passed in string. */ +- canon = orig_name; +- +- bool do_idn = req->ai_flags & AI_CANONIDN; +- if (do_idn) +- { +- char *out; +- int rc = __idna_from_dns_encoding (canon, &out); +- if (rc == 0) +- canon = out; +- else if (rc == EAI_IDN_ENCODE) +- /* Use the punycode name as a fallback. */ +- do_idn = false; +- else +- { +- result = -rc; +- goto free_and_return; +- } +- } +- if (!do_idn) +- { +- if (canonbuf != NULL) +- /* We already allocated the string using malloc, but +- the buffer is now owned by canon. */ +- canonbuf = NULL; +- else +- { +- canon = __strdup (canon); +- if (canon == NULL) +- { +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- } +- } +- } +- + family = at2->family; + if (family == AF_INET6) + { +@@ -1078,7 +1099,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + ai = *pai = malloc (sizeof (struct addrinfo) + socklen); + if (ai == NULL) + { +- free ((char *) canon); + result = -EAI_MEMORY; + goto free_and_return; + } +@@ -1138,7 +1158,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + if (malloc_name) + free ((char *) name); + free (addrmem); +- free (canonbuf); ++ free (canon); + + return result; + } diff --git a/SOURCES/glibc-RHEL-2426-3.patch b/SOURCES/glibc-RHEL-2426-3.patch new file mode 100644 index 0000000..27582f2 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-3.patch @@ -0,0 +1,86 @@ +commit f7efb43738f255db32cfa4e84a491c09f6da66e2 +Author: Siddhesh Poyarekar +Date: Thu Mar 3 23:07:42 2022 +0530 + + getaddrinfo: Fix leak with AI_ALL [BZ #28852] + + Use realloc in convert_hostent_to_gaih_addrtuple and fix up pointers in + the result list so that a single block is maintained for + hostbyname3_r/hostbyname2_r and freed in gaih_inet. This result is + never merged with any other results, since the hosts database does not + permit merging. + + Resolves BZ #28852. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit 300460460706ce3ffe29a7df8966e68323ec5bf1) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 5c0d873e1d766099..ed70e6cb3944d219 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -189,19 +189,16 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + return 0; + } + +-/* Convert struct hostent to a list of struct gaih_addrtuple objects. +- h_name is not copied, and the struct hostent object must not be +- deallocated prematurely. *RESULT must be NULL or a pointer to a +- linked-list. The new addresses are appended at the end. */ ++/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name ++ is not copied, and the struct hostent object must not be deallocated ++ prematurely. The new addresses are appended to the tuple array in ++ RESULT. */ + static bool + convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + int family, + struct hostent *h, + struct gaih_addrtuple **result) + { +- while (*result) +- result = &(*result)->next; +- + /* Count the number of addresses in h->h_addr_list. */ + size_t count = 0; + for (char **p = h->h_addr_list; *p != NULL; ++p) +@@ -212,10 +209,30 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr)) + return true; + +- struct gaih_addrtuple *array = calloc (count, sizeof (*array)); ++ struct gaih_addrtuple *array = *result; ++ size_t old = 0; ++ ++ while (array != NULL) ++ { ++ old++; ++ array = array->next; ++ } ++ ++ array = realloc (*result, (old + count) * sizeof (*array)); ++ + if (array == NULL) + return false; + ++ *result = array; ++ ++ /* Update the next pointers on reallocation. */ ++ for (size_t i = 0; i < old; i++) ++ array[i].next = array + i + 1; ++ ++ array += old; ++ ++ memset (array, 0, count * sizeof (*array)); ++ + for (size_t i = 0; i < count; ++i) + { + if (family == AF_INET && req->ai_family == AF_INET6) +@@ -235,7 +252,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + array[0].name = h->h_name; + array[count - 1].next = NULL; + +- *result = array; + return true; + } + diff --git a/SOURCES/glibc-RHEL-2426-4.patch b/SOURCES/glibc-RHEL-2426-4.patch new file mode 100644 index 0000000..427630d --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-4.patch @@ -0,0 +1,285 @@ +commit e05e5889b8a307fe4be55b03bcbd7a1c62fc2f2d +Author: Siddhesh Poyarekar +Date: Thu Feb 10 13:27:11 2022 +0530 + + gaih_inet: Simplify service resolution + + Refactor the code to split out the service resolution code into a + separate function. Allocate the service tuples array just once to the + size of the typeproto array, thus avoiding the unnecessary pointer + chasing and stack allocations. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit 8d6cf99f2fb81a097f9334c125e5c23604af1a98) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index ed70e6cb3944d219..8c78ef9570fe0f58 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -100,14 +100,12 @@ struct gaih_service + + struct gaih_servtuple + { +- struct gaih_servtuple *next; + int socktype; + int protocol; + int port; ++ bool set; + }; + +-static const struct gaih_servtuple nullserv; +- + + struct gaih_typeproto + { +@@ -180,11 +178,11 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + } + while (r); + +- st->next = NULL; + st->socktype = tp->socktype; + st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) + ? req->ai_protocol : tp->protocol); + st->port = s->s_port; ++ st->set = true; + + return 0; + } +@@ -375,20 +373,11 @@ process_canonname (const struct addrinfo *req, const char *orig_name, + } + + static int +-gaih_inet (const char *name, const struct gaih_service *service, +- const struct addrinfo *req, struct addrinfo **pai, +- unsigned int *naddrs, struct scratch_buffer *tmpbuf) ++get_servtuples (const struct gaih_service *service, const struct addrinfo *req, ++ struct gaih_servtuple *st, struct scratch_buffer *tmpbuf) + { ++ int i; + const struct gaih_typeproto *tp = gaih_inet_typeproto; +- struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv; +- struct gaih_addrtuple *at = NULL; +- bool got_ipv6 = false; +- char *canon = NULL; +- const char *orig_name = name; +- +- /* Reserve stack memory for the scratch buffer in the getaddrinfo +- function. */ +- size_t alloca_used = sizeof (struct scratch_buffer); + + if (req->ai_protocol || req->ai_socktype) + { +@@ -410,98 +399,88 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + } + +- int port = 0; +- if (service != NULL) ++ if (service != NULL && (tp->protoflag & GAI_PROTO_NOSERVICE) != 0) ++ return -EAI_SERVICE; ++ ++ if (service == NULL || service->num >= 0) + { +- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) +- return -EAI_SERVICE; ++ int port = service != NULL ? htons (service->num) : 0; + +- if (service->num < 0) ++ if (req->ai_socktype || req->ai_protocol) + { +- if (tp->name[0]) +- { +- st = (struct gaih_servtuple *) +- alloca_account (sizeof (struct gaih_servtuple), alloca_used); +- +- int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf); +- if (__glibc_unlikely (rc != 0)) +- return rc; +- } +- else +- { +- struct gaih_servtuple **pst = &st; +- for (tp++; tp->name[0]; tp++) +- { +- struct gaih_servtuple *newp; ++ st[0].socktype = tp->socktype; ++ st[0].protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ++ ? req->ai_protocol : tp->protocol); ++ st[0].port = port; ++ st[0].set = true; + +- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) +- continue; ++ return 0; ++ } + +- if (req->ai_socktype != 0 +- && req->ai_socktype != tp->socktype) +- continue; +- if (req->ai_protocol != 0 +- && !(tp->protoflag & GAI_PROTO_PROTOANY) +- && req->ai_protocol != tp->protocol) +- continue; ++ /* Neither socket type nor protocol is set. Return all socket types ++ we know about. */ ++ for (i = 0, ++tp; tp->name[0]; ++tp) ++ if (tp->defaultflag) ++ { ++ st[i].socktype = tp->socktype; ++ st[i].protocol = tp->protocol; ++ st[i].port = port; ++ st[i++].set = true; ++ } + +- newp = (struct gaih_servtuple *) +- alloca_account (sizeof (struct gaih_servtuple), +- alloca_used); ++ return 0; ++ } + +- if (gaih_inet_serv (service->name, +- tp, req, newp, tmpbuf) != 0) +- continue; ++ if (tp->name[0]) ++ return gaih_inet_serv (service->name, tp, req, st, tmpbuf); + +- *pst = newp; +- pst = &(newp->next); +- } +- if (st == (struct gaih_servtuple *) &nullserv) +- return -EAI_SERVICE; +- } +- } +- else +- { +- port = htons (service->num); +- goto got_port; +- } +- } +- else ++ for (i = 0, tp++; tp->name[0]; tp++) + { +- got_port: ++ if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) ++ continue; + +- if (req->ai_socktype || req->ai_protocol) +- { +- st = alloca_account (sizeof (struct gaih_servtuple), alloca_used); +- st->next = NULL; +- st->socktype = tp->socktype; +- st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) +- ? req->ai_protocol : tp->protocol); +- st->port = port; +- } +- else +- { +- /* Neither socket type nor protocol is set. Return all socket types +- we know about. */ +- struct gaih_servtuple **lastp = &st; +- for (++tp; tp->name[0]; ++tp) +- if (tp->defaultflag) +- { +- struct gaih_servtuple *newp; ++ if (req->ai_socktype != 0 ++ && req->ai_socktype != tp->socktype) ++ continue; ++ if (req->ai_protocol != 0 ++ && !(tp->protoflag & GAI_PROTO_PROTOANY) ++ && req->ai_protocol != tp->protocol) ++ continue; + +- newp = alloca_account (sizeof (struct gaih_servtuple), +- alloca_used); +- newp->next = NULL; +- newp->socktype = tp->socktype; +- newp->protocol = tp->protocol; +- newp->port = port; ++ if (gaih_inet_serv (service->name, ++ tp, req, &st[i], tmpbuf) != 0) ++ continue; + +- *lastp = newp; +- lastp = &newp->next; +- } +- } ++ i++; + } + ++ if (!st[0].set) ++ return -EAI_SERVICE; ++ ++ return 0; ++} ++ ++static int ++gaih_inet (const char *name, const struct gaih_service *service, ++ const struct addrinfo *req, struct addrinfo **pai, ++ unsigned int *naddrs, struct scratch_buffer *tmpbuf) ++{ ++ struct gaih_servtuple st[sizeof (gaih_inet_typeproto) ++ / sizeof (struct gaih_typeproto)] = {0}; ++ ++ struct gaih_addrtuple *at = NULL; ++ bool got_ipv6 = false; ++ char *canon = NULL; ++ const char *orig_name = name; ++ ++ /* Reserve stack memory for the scratch buffer in the getaddrinfo ++ function. */ ++ size_t alloca_used = sizeof (struct scratch_buffer); ++ ++ int rc; ++ if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0) ++ return rc; ++ + bool malloc_name = false; + struct gaih_addrtuple *addrmem = NULL; + int result = 0; +@@ -1083,7 +1062,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + if ((result = process_canonname (req, orig_name, &canon)) != 0) + goto free_and_return; + +- struct gaih_servtuple *st2; + struct gaih_addrtuple *at2 = at; + size_t socklen; + sa_family_t family; +@@ -1109,7 +1087,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + else + socklen = sizeof (struct sockaddr_in); + +- for (st2 = st; st2 != NULL; st2 = st2->next) ++ for (int i = 0; st[i].set; i++) + { + struct addrinfo *ai; + ai = *pai = malloc (sizeof (struct addrinfo) + socklen); +@@ -1121,8 +1099,8 @@ gaih_inet (const char *name, const struct gaih_service *service, + + ai->ai_flags = req->ai_flags; + ai->ai_family = family; +- ai->ai_socktype = st2->socktype; +- ai->ai_protocol = st2->protocol; ++ ai->ai_socktype = st[i].socktype; ++ ai->ai_protocol = st[i].protocol; + ai->ai_addrlen = socklen; + ai->ai_addr = (void *) (ai + 1); + +@@ -1144,7 +1122,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + struct sockaddr_in6 *sin6p = + (struct sockaddr_in6 *) ai->ai_addr; + +- sin6p->sin6_port = st2->port; ++ sin6p->sin6_port = st[i].port; + sin6p->sin6_flowinfo = 0; + memcpy (&sin6p->sin6_addr, + at2->addr, sizeof (struct in6_addr)); +@@ -1154,7 +1132,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + { + struct sockaddr_in *sinp = + (struct sockaddr_in *) ai->ai_addr; +- sinp->sin_port = st2->port; ++ sinp->sin_port = st[i].port; + memcpy (&sinp->sin_addr, + at2->addr, sizeof (struct in_addr)); + memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero)); diff --git a/SOURCES/glibc-RHEL-2426-5.patch b/SOURCES/glibc-RHEL-2426-5.patch new file mode 100644 index 0000000..f6425af --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-5.patch @@ -0,0 +1,1123 @@ +commit 922f2614d69dc47922c1a8e8a08f2bd74874587e +Author: Siddhesh Poyarekar +Date: Mon Mar 7 14:08:51 2022 +0530 + + gaih_inet: make numeric lookup a separate routine + + Introduce the gaih_result structure and general paradigm for cleanups + that follow to process the lookup request and return a result. A lookup + function (like text_to_binary_address), should return an integer error + code and set members of gaih_result based on what it finds. If the + function does not have a result and no errors have occurred during the + lookup, it should return 0 and res.at should be set to NULL, allowing a + subsequent function to do the lookup until we run out of options. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit 26dea461191cca519b498890a9682fe4bc8e4c2f) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 8c78ef9570fe0f58..57b6834c8bb3887c 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -116,6 +116,12 @@ struct gaih_typeproto + char name[8]; + }; + ++struct gaih_result ++{ ++ struct gaih_addrtuple *at; ++ char *canon; ++}; ++ + /* Values for `protoflag'. */ + #define GAI_PROTO_NOSERVICE 1 + #define GAI_PROTO_PROTOANY 2 +@@ -297,7 +303,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + } \ + *pat = addrmem; \ + \ +- if (localcanon != NULL && canon == NULL) \ ++ if (localcanon != NULL && res.canon == NULL) \ + { \ + char *canonbuf = __strdup (localcanon); \ + if (canonbuf == NULL) \ +@@ -306,7 +312,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + result = -EAI_SYSTEM; \ + goto free_and_return; \ + } \ +- canon = canonbuf; \ ++ res.canon = canonbuf; \ + } \ + if (_family == AF_INET6 && *pat != NULL) \ + got_ipv6 = true; \ +@@ -342,9 +348,9 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) + + static int + process_canonname (const struct addrinfo *req, const char *orig_name, +- char **canonp) ++ struct gaih_result *res) + { +- char *canon = *canonp; ++ char *canon = res->canon; + + if ((req->ai_flags & AI_CANONNAME) != 0) + { +@@ -368,7 +374,7 @@ process_canonname (const struct addrinfo *req, const char *orig_name, + return -EAI_MEMORY; + } + +- *canonp = canon; ++ res->canon = canon; + return 0; + } + +@@ -460,6 +466,105 @@ get_servtuples (const struct gaih_service *service, const struct addrinfo *req, + return 0; + } + ++/* Convert numeric addresses to binary into RES. On failure, RES->AT is set to ++ NULL and an error code is returned. If AI_NUMERIC_HOST is not requested and ++ the function cannot determine a result, RES->AT is set to NULL and 0 ++ returned. */ ++ ++static int ++text_to_binary_address (const char *name, const struct addrinfo *req, ++ struct gaih_result *res) ++{ ++ struct gaih_addrtuple *at = res->at; ++ int result = 0; ++ ++ assert (at != NULL); ++ ++ memset (at->addr, 0, sizeof (at->addr)); ++ if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0) ++ { ++ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) ++ at->family = AF_INET; ++ else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) ++ { ++ at->addr[3] = at->addr[0]; ++ at->addr[2] = htonl (0xffff); ++ at->addr[1] = 0; ++ at->addr[0] = 0; ++ at->family = AF_INET6; ++ } ++ else ++ { ++ result = -EAI_ADDRFAMILY; ++ goto out; ++ } ++ ++ if (req->ai_flags & AI_CANONNAME) ++ { ++ char *canonbuf = __strdup (name); ++ if (canonbuf == NULL) ++ { ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ res->canon = canonbuf; ++ } ++ return 0; ++ } ++ ++ char *scope_delim = strchr (name, SCOPE_DELIMITER); ++ int e; ++ ++ if (scope_delim == NULL) ++ e = inet_pton (AF_INET6, name, at->addr); ++ else ++ e = __inet_pton_length (AF_INET6, name, scope_delim - name, at->addr); ++ ++ if (e > 0) ++ { ++ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) ++ at->family = AF_INET6; ++ else if (req->ai_family == AF_INET ++ && IN6_IS_ADDR_V4MAPPED (at->addr)) ++ { ++ at->addr[0] = at->addr[3]; ++ at->family = AF_INET; ++ } ++ else ++ { ++ result = -EAI_ADDRFAMILY; ++ goto out; ++ } ++ ++ if (scope_delim != NULL ++ && __inet6_scopeid_pton ((struct in6_addr *) at->addr, ++ scope_delim + 1, &at->scopeid) != 0) ++ { ++ result = -EAI_NONAME; ++ goto out; ++ } ++ ++ if (req->ai_flags & AI_CANONNAME) ++ { ++ char *canonbuf = __strdup (name); ++ if (canonbuf == NULL) ++ { ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ res->canon = canonbuf; ++ } ++ return 0; ++ } ++ ++ if ((req->ai_flags & AI_NUMERICHOST)) ++ result = -EAI_NONAME; ++ ++out: ++ res->at = NULL; ++ return result; ++} ++ + static int + gaih_inet (const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai, +@@ -468,9 +573,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + struct gaih_servtuple st[sizeof (gaih_inet_typeproto) + / sizeof (struct gaih_typeproto)] = {0}; + +- struct gaih_addrtuple *at = NULL; + bool got_ipv6 = false; +- char *canon = NULL; + const char *orig_name = name; + + /* Reserve stack memory for the scratch buffer in the getaddrinfo +@@ -485,6 +588,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + struct gaih_addrtuple *addrmem = NULL; + int result = 0; + ++ struct gaih_result res = {0}; + if (name != NULL) + { + if (req->ai_flags & AI_IDN) +@@ -497,533 +601,441 @@ gaih_inet (const char *name, const struct gaih_service *service, + malloc_name = true; + } + +- uint32_t addr[4]; +- if (__inet_aton_exact (name, (struct in_addr *) addr) != 0) ++ res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); ++ res.at->scopeid = 0; ++ res.at->next = NULL; ++ ++ if ((result = text_to_binary_address (name, req, &res)) != 0) ++ goto free_and_return; ++ else if (res.at != NULL) ++ goto process_list; ++ ++ int no_data = 0; ++ int no_inet6_data = 0; ++ nss_action_list nip; ++ enum nss_status inet6_status = NSS_STATUS_UNAVAIL; ++ enum nss_status status = NSS_STATUS_UNAVAIL; ++ int no_more; ++ struct resolv_context *res_ctx = NULL; ++ bool do_merge = false; ++ ++ /* If we do not have to look for IPv6 addresses or the canonical ++ name, use the simple, old functions, which do not support ++ IPv6 scope ids, nor retrieving the canonical name. */ ++ if (req->ai_family == AF_INET ++ && (req->ai_flags & AI_CANONNAME) == 0) + { +- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); +- at->scopeid = 0; +- at->next = NULL; +- +- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) +- { +- memcpy (at->addr, addr, sizeof (at->addr)); +- at->family = AF_INET; +- } +- else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) +- { +- at->addr[3] = addr[0]; +- at->addr[2] = htonl (0xffff); +- at->addr[1] = 0; +- at->addr[0] = 0; +- at->family = AF_INET6; +- } +- else +- { +- result = -EAI_ADDRFAMILY; +- goto free_and_return; +- } ++ int rc; ++ struct hostent th; ++ struct hostent *h; + +- if (req->ai_flags & AI_CANONNAME) ++ while (1) + { +- char *canonbuf = __strdup (name); +- if (canonbuf == NULL) ++ rc = __gethostbyname2_r (name, AF_INET, &th, ++ tmpbuf->data, tmpbuf->length, ++ &h, &h_errno); ++ if (rc != ERANGE || h_errno != NETDB_INTERNAL) ++ break; ++ if (!scratch_buffer_grow (tmpbuf)) + { + result = -EAI_MEMORY; + goto free_and_return; + } +- canon = canonbuf; + } + +- goto process_list; +- } +- +- char *scope_delim = strchr (name, SCOPE_DELIMITER); +- int e; +- +- if (scope_delim == NULL) +- e = inet_pton (AF_INET6, name, addr); +- else +- e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr); +- +- if (e > 0) +- { +- at = alloca_account (sizeof (struct gaih_addrtuple), +- alloca_used); +- at->scopeid = 0; +- at->next = NULL; +- +- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) +- { +- memcpy (at->addr, addr, sizeof (at->addr)); +- at->family = AF_INET6; +- } +- else if (req->ai_family == AF_INET +- && IN6_IS_ADDR_V4MAPPED (addr)) ++ if (rc == 0) + { +- at->addr[0] = addr[3]; +- at->addr[1] = addr[1]; +- at->addr[2] = addr[2]; +- at->addr[3] = addr[3]; +- at->family = AF_INET; ++ if (h != NULL) ++ { ++ /* We found data, convert it. */ ++ if (!convert_hostent_to_gaih_addrtuple ++ (req, AF_INET, h, &addrmem)) ++ { ++ result = -EAI_MEMORY; ++ goto free_and_return; ++ } ++ res.at = addrmem; ++ } ++ else ++ { ++ if (h_errno == NO_DATA) ++ result = -EAI_NODATA; ++ else ++ result = -EAI_NONAME; ++ goto free_and_return; ++ } + } + else + { +- result = -EAI_ADDRFAMILY; +- goto free_and_return; +- } ++ if (h_errno == NETDB_INTERNAL) ++ result = -EAI_SYSTEM; ++ else if (h_errno == TRY_AGAIN) ++ result = -EAI_AGAIN; ++ else ++ /* We made requests but they turned out no data. ++ The name is known, though. */ ++ result = -EAI_NODATA; + +- if (scope_delim != NULL +- && __inet6_scopeid_pton ((struct in6_addr *) at->addr, +- scope_delim + 1, +- &at->scopeid) != 0) +- { +- result = -EAI_NONAME; + goto free_and_return; + } + +- if (req->ai_flags & AI_CANONNAME) ++ goto process_list; ++ } ++ ++#ifdef USE_NSCD ++ if (__nss_not_use_nscd_hosts > 0 ++ && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) ++ __nss_not_use_nscd_hosts = 0; ++ ++ if (!__nss_not_use_nscd_hosts ++ && !__nss_database_custom[NSS_DBSIDX_hosts]) ++ { ++ /* Try to use nscd. */ ++ struct nscd_ai_result *air = NULL; ++ int err = __nscd_getai (name, &air, &h_errno); ++ if (air != NULL) + { +- char *canonbuf = __strdup (name); +- if (canonbuf == NULL) ++ /* Transform into gaih_addrtuple list. */ ++ bool added_canon = (req->ai_flags & AI_CANONNAME) == 0; ++ char *addrs = air->addrs; ++ ++ addrmem = calloc (air->naddrs, sizeof (*addrmem)); ++ if (addrmem == NULL) + { + result = -EAI_MEMORY; + goto free_and_return; + } +- canon = canonbuf; +- } + +- goto process_list; +- } +- +- if ((req->ai_flags & AI_NUMERICHOST) == 0) +- { +- int no_data = 0; +- int no_inet6_data = 0; +- nss_action_list nip; +- enum nss_status inet6_status = NSS_STATUS_UNAVAIL; +- enum nss_status status = NSS_STATUS_UNAVAIL; +- int no_more; +- struct resolv_context *res_ctx = NULL; +- bool do_merge = false; +- +- /* If we do not have to look for IPv6 addresses or the canonical +- name, use the simple, old functions, which do not support +- IPv6 scope ids, nor retrieving the canonical name. */ +- if (req->ai_family == AF_INET +- && (req->ai_flags & AI_CANONNAME) == 0) +- { +- int rc; +- struct hostent th; +- struct hostent *h; ++ struct gaih_addrtuple *addrfree = addrmem; ++ struct gaih_addrtuple **pat = &res.at; + +- while (1) ++ for (int i = 0; i < air->naddrs; ++i) + { +- rc = __gethostbyname2_r (name, AF_INET, &th, +- tmpbuf->data, tmpbuf->length, +- &h, &h_errno); +- if (rc != ERANGE || h_errno != NETDB_INTERNAL) +- break; +- if (!scratch_buffer_grow (tmpbuf)) ++ socklen_t size = (air->family[i] == AF_INET ++ ? INADDRSZ : IN6ADDRSZ); ++ ++ if (!((air->family[i] == AF_INET ++ && req->ai_family == AF_INET6 ++ && (req->ai_flags & AI_V4MAPPED) != 0) ++ || req->ai_family == AF_UNSPEC ++ || air->family[i] == req->ai_family)) + { +- result = -EAI_MEMORY; +- goto free_and_return; ++ /* Skip over non-matching result. */ ++ addrs += size; ++ continue; + } +- } + +- if (rc == 0) +- { +- if (h != NULL) ++ if (*pat == NULL) ++ { ++ *pat = addrfree++; ++ (*pat)->scopeid = 0; ++ } ++ uint32_t *pataddr = (*pat)->addr; ++ (*pat)->next = NULL; ++ if (added_canon || air->canon == NULL) ++ (*pat)->name = NULL; ++ else if (res.canon == NULL) + { +- /* We found data, convert it. */ +- if (!convert_hostent_to_gaih_addrtuple +- (req, AF_INET, h, &addrmem)) ++ char *canonbuf = __strdup (air->canon); ++ if (canonbuf == NULL) + { + result = -EAI_MEMORY; + goto free_and_return; + } +- at = addrmem; ++ res.canon = (*pat)->name = canonbuf; + } +- else ++ ++ if (air->family[i] == AF_INET ++ && req->ai_family == AF_INET6 ++ && (req->ai_flags & AI_V4MAPPED)) + { +- if (h_errno == NO_DATA) +- result = -EAI_NODATA; +- else +- result = -EAI_NONAME; +- goto free_and_return; ++ (*pat)->family = AF_INET6; ++ pataddr[3] = *(uint32_t *) addrs; ++ pataddr[2] = htonl (0xffff); ++ pataddr[1] = 0; ++ pataddr[0] = 0; ++ pat = &((*pat)->next); ++ added_canon = true; ++ } ++ else if (req->ai_family == AF_UNSPEC ++ || air->family[i] == req->ai_family) ++ { ++ (*pat)->family = air->family[i]; ++ memcpy (pataddr, addrs, size); ++ pat = &((*pat)->next); ++ added_canon = true; ++ if (air->family[i] == AF_INET6) ++ got_ipv6 = true; + } ++ addrs += size; + } +- else +- { +- if (h_errno == NETDB_INTERNAL) +- result = -EAI_SYSTEM; +- else if (h_errno == TRY_AGAIN) +- result = -EAI_AGAIN; +- else +- /* We made requests but they turned out no data. +- The name is known, though. */ +- result = -EAI_NODATA; + +- goto free_and_return; +- } ++ free (air); + + goto process_list; + } ++ else if (err == 0) ++ /* The database contains a negative entry. */ ++ goto free_and_return; ++ else if (__nss_not_use_nscd_hosts == 0) ++ { ++ if (h_errno == NETDB_INTERNAL && errno == ENOMEM) ++ result = -EAI_MEMORY; ++ else if (h_errno == TRY_AGAIN) ++ result = -EAI_AGAIN; ++ else ++ result = -EAI_SYSTEM; + +-#ifdef USE_NSCD +- if (__nss_not_use_nscd_hosts > 0 +- && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) +- __nss_not_use_nscd_hosts = 0; ++ goto free_and_return; ++ } ++ } ++#endif ++ ++ no_more = !__nss_database_get (nss_database_hosts, &nip); + +- if (!__nss_not_use_nscd_hosts +- && !__nss_database_custom[NSS_DBSIDX_hosts]) ++ /* If we are looking for both IPv4 and IPv6 address we don't ++ want the lookup functions to automatically promote IPv4 ++ addresses to IPv6 addresses, so we use the no_inet6 ++ function variant. */ ++ res_ctx = __resolv_context_get (); ++ if (res_ctx == NULL) ++ no_more = 1; ++ ++ while (!no_more) ++ { ++ /* Always start afresh; continue should discard previous results ++ and the hosts database does not support merge. */ ++ res.at = NULL; ++ free (res.canon); ++ free (addrmem); ++ res.canon = NULL; ++ addrmem = NULL; ++ got_ipv6 = false; ++ ++ if (do_merge) + { +- /* Try to use nscd. */ +- struct nscd_ai_result *air = NULL; +- int err = __nscd_getai (name, &air, &h_errno); +- if (air != NULL) ++ __set_h_errno (NETDB_INTERNAL); ++ __set_errno (EBUSY); ++ break; ++ } ++ ++ no_data = 0; ++ nss_gethostbyname4_r *fct4 = NULL; ++ ++ /* gethostbyname4_r sends out parallel A and AAAA queries and ++ is thus only suitable for PF_UNSPEC. */ ++ if (req->ai_family == PF_UNSPEC) ++ fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); ++ ++ if (fct4 != NULL) ++ { ++ while (1) + { +- /* Transform into gaih_addrtuple list. */ +- bool added_canon = (req->ai_flags & AI_CANONNAME) == 0; +- char *addrs = air->addrs; ++ status = DL_CALL_FCT (fct4, (name, &res.at, ++ tmpbuf->data, tmpbuf->length, ++ &errno, &h_errno, ++ NULL)); ++ if (status == NSS_STATUS_SUCCESS) ++ break; ++ /* gethostbyname4_r may write into AT, so reset it. */ ++ res.at = NULL; ++ if (status != NSS_STATUS_TRYAGAIN ++ || errno != ERANGE || h_errno != NETDB_INTERNAL) ++ { ++ if (h_errno == TRY_AGAIN) ++ no_data = EAI_AGAIN; ++ else ++ no_data = h_errno == NO_DATA; ++ break; ++ } + +- addrmem = calloc (air->naddrs, sizeof (*addrmem)); +- if (addrmem == NULL) ++ if (!scratch_buffer_grow (tmpbuf)) + { ++ __resolv_context_put (res_ctx); + result = -EAI_MEMORY; + goto free_and_return; + } ++ } + +- struct gaih_addrtuple *addrfree = addrmem; +- struct gaih_addrtuple **pat = &at; ++ if (status == NSS_STATUS_SUCCESS) ++ { ++ assert (!no_data); ++ no_data = 1; + +- for (int i = 0; i < air->naddrs; ++i) ++ if ((req->ai_flags & AI_CANONNAME) != 0 && res.canon == NULL) + { +- socklen_t size = (air->family[i] == AF_INET +- ? INADDRSZ : IN6ADDRSZ); +- +- if (!((air->family[i] == AF_INET +- && req->ai_family == AF_INET6 +- && (req->ai_flags & AI_V4MAPPED) != 0) +- || req->ai_family == AF_UNSPEC +- || air->family[i] == req->ai_family)) ++ char *canonbuf = __strdup (res.at->name); ++ if (canonbuf == NULL) + { +- /* Skip over non-matching result. */ +- addrs += size; +- continue; ++ __resolv_context_put (res_ctx); ++ result = -EAI_MEMORY; ++ goto free_and_return; + } ++ res.canon = canonbuf; ++ } + +- if (*pat == NULL) +- { +- *pat = addrfree++; +- (*pat)->scopeid = 0; +- } +- uint32_t *pataddr = (*pat)->addr; +- (*pat)->next = NULL; +- if (added_canon || air->canon == NULL) +- (*pat)->name = NULL; +- else if (canon == NULL) +- { +- char *canonbuf = __strdup (air->canon); +- if (canonbuf == NULL) +- { +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- canon = (*pat)->name = canonbuf; +- } ++ struct gaih_addrtuple **pat = &res.at; + +- if (air->family[i] == AF_INET ++ while (*pat != NULL) ++ { ++ if ((*pat)->family == AF_INET + && req->ai_family == AF_INET6 +- && (req->ai_flags & AI_V4MAPPED)) ++ && (req->ai_flags & AI_V4MAPPED) != 0) + { ++ uint32_t *pataddr = (*pat)->addr; + (*pat)->family = AF_INET6; +- pataddr[3] = *(uint32_t *) addrs; ++ pataddr[3] = pataddr[0]; + pataddr[2] = htonl (0xffff); + pataddr[1] = 0; + pataddr[0] = 0; + pat = &((*pat)->next); +- added_canon = true; ++ no_data = 0; + } + else if (req->ai_family == AF_UNSPEC +- || air->family[i] == req->ai_family) ++ || (*pat)->family == req->ai_family) + { +- (*pat)->family = air->family[i]; +- memcpy (pataddr, addrs, size); + pat = &((*pat)->next); +- added_canon = true; +- if (air->family[i] == AF_INET6) ++ ++ no_data = 0; ++ if (req->ai_family == AF_INET6) + got_ipv6 = true; + } +- addrs += size; ++ else ++ *pat = ((*pat)->next); + } +- +- free (air); +- +- goto process_list; + } +- else if (err == 0) +- /* The database contains a negative entry. */ +- goto free_and_return; +- else if (__nss_not_use_nscd_hosts == 0) +- { +- if (h_errno == NETDB_INTERNAL && errno == ENOMEM) +- result = -EAI_MEMORY; +- else if (h_errno == TRY_AGAIN) +- result = -EAI_AGAIN; +- else +- result = -EAI_SYSTEM; + +- goto free_and_return; +- } ++ no_inet6_data = no_data; + } +-#endif +- +- no_more = !__nss_database_get (nss_database_hosts, &nip); +- +- /* If we are looking for both IPv4 and IPv6 address we don't +- want the lookup functions to automatically promote IPv4 +- addresses to IPv6 addresses, so we use the no_inet6 +- function variant. */ +- res_ctx = __resolv_context_get (); +- if (res_ctx == NULL) +- no_more = 1; +- +- while (!no_more) ++ else + { +- /* Always start afresh; continue should discard previous results +- and the hosts database does not support merge. */ +- at = NULL; +- free (canon); +- free (addrmem); +- canon = NULL; +- addrmem = NULL; +- got_ipv6 = false; +- +- if (do_merge) ++ nss_gethostbyname3_r *fct = NULL; ++ if (req->ai_flags & AI_CANONNAME) ++ /* No need to use this function if we do not look for ++ the canonical name. The function does not exist in ++ all NSS modules and therefore the lookup would ++ often fail. */ ++ fct = __nss_lookup_function (nip, "gethostbyname3_r"); ++ if (fct == NULL) ++ /* We are cheating here. The gethostbyname2_r ++ function does not have the same interface as ++ gethostbyname3_r but the extra arguments the ++ latter takes are added at the end. So the ++ gethostbyname2_r code will just ignore them. */ ++ fct = __nss_lookup_function (nip, "gethostbyname2_r"); ++ ++ if (fct != NULL) + { +- __set_h_errno (NETDB_INTERNAL); +- __set_errno (EBUSY); +- break; +- } +- +- no_data = 0; +- nss_gethostbyname4_r *fct4 = NULL; +- +- /* gethostbyname4_r sends out parallel A and AAAA queries and +- is thus only suitable for PF_UNSPEC. */ +- if (req->ai_family == PF_UNSPEC) +- fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); ++ struct gaih_addrtuple **pat = &res.at; + +- if (fct4 != NULL) +- { +- while (1) ++ if (req->ai_family == AF_INET6 ++ || req->ai_family == AF_UNSPEC) + { +- status = DL_CALL_FCT (fct4, (name, &at, +- tmpbuf->data, tmpbuf->length, +- &errno, &h_errno, +- NULL)); +- if (status == NSS_STATUS_SUCCESS) +- break; +- /* gethostbyname4_r may write into AT, so reset it. */ +- at = NULL; +- if (status != NSS_STATUS_TRYAGAIN +- || errno != ERANGE || h_errno != NETDB_INTERNAL) +- { +- if (h_errno == TRY_AGAIN) +- no_data = EAI_AGAIN; +- else +- no_data = h_errno == NO_DATA; +- break; +- } ++ gethosts (AF_INET6); ++ no_inet6_data = no_data; ++ inet6_status = status; ++ } ++ if (req->ai_family == AF_INET ++ || req->ai_family == AF_UNSPEC ++ || (req->ai_family == AF_INET6 ++ && (req->ai_flags & AI_V4MAPPED) ++ /* Avoid generating the mapped addresses if we ++ know we are not going to need them. */ ++ && ((req->ai_flags & AI_ALL) || !got_ipv6))) ++ { ++ gethosts (AF_INET); + +- if (!scratch_buffer_grow (tmpbuf)) ++ if (req->ai_family == AF_INET) + { +- __resolv_context_put (res_ctx); +- result = -EAI_MEMORY; +- goto free_and_return; ++ no_inet6_data = no_data; ++ inet6_status = status; + } + } + +- if (status == NSS_STATUS_SUCCESS) ++ /* If we found one address for AF_INET or AF_INET6, ++ don't continue the search. */ ++ if (inet6_status == NSS_STATUS_SUCCESS ++ || status == NSS_STATUS_SUCCESS) + { +- assert (!no_data); +- no_data = 1; +- +- if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) ++ if ((req->ai_flags & AI_CANONNAME) != 0 ++ && res.canon == NULL) + { +- char *canonbuf = __strdup (at->name); ++ char *canonbuf = getcanonname (nip, res.at, name); + if (canonbuf == NULL) + { + __resolv_context_put (res_ctx); + result = -EAI_MEMORY; + goto free_and_return; + } +- canon = canonbuf; +- } +- +- struct gaih_addrtuple **pat = &at; +- +- while (*pat != NULL) +- { +- if ((*pat)->family == AF_INET +- && req->ai_family == AF_INET6 +- && (req->ai_flags & AI_V4MAPPED) != 0) +- { +- uint32_t *pataddr = (*pat)->addr; +- (*pat)->family = AF_INET6; +- pataddr[3] = pataddr[0]; +- pataddr[2] = htonl (0xffff); +- pataddr[1] = 0; +- pataddr[0] = 0; +- pat = &((*pat)->next); +- no_data = 0; +- } +- else if (req->ai_family == AF_UNSPEC +- || (*pat)->family == req->ai_family) +- { +- pat = &((*pat)->next); +- +- no_data = 0; +- if (req->ai_family == AF_INET6) +- got_ipv6 = true; +- } +- else +- *pat = ((*pat)->next); +- } +- } +- +- no_inet6_data = no_data; +- } +- else +- { +- nss_gethostbyname3_r *fct = NULL; +- if (req->ai_flags & AI_CANONNAME) +- /* No need to use this function if we do not look for +- the canonical name. The function does not exist in +- all NSS modules and therefore the lookup would +- often fail. */ +- fct = __nss_lookup_function (nip, "gethostbyname3_r"); +- if (fct == NULL) +- /* We are cheating here. The gethostbyname2_r +- function does not have the same interface as +- gethostbyname3_r but the extra arguments the +- latter takes are added at the end. So the +- gethostbyname2_r code will just ignore them. */ +- fct = __nss_lookup_function (nip, "gethostbyname2_r"); +- +- if (fct != NULL) +- { +- struct gaih_addrtuple **pat = &at; +- +- if (req->ai_family == AF_INET6 +- || req->ai_family == AF_UNSPEC) +- { +- gethosts (AF_INET6); +- no_inet6_data = no_data; +- inet6_status = status; +- } +- if (req->ai_family == AF_INET +- || req->ai_family == AF_UNSPEC +- || (req->ai_family == AF_INET6 +- && (req->ai_flags & AI_V4MAPPED) +- /* Avoid generating the mapped addresses if we +- know we are not going to need them. */ +- && ((req->ai_flags & AI_ALL) || !got_ipv6))) +- { +- gethosts (AF_INET); +- +- if (req->ai_family == AF_INET) +- { +- no_inet6_data = no_data; +- inet6_status = status; +- } +- } +- +- /* If we found one address for AF_INET or AF_INET6, +- don't continue the search. */ +- if (inet6_status == NSS_STATUS_SUCCESS +- || status == NSS_STATUS_SUCCESS) +- { +- if ((req->ai_flags & AI_CANONNAME) != 0 +- && canon == NULL) +- { +- char *canonbuf = getcanonname (nip, at, name); +- if (canonbuf == NULL) +- { +- __resolv_context_put (res_ctx); +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- canon = canonbuf; +- } +- status = NSS_STATUS_SUCCESS; +- } +- else +- { +- /* We can have different states for AF_INET and +- AF_INET6. Try to find a useful one for both. */ +- if (inet6_status == NSS_STATUS_TRYAGAIN) +- status = NSS_STATUS_TRYAGAIN; +- else if (status == NSS_STATUS_UNAVAIL +- && inet6_status != NSS_STATUS_UNAVAIL) +- status = inet6_status; ++ res.canon = canonbuf; + } ++ status = NSS_STATUS_SUCCESS; + } + else + { +- /* Could not locate any of the lookup functions. +- The NSS lookup code does not consistently set +- errno, so we need to supply our own error +- code here. The root cause could either be a +- resource allocation failure, or a missing +- service function in the DSO (so it should not +- be listed in /etc/nsswitch.conf). Assume the +- former, and return EBUSY. */ +- status = NSS_STATUS_UNAVAIL; +- __set_h_errno (NETDB_INTERNAL); +- __set_errno (EBUSY); ++ /* We can have different states for AF_INET and ++ AF_INET6. Try to find a useful one for both. */ ++ if (inet6_status == NSS_STATUS_TRYAGAIN) ++ status = NSS_STATUS_TRYAGAIN; ++ else if (status == NSS_STATUS_UNAVAIL ++ && inet6_status != NSS_STATUS_UNAVAIL) ++ status = inet6_status; + } + } ++ else ++ { ++ /* Could not locate any of the lookup functions. ++ The NSS lookup code does not consistently set ++ errno, so we need to supply our own error ++ code here. The root cause could either be a ++ resource allocation failure, or a missing ++ service function in the DSO (so it should not ++ be listed in /etc/nsswitch.conf). Assume the ++ former, and return EBUSY. */ ++ status = NSS_STATUS_UNAVAIL; ++ __set_h_errno (NETDB_INTERNAL); ++ __set_errno (EBUSY); ++ } ++ } + +- if (nss_next_action (nip, status) == NSS_ACTION_RETURN) +- break; ++ if (nss_next_action (nip, status) == NSS_ACTION_RETURN) ++ break; + +- /* The hosts database does not support MERGE. */ +- if (nss_next_action (nip, status) == NSS_ACTION_MERGE) +- do_merge = true; ++ /* The hosts database does not support MERGE. */ ++ if (nss_next_action (nip, status) == NSS_ACTION_MERGE) ++ do_merge = true; + +- nip++; +- if (nip->module == NULL) +- no_more = -1; +- } ++ nip++; ++ if (nip->module == NULL) ++ no_more = -1; ++ } + +- __resolv_context_put (res_ctx); ++ __resolv_context_put (res_ctx); + +- /* If we have a failure which sets errno, report it using +- EAI_SYSTEM. */ +- if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) +- && h_errno == NETDB_INTERNAL) +- { +- result = -EAI_SYSTEM; +- goto free_and_return; +- } ++ /* If we have a failure which sets errno, report it using ++ EAI_SYSTEM. */ ++ if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) ++ && h_errno == NETDB_INTERNAL) ++ { ++ result = -EAI_SYSTEM; ++ goto free_and_return; ++ } + +- if (no_data != 0 && no_inet6_data != 0) +- { +- /* If both requests timed out report this. */ +- if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) +- result = -EAI_AGAIN; +- else +- /* We made requests but they turned out no data. The name +- is known, though. */ +- result = -EAI_NODATA; ++ if (no_data != 0 && no_inet6_data != 0) ++ { ++ /* If both requests timed out report this. */ ++ if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) ++ result = -EAI_AGAIN; ++ else ++ /* We made requests but they turned out no data. The name ++ is known, though. */ ++ result = -EAI_NODATA; + +- goto free_and_return; +- } ++ goto free_and_return; + } + + process_list: +- if (at == NULL) ++ if (res.at == NULL) + { + result = -EAI_NONAME; + goto free_and_return; +@@ -1032,21 +1044,22 @@ gaih_inet (const char *name, const struct gaih_service *service, + else + { + struct gaih_addrtuple *atr; +- atr = at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); +- memset (at, '\0', sizeof (struct gaih_addrtuple)); ++ atr = res.at = alloca_account (sizeof (struct gaih_addrtuple), ++ alloca_used); ++ memset (res.at, '\0', sizeof (struct gaih_addrtuple)); + + if (req->ai_family == AF_UNSPEC) + { +- at->next = __alloca (sizeof (struct gaih_addrtuple)); +- memset (at->next, '\0', sizeof (struct gaih_addrtuple)); ++ res.at->next = __alloca (sizeof (struct gaih_addrtuple)); ++ memset (res.at->next, '\0', sizeof (struct gaih_addrtuple)); + } + + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) + { +- at->family = AF_INET6; ++ res.at->family = AF_INET6; + if ((req->ai_flags & AI_PASSIVE) == 0) +- memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr)); +- atr = at->next; ++ memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr)); ++ atr = res.at->next; + } + + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) +@@ -1059,10 +1072,10 @@ gaih_inet (const char *name, const struct gaih_service *service, + + { + /* Set up the canonical name if we need it. */ +- if ((result = process_canonname (req, orig_name, &canon)) != 0) ++ if ((result = process_canonname (req, orig_name, &res)) != 0) + goto free_and_return; + +- struct gaih_addrtuple *at2 = at; ++ struct gaih_addrtuple *at2 = res.at; + size_t socklen; + sa_family_t family; + +@@ -1105,8 +1118,8 @@ gaih_inet (const char *name, const struct gaih_service *service, + ai->ai_addr = (void *) (ai + 1); + + /* We only add the canonical name once. */ +- ai->ai_canonname = (char *) canon; +- canon = NULL; ++ ai->ai_canonname = res.canon; ++ res.canon = NULL; + + #ifdef _HAVE_SA_LEN + ai->ai_addr->sa_len = socklen; +@@ -1152,7 +1165,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + if (malloc_name) + free ((char *) name); + free (addrmem); +- free (canon); ++ free (res.canon); + + return result; + } diff --git a/SOURCES/glibc-RHEL-2426-6.patch b/SOURCES/glibc-RHEL-2426-6.patch new file mode 100644 index 0000000..c9e0581 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-6.patch @@ -0,0 +1,179 @@ +commit 3b5a3e5009088a029525277f36228eeb95032358 +Author: Siddhesh Poyarekar +Date: Fri Mar 4 14:57:12 2022 +0530 + + gaih_inet: Split simple gethostbyname into its own function + + Add a free_at flag in gaih_result to indicate if res.at needs to be + freed by the caller. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit b44389cb7fa28a59804571dac09cc32ebfac03d1) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 57b6834c8bb3887c..3870b2dc2edc89cd 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -120,6 +120,7 @@ struct gaih_result + { + struct gaih_addrtuple *at; + char *canon; ++ bool free_at; + }; + + /* Values for `protoflag'. */ +@@ -565,6 +566,62 @@ out: + return result; + } + ++/* If possible, call the simple, old functions, which do not support IPv6 scope ++ ids, nor retrieving the canonical name. */ ++ ++static int ++try_simple_gethostbyname (const char *name, const struct addrinfo *req, ++ struct scratch_buffer *tmpbuf, ++ struct gaih_result *res) ++{ ++ res->at = NULL; ++ ++ if (req->ai_family != AF_INET || (req->ai_flags & AI_CANONNAME) != 0) ++ return 0; ++ ++ int rc; ++ struct hostent th; ++ struct hostent *h; ++ ++ while (1) ++ { ++ rc = __gethostbyname2_r (name, AF_INET, &th, tmpbuf->data, ++ tmpbuf->length, &h, &h_errno); ++ if (rc != ERANGE || h_errno != NETDB_INTERNAL) ++ break; ++ if (!scratch_buffer_grow (tmpbuf)) ++ return -EAI_MEMORY; ++ } ++ ++ if (rc == 0) ++ { ++ if (h != NULL) ++ { ++ /* We found data, convert it. RES->AT from the conversion will ++ either be an allocated block or NULL, both of which are safe to ++ pass to free (). */ ++ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at)) ++ return -EAI_MEMORY; ++ ++ res->free_at = true; ++ return 0; ++ } ++ if (h_errno == NO_DATA) ++ return -EAI_NODATA; ++ ++ return -EAI_NONAME; ++ } ++ ++ if (h_errno == NETDB_INTERNAL) ++ return -EAI_SYSTEM; ++ if (h_errno == TRY_AGAIN) ++ return -EAI_AGAIN; ++ ++ /* We made requests but they turned out no data. ++ The name is known, though. */ ++ return -EAI_NODATA; ++} ++ + static int + gaih_inet (const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai, +@@ -610,6 +667,11 @@ gaih_inet (const char *name, const struct gaih_service *service, + else if (res.at != NULL) + goto process_list; + ++ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0) ++ goto free_and_return; ++ else if (res.at != NULL) ++ goto process_list; ++ + int no_data = 0; + int no_inet6_data = 0; + nss_action_list nip; +@@ -619,69 +681,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + struct resolv_context *res_ctx = NULL; + bool do_merge = false; + +- /* If we do not have to look for IPv6 addresses or the canonical +- name, use the simple, old functions, which do not support +- IPv6 scope ids, nor retrieving the canonical name. */ +- if (req->ai_family == AF_INET +- && (req->ai_flags & AI_CANONNAME) == 0) +- { +- int rc; +- struct hostent th; +- struct hostent *h; +- +- while (1) +- { +- rc = __gethostbyname2_r (name, AF_INET, &th, +- tmpbuf->data, tmpbuf->length, +- &h, &h_errno); +- if (rc != ERANGE || h_errno != NETDB_INTERNAL) +- break; +- if (!scratch_buffer_grow (tmpbuf)) +- { +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- } +- +- if (rc == 0) +- { +- if (h != NULL) +- { +- /* We found data, convert it. */ +- if (!convert_hostent_to_gaih_addrtuple +- (req, AF_INET, h, &addrmem)) +- { +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- res.at = addrmem; +- } +- else +- { +- if (h_errno == NO_DATA) +- result = -EAI_NODATA; +- else +- result = -EAI_NONAME; +- goto free_and_return; +- } +- } +- else +- { +- if (h_errno == NETDB_INTERNAL) +- result = -EAI_SYSTEM; +- else if (h_errno == TRY_AGAIN) +- result = -EAI_AGAIN; +- else +- /* We made requests but they turned out no data. +- The name is known, though. */ +- result = -EAI_NODATA; +- +- goto free_and_return; +- } +- +- goto process_list; +- } +- + #ifdef USE_NSCD + if (__nss_not_use_nscd_hosts > 0 + && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) +@@ -1165,6 +1164,8 @@ gaih_inet (const char *name, const struct gaih_service *service, + if (malloc_name) + free ((char *) name); + free (addrmem); ++ if (res.free_at) ++ free (res.at); + free (res.canon); + + return result; diff --git a/SOURCES/glibc-RHEL-2426-7.patch b/SOURCES/glibc-RHEL-2426-7.patch new file mode 100644 index 0000000..253805a --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-7.patch @@ -0,0 +1,328 @@ +commit 5914a1d55b468ccf0fb6d997a7a4e378339df735 +Author: Siddhesh Poyarekar +Date: Mon Mar 7 15:53:45 2022 +0530 + + gaih_inet: Split nscd lookup code into its own function. + + Add a new member got_ipv6 to indicate if the results have an IPv6 + result and use it instead of the local got_ipv6. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit e7e5315b7fa065a9c8bf525ca9a32f46fa4837e5) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 3870b2dc2edc89cd..7c497a88f8b5b9f8 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -121,6 +121,7 @@ struct gaih_result + struct gaih_addrtuple *at; + char *canon; + bool free_at; ++ bool got_ipv6; + }; + + /* Values for `protoflag'. */ +@@ -316,7 +317,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + res.canon = canonbuf; \ + } \ + if (_family == AF_INET6 && *pat != NULL) \ +- got_ipv6 = true; \ ++ res.got_ipv6 = true; \ + } \ + } + +@@ -467,6 +468,128 @@ get_servtuples (const struct gaih_service *service, const struct addrinfo *req, + return 0; + } + ++#ifdef USE_NSCD ++/* Query addresses from nscd cache, returning a non-zero value on error. ++ RES members have the lookup result; RES->AT is NULL if there were no errors ++ but also no results. */ ++ ++static int ++get_nscd_addresses (const char *name, const struct addrinfo *req, ++ struct gaih_result *res) ++{ ++ if (__nss_not_use_nscd_hosts > 0 ++ && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) ++ __nss_not_use_nscd_hosts = 0; ++ ++ res->at = NULL; ++ ++ if (__nss_not_use_nscd_hosts || __nss_database_custom[NSS_DBSIDX_hosts]) ++ return 0; ++ ++ /* Try to use nscd. */ ++ struct nscd_ai_result *air = NULL; ++ int err = __nscd_getai (name, &air, &h_errno); ++ ++ if (__glibc_unlikely (air == NULL)) ++ { ++ /* The database contains a negative entry. */ ++ if (err == 0) ++ return -EAI_NONAME; ++ if (__nss_not_use_nscd_hosts == 0) ++ { ++ if (h_errno == NETDB_INTERNAL && errno == ENOMEM) ++ return -EAI_MEMORY; ++ if (h_errno == TRY_AGAIN) ++ return -EAI_AGAIN; ++ return -EAI_SYSTEM; ++ } ++ return 0; ++ } ++ ++ /* Transform into gaih_addrtuple list. */ ++ int result = 0; ++ char *addrs = air->addrs; ++ ++ struct gaih_addrtuple *addrfree = calloc (air->naddrs, sizeof (*addrfree)); ++ struct gaih_addrtuple *at = calloc (air->naddrs, sizeof (*at)); ++ if (at == NULL) ++ { ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ ++ res->free_at = true; ++ ++ int count = 0; ++ for (int i = 0; i < air->naddrs; ++i) ++ { ++ socklen_t size = (air->family[i] == AF_INET ++ ? INADDRSZ : IN6ADDRSZ); ++ ++ if (!((air->family[i] == AF_INET ++ && req->ai_family == AF_INET6 ++ && (req->ai_flags & AI_V4MAPPED) != 0) ++ || req->ai_family == AF_UNSPEC ++ || air->family[i] == req->ai_family)) ++ { ++ /* Skip over non-matching result. */ ++ addrs += size; ++ continue; ++ } ++ ++ if (air->family[i] == AF_INET && req->ai_family == AF_INET6 ++ && (req->ai_flags & AI_V4MAPPED)) ++ { ++ at[count].family = AF_INET6; ++ at[count].addr[3] = *(uint32_t *) addrs; ++ at[count].addr[2] = htonl (0xffff); ++ } ++ else if (req->ai_family == AF_UNSPEC ++ || air->family[count] == req->ai_family) ++ { ++ at[count].family = air->family[count]; ++ memcpy (at[count].addr, addrs, size); ++ if (air->family[count] == AF_INET6) ++ res->got_ipv6 = true; ++ } ++ at[count].next = at + count + 1; ++ count++; ++ addrs += size; ++ } ++ ++ if ((req->ai_flags & AI_CANONNAME) && air->canon != NULL) ++ { ++ char *canonbuf = __strdup (air->canon); ++ if (canonbuf == NULL) ++ { ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ res->canon = canonbuf; ++ } ++ ++ if (count == 0) ++ { ++ result = -EAI_NONAME; ++ goto out; ++ } ++ ++ at[count - 1].next = NULL; ++ ++ res->at = at; ++ ++out: ++ free (air); ++ if (result != 0) ++ { ++ free (at); ++ res->free_at = false; ++ } ++ ++ return result; ++} ++#endif ++ + /* Convert numeric addresses to binary into RES. On failure, RES->AT is set to + NULL and an error code is returned. If AI_NUMERIC_HOST is not requested and + the function cannot determine a result, RES->AT is set to NULL and 0 +@@ -630,7 +753,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + struct gaih_servtuple st[sizeof (gaih_inet_typeproto) + / sizeof (struct gaih_typeproto)] = {0}; + +- bool got_ipv6 = false; + const char *orig_name = name; + + /* Reserve stack memory for the scratch buffer in the getaddrinfo +@@ -672,6 +794,13 @@ gaih_inet (const char *name, const struct gaih_service *service, + else if (res.at != NULL) + goto process_list; + ++#ifdef USE_NSCD ++ if ((result = get_nscd_addresses (name, req, &res)) != 0) ++ goto free_and_return; ++ else if (res.at != NULL) ++ goto process_list; ++#endif ++ + int no_data = 0; + int no_inet6_data = 0; + nss_action_list nip; +@@ -681,115 +810,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + struct resolv_context *res_ctx = NULL; + bool do_merge = false; + +-#ifdef USE_NSCD +- if (__nss_not_use_nscd_hosts > 0 +- && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) +- __nss_not_use_nscd_hosts = 0; +- +- if (!__nss_not_use_nscd_hosts +- && !__nss_database_custom[NSS_DBSIDX_hosts]) +- { +- /* Try to use nscd. */ +- struct nscd_ai_result *air = NULL; +- int err = __nscd_getai (name, &air, &h_errno); +- if (air != NULL) +- { +- /* Transform into gaih_addrtuple list. */ +- bool added_canon = (req->ai_flags & AI_CANONNAME) == 0; +- char *addrs = air->addrs; +- +- addrmem = calloc (air->naddrs, sizeof (*addrmem)); +- if (addrmem == NULL) +- { +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- +- struct gaih_addrtuple *addrfree = addrmem; +- struct gaih_addrtuple **pat = &res.at; +- +- for (int i = 0; i < air->naddrs; ++i) +- { +- socklen_t size = (air->family[i] == AF_INET +- ? INADDRSZ : IN6ADDRSZ); +- +- if (!((air->family[i] == AF_INET +- && req->ai_family == AF_INET6 +- && (req->ai_flags & AI_V4MAPPED) != 0) +- || req->ai_family == AF_UNSPEC +- || air->family[i] == req->ai_family)) +- { +- /* Skip over non-matching result. */ +- addrs += size; +- continue; +- } +- +- if (*pat == NULL) +- { +- *pat = addrfree++; +- (*pat)->scopeid = 0; +- } +- uint32_t *pataddr = (*pat)->addr; +- (*pat)->next = NULL; +- if (added_canon || air->canon == NULL) +- (*pat)->name = NULL; +- else if (res.canon == NULL) +- { +- char *canonbuf = __strdup (air->canon); +- if (canonbuf == NULL) +- { +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- res.canon = (*pat)->name = canonbuf; +- } +- +- if (air->family[i] == AF_INET +- && req->ai_family == AF_INET6 +- && (req->ai_flags & AI_V4MAPPED)) +- { +- (*pat)->family = AF_INET6; +- pataddr[3] = *(uint32_t *) addrs; +- pataddr[2] = htonl (0xffff); +- pataddr[1] = 0; +- pataddr[0] = 0; +- pat = &((*pat)->next); +- added_canon = true; +- } +- else if (req->ai_family == AF_UNSPEC +- || air->family[i] == req->ai_family) +- { +- (*pat)->family = air->family[i]; +- memcpy (pataddr, addrs, size); +- pat = &((*pat)->next); +- added_canon = true; +- if (air->family[i] == AF_INET6) +- got_ipv6 = true; +- } +- addrs += size; +- } +- +- free (air); +- +- goto process_list; +- } +- else if (err == 0) +- /* The database contains a negative entry. */ +- goto free_and_return; +- else if (__nss_not_use_nscd_hosts == 0) +- { +- if (h_errno == NETDB_INTERNAL && errno == ENOMEM) +- result = -EAI_MEMORY; +- else if (h_errno == TRY_AGAIN) +- result = -EAI_AGAIN; +- else +- result = -EAI_SYSTEM; +- +- goto free_and_return; +- } +- } +-#endif +- + no_more = !__nss_database_get (nss_database_hosts, &nip); + + /* If we are looking for both IPv4 and IPv6 address we don't +@@ -897,7 +917,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + + no_data = 0; + if (req->ai_family == AF_INET6) +- got_ipv6 = true; ++ res.got_ipv6 = true; + } + else + *pat = ((*pat)->next); +@@ -940,7 +960,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + && (req->ai_flags & AI_V4MAPPED) + /* Avoid generating the mapped addresses if we + know we are not going to need them. */ +- && ((req->ai_flags & AI_ALL) || !got_ipv6))) ++ && ((req->ai_flags & AI_ALL) || !res.got_ipv6))) + { + gethosts (AF_INET); + +@@ -1091,7 +1111,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + /* If we looked up IPv4 mapped address discard them here if + the caller isn't interested in all address and we have + found at least one IPv6 address. */ +- if (got_ipv6 ++ if (res.got_ipv6 + && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED + && IN6_IS_ADDR_V4MAPPED (at2->addr)) + goto ignore; diff --git a/SOURCES/glibc-RHEL-2426-8.patch b/SOURCES/glibc-RHEL-2426-8.patch new file mode 100644 index 0000000..bc3766b --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-8.patch @@ -0,0 +1,673 @@ +commit ec71cb961121760f81e55af5489e658dc89e96e6 +Author: Siddhesh Poyarekar +Date: Mon Mar 7 15:56:22 2022 +0530 + + gaih_inet: separate nss lookup loop into its own function + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit 906cecbe0889e601c91d9aba738049c73ebe4dd2) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 7c497a88f8b5b9f8..145ea6fa381ad14b 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -159,6 +159,14 @@ static const struct addrinfo default_hints = + .ai_next = NULL + }; + ++static void ++gaih_result_reset (struct gaih_result *res) ++{ ++ if (res->free_at) ++ free (res->at); ++ free (res->canon); ++ memset (res, 0, sizeof (*res)); ++} + + static int + gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, +@@ -197,13 +205,10 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + + /* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name + is not copied, and the struct hostent object must not be deallocated +- prematurely. The new addresses are appended to the tuple array in +- RESULT. */ ++ prematurely. The new addresses are appended to the tuple array in RES. */ + static bool +-convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, +- int family, +- struct hostent *h, +- struct gaih_addrtuple **result) ++convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, ++ struct hostent *h, struct gaih_result *res) + { + /* Count the number of addresses in h->h_addr_list. */ + size_t count = 0; +@@ -215,7 +220,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr)) + return true; + +- struct gaih_addrtuple *array = *result; ++ struct gaih_addrtuple *array = res->at; + size_t old = 0; + + while (array != NULL) +@@ -224,12 +229,14 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + array = array->next; + } + +- array = realloc (*result, (old + count) * sizeof (*array)); ++ array = realloc (res->at, (old + count) * sizeof (*array)); + + if (array == NULL) + return false; + +- *result = array; ++ res->got_ipv6 = family == AF_INET6; ++ res->at = array; ++ res->free_at = true; + + /* Update the next pointers on reallocation. */ + for (size_t i = 0; i < old; i++) +@@ -278,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + { \ + __resolv_context_put (res_ctx); \ + result = -EAI_MEMORY; \ +- goto free_and_return; \ ++ goto out; \ + } \ + } \ + if (status == NSS_STATUS_NOTFOUND \ +@@ -288,7 +295,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + { \ + __resolv_context_put (res_ctx); \ + result = -EAI_SYSTEM; \ +- goto free_and_return; \ ++ goto out; \ + } \ + if (h_errno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ +@@ -297,27 +304,24 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + } \ + else if (status == NSS_STATUS_SUCCESS) \ + { \ +- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \ ++ if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \ + { \ + __resolv_context_put (res_ctx); \ + result = -EAI_SYSTEM; \ +- goto free_and_return; \ ++ goto out; \ + } \ +- *pat = addrmem; \ + \ +- if (localcanon != NULL && res.canon == NULL) \ ++ if (localcanon != NULL && res->canon == NULL) \ + { \ + char *canonbuf = __strdup (localcanon); \ + if (canonbuf == NULL) \ + { \ + __resolv_context_put (res_ctx); \ + result = -EAI_SYSTEM; \ +- goto free_and_return; \ ++ goto out; \ + } \ +- res.canon = canonbuf; \ ++ res->canon = canonbuf; \ + } \ +- if (_family == AF_INET6 && *pat != NULL) \ +- res.got_ipv6 = true; \ + } \ + } + +@@ -590,6 +594,260 @@ out: + } + #endif + ++static int ++get_nss_addresses (const char *name, const struct addrinfo *req, ++ struct scratch_buffer *tmpbuf, struct gaih_result *res) ++{ ++ int no_data = 0; ++ int no_inet6_data = 0; ++ nss_action_list nip; ++ enum nss_status inet6_status = NSS_STATUS_UNAVAIL; ++ enum nss_status status = NSS_STATUS_UNAVAIL; ++ int no_more; ++ struct resolv_context *res_ctx = NULL; ++ bool do_merge = false; ++ int result = 0; ++ ++ no_more = !__nss_database_get (nss_database_hosts, &nip); ++ ++ /* If we are looking for both IPv4 and IPv6 address we don't ++ want the lookup functions to automatically promote IPv4 ++ addresses to IPv6 addresses, so we use the no_inet6 ++ function variant. */ ++ res_ctx = __resolv_context_get (); ++ if (res_ctx == NULL) ++ no_more = 1; ++ ++ while (!no_more) ++ { ++ /* Always start afresh; continue should discard previous results ++ and the hosts database does not support merge. */ ++ gaih_result_reset (res); ++ ++ if (do_merge) ++ { ++ __set_h_errno (NETDB_INTERNAL); ++ __set_errno (EBUSY); ++ break; ++ } ++ ++ no_data = 0; ++ nss_gethostbyname4_r *fct4 = NULL; ++ ++ /* gethostbyname4_r sends out parallel A and AAAA queries and ++ is thus only suitable for PF_UNSPEC. */ ++ if (req->ai_family == PF_UNSPEC) ++ fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); ++ ++ if (fct4 != NULL) ++ { ++ while (1) ++ { ++ status = DL_CALL_FCT (fct4, (name, &res->at, ++ tmpbuf->data, tmpbuf->length, ++ &errno, &h_errno, ++ NULL)); ++ if (status == NSS_STATUS_SUCCESS) ++ break; ++ /* gethostbyname4_r may write into AT, so reset it. */ ++ res->at = NULL; ++ if (status != NSS_STATUS_TRYAGAIN ++ || errno != ERANGE || h_errno != NETDB_INTERNAL) ++ { ++ if (h_errno == TRY_AGAIN) ++ no_data = EAI_AGAIN; ++ else ++ no_data = h_errno == NO_DATA; ++ break; ++ } ++ ++ if (!scratch_buffer_grow (tmpbuf)) ++ { ++ __resolv_context_put (res_ctx); ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ } ++ ++ if (status == NSS_STATUS_SUCCESS) ++ { ++ assert (!no_data); ++ no_data = 1; ++ ++ if ((req->ai_flags & AI_CANONNAME) != 0 && res->canon == NULL) ++ { ++ char *canonbuf = __strdup (res->at->name); ++ if (canonbuf == NULL) ++ { ++ __resolv_context_put (res_ctx); ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ res->canon = canonbuf; ++ } ++ ++ struct gaih_addrtuple **pat = &res->at; ++ ++ while (*pat != NULL) ++ { ++ if ((*pat)->family == AF_INET ++ && req->ai_family == AF_INET6 ++ && (req->ai_flags & AI_V4MAPPED) != 0) ++ { ++ uint32_t *pataddr = (*pat)->addr; ++ (*pat)->family = AF_INET6; ++ pataddr[3] = pataddr[0]; ++ pataddr[2] = htonl (0xffff); ++ pataddr[1] = 0; ++ pataddr[0] = 0; ++ pat = &((*pat)->next); ++ no_data = 0; ++ } ++ else if (req->ai_family == AF_UNSPEC ++ || (*pat)->family == req->ai_family) ++ { ++ pat = &((*pat)->next); ++ ++ no_data = 0; ++ if (req->ai_family == AF_INET6) ++ res->got_ipv6 = true; ++ } ++ else ++ *pat = ((*pat)->next); ++ } ++ } ++ ++ no_inet6_data = no_data; ++ } ++ else ++ { ++ nss_gethostbyname3_r *fct = NULL; ++ if (req->ai_flags & AI_CANONNAME) ++ /* No need to use this function if we do not look for ++ the canonical name. The function does not exist in ++ all NSS modules and therefore the lookup would ++ often fail. */ ++ fct = __nss_lookup_function (nip, "gethostbyname3_r"); ++ if (fct == NULL) ++ /* We are cheating here. The gethostbyname2_r ++ function does not have the same interface as ++ gethostbyname3_r but the extra arguments the ++ latter takes are added at the end. So the ++ gethostbyname2_r code will just ignore them. */ ++ fct = __nss_lookup_function (nip, "gethostbyname2_r"); ++ ++ if (fct != NULL) ++ { ++ if (req->ai_family == AF_INET6 ++ || req->ai_family == AF_UNSPEC) ++ { ++ gethosts (AF_INET6); ++ no_inet6_data = no_data; ++ inet6_status = status; ++ } ++ if (req->ai_family == AF_INET ++ || req->ai_family == AF_UNSPEC ++ || (req->ai_family == AF_INET6 ++ && (req->ai_flags & AI_V4MAPPED) ++ /* Avoid generating the mapped addresses if we ++ know we are not going to need them. */ ++ && ((req->ai_flags & AI_ALL) || !res->got_ipv6))) ++ { ++ gethosts (AF_INET); ++ ++ if (req->ai_family == AF_INET) ++ { ++ no_inet6_data = no_data; ++ inet6_status = status; ++ } ++ } ++ ++ /* If we found one address for AF_INET or AF_INET6, ++ don't continue the search. */ ++ if (inet6_status == NSS_STATUS_SUCCESS ++ || status == NSS_STATUS_SUCCESS) ++ { ++ if ((req->ai_flags & AI_CANONNAME) != 0 ++ && res->canon == NULL) ++ { ++ char *canonbuf = getcanonname (nip, res->at, name); ++ if (canonbuf == NULL) ++ { ++ __resolv_context_put (res_ctx); ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ res->canon = canonbuf; ++ } ++ status = NSS_STATUS_SUCCESS; ++ } ++ else ++ { ++ /* We can have different states for AF_INET and ++ AF_INET6. Try to find a useful one for both. */ ++ if (inet6_status == NSS_STATUS_TRYAGAIN) ++ status = NSS_STATUS_TRYAGAIN; ++ else if (status == NSS_STATUS_UNAVAIL ++ && inet6_status != NSS_STATUS_UNAVAIL) ++ status = inet6_status; ++ } ++ } ++ else ++ { ++ /* Could not locate any of the lookup functions. ++ The NSS lookup code does not consistently set ++ errno, so we need to supply our own error ++ code here. The root cause could either be a ++ resource allocation failure, or a missing ++ service function in the DSO (so it should not ++ be listed in /etc/nsswitch.conf). Assume the ++ former, and return EBUSY. */ ++ status = NSS_STATUS_UNAVAIL; ++ __set_h_errno (NETDB_INTERNAL); ++ __set_errno (EBUSY); ++ } ++ } ++ ++ if (nss_next_action (nip, status) == NSS_ACTION_RETURN) ++ break; ++ ++ /* The hosts database does not support MERGE. */ ++ if (nss_next_action (nip, status) == NSS_ACTION_MERGE) ++ do_merge = true; ++ ++ nip++; ++ if (nip->module == NULL) ++ no_more = -1; ++ } ++ ++ __resolv_context_put (res_ctx); ++ ++ /* If we have a failure which sets errno, report it using ++ EAI_SYSTEM. */ ++ if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) ++ && h_errno == NETDB_INTERNAL) ++ { ++ result = -EAI_SYSTEM; ++ goto out; ++ } ++ ++ if (no_data != 0 && no_inet6_data != 0) ++ { ++ /* If both requests timed out report this. */ ++ if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) ++ result = -EAI_AGAIN; ++ else ++ /* We made requests but they turned out no data. The name ++ is known, though. */ ++ result = -EAI_NODATA; ++ } ++ ++out: ++ if (result != 0) ++ gaih_result_reset (res); ++ return result; ++} ++ + /* Convert numeric addresses to binary into RES. On failure, RES->AT is set to + NULL and an error code is returned. If AI_NUMERIC_HOST is not requested and + the function cannot determine a result, RES->AT is set to NULL and 0 +@@ -723,7 +981,7 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req, + /* We found data, convert it. RES->AT from the conversion will + either be an allocated block or NULL, both of which are safe to + pass to free (). */ +- if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at)) ++ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, res)) + return -EAI_MEMORY; + + res->free_at = true; +@@ -801,264 +1059,14 @@ gaih_inet (const char *name, const struct gaih_service *service, + goto process_list; + #endif + +- int no_data = 0; +- int no_inet6_data = 0; +- nss_action_list nip; +- enum nss_status inet6_status = NSS_STATUS_UNAVAIL; +- enum nss_status status = NSS_STATUS_UNAVAIL; +- int no_more; +- struct resolv_context *res_ctx = NULL; +- bool do_merge = false; +- +- no_more = !__nss_database_get (nss_database_hosts, &nip); +- +- /* If we are looking for both IPv4 and IPv6 address we don't +- want the lookup functions to automatically promote IPv4 +- addresses to IPv6 addresses, so we use the no_inet6 +- function variant. */ +- res_ctx = __resolv_context_get (); +- if (res_ctx == NULL) +- no_more = 1; +- +- while (!no_more) +- { +- /* Always start afresh; continue should discard previous results +- and the hosts database does not support merge. */ +- res.at = NULL; +- free (res.canon); +- free (addrmem); +- res.canon = NULL; +- addrmem = NULL; +- got_ipv6 = false; +- +- if (do_merge) +- { +- __set_h_errno (NETDB_INTERNAL); +- __set_errno (EBUSY); +- break; +- } +- +- no_data = 0; +- nss_gethostbyname4_r *fct4 = NULL; +- +- /* gethostbyname4_r sends out parallel A and AAAA queries and +- is thus only suitable for PF_UNSPEC. */ +- if (req->ai_family == PF_UNSPEC) +- fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); +- +- if (fct4 != NULL) +- { +- while (1) +- { +- status = DL_CALL_FCT (fct4, (name, &res.at, +- tmpbuf->data, tmpbuf->length, +- &errno, &h_errno, +- NULL)); +- if (status == NSS_STATUS_SUCCESS) +- break; +- /* gethostbyname4_r may write into AT, so reset it. */ +- res.at = NULL; +- if (status != NSS_STATUS_TRYAGAIN +- || errno != ERANGE || h_errno != NETDB_INTERNAL) +- { +- if (h_errno == TRY_AGAIN) +- no_data = EAI_AGAIN; +- else +- no_data = h_errno == NO_DATA; +- break; +- } +- +- if (!scratch_buffer_grow (tmpbuf)) +- { +- __resolv_context_put (res_ctx); +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- } +- +- if (status == NSS_STATUS_SUCCESS) +- { +- assert (!no_data); +- no_data = 1; +- +- if ((req->ai_flags & AI_CANONNAME) != 0 && res.canon == NULL) +- { +- char *canonbuf = __strdup (res.at->name); +- if (canonbuf == NULL) +- { +- __resolv_context_put (res_ctx); +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- res.canon = canonbuf; +- } +- +- struct gaih_addrtuple **pat = &res.at; +- +- while (*pat != NULL) +- { +- if ((*pat)->family == AF_INET +- && req->ai_family == AF_INET6 +- && (req->ai_flags & AI_V4MAPPED) != 0) +- { +- uint32_t *pataddr = (*pat)->addr; +- (*pat)->family = AF_INET6; +- pataddr[3] = pataddr[0]; +- pataddr[2] = htonl (0xffff); +- pataddr[1] = 0; +- pataddr[0] = 0; +- pat = &((*pat)->next); +- no_data = 0; +- } +- else if (req->ai_family == AF_UNSPEC +- || (*pat)->family == req->ai_family) +- { +- pat = &((*pat)->next); +- +- no_data = 0; +- if (req->ai_family == AF_INET6) +- res.got_ipv6 = true; +- } +- else +- *pat = ((*pat)->next); +- } +- } +- +- no_inet6_data = no_data; +- } +- else +- { +- nss_gethostbyname3_r *fct = NULL; +- if (req->ai_flags & AI_CANONNAME) +- /* No need to use this function if we do not look for +- the canonical name. The function does not exist in +- all NSS modules and therefore the lookup would +- often fail. */ +- fct = __nss_lookup_function (nip, "gethostbyname3_r"); +- if (fct == NULL) +- /* We are cheating here. The gethostbyname2_r +- function does not have the same interface as +- gethostbyname3_r but the extra arguments the +- latter takes are added at the end. So the +- gethostbyname2_r code will just ignore them. */ +- fct = __nss_lookup_function (nip, "gethostbyname2_r"); +- +- if (fct != NULL) +- { +- struct gaih_addrtuple **pat = &res.at; +- +- if (req->ai_family == AF_INET6 +- || req->ai_family == AF_UNSPEC) +- { +- gethosts (AF_INET6); +- no_inet6_data = no_data; +- inet6_status = status; +- } +- if (req->ai_family == AF_INET +- || req->ai_family == AF_UNSPEC +- || (req->ai_family == AF_INET6 +- && (req->ai_flags & AI_V4MAPPED) +- /* Avoid generating the mapped addresses if we +- know we are not going to need them. */ +- && ((req->ai_flags & AI_ALL) || !res.got_ipv6))) +- { +- gethosts (AF_INET); +- +- if (req->ai_family == AF_INET) +- { +- no_inet6_data = no_data; +- inet6_status = status; +- } +- } +- +- /* If we found one address for AF_INET or AF_INET6, +- don't continue the search. */ +- if (inet6_status == NSS_STATUS_SUCCESS +- || status == NSS_STATUS_SUCCESS) +- { +- if ((req->ai_flags & AI_CANONNAME) != 0 +- && res.canon == NULL) +- { +- char *canonbuf = getcanonname (nip, res.at, name); +- if (canonbuf == NULL) +- { +- __resolv_context_put (res_ctx); +- result = -EAI_MEMORY; +- goto free_and_return; +- } +- res.canon = canonbuf; +- } +- status = NSS_STATUS_SUCCESS; +- } +- else +- { +- /* We can have different states for AF_INET and +- AF_INET6. Try to find a useful one for both. */ +- if (inet6_status == NSS_STATUS_TRYAGAIN) +- status = NSS_STATUS_TRYAGAIN; +- else if (status == NSS_STATUS_UNAVAIL +- && inet6_status != NSS_STATUS_UNAVAIL) +- status = inet6_status; +- } +- } +- else +- { +- /* Could not locate any of the lookup functions. +- The NSS lookup code does not consistently set +- errno, so we need to supply our own error +- code here. The root cause could either be a +- resource allocation failure, or a missing +- service function in the DSO (so it should not +- be listed in /etc/nsswitch.conf). Assume the +- former, and return EBUSY. */ +- status = NSS_STATUS_UNAVAIL; +- __set_h_errno (NETDB_INTERNAL); +- __set_errno (EBUSY); +- } +- } +- +- if (nss_next_action (nip, status) == NSS_ACTION_RETURN) +- break; +- +- /* The hosts database does not support MERGE. */ +- if (nss_next_action (nip, status) == NSS_ACTION_MERGE) +- do_merge = true; +- +- nip++; +- if (nip->module == NULL) +- no_more = -1; +- } +- +- __resolv_context_put (res_ctx); +- +- /* If we have a failure which sets errno, report it using +- EAI_SYSTEM. */ +- if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) +- && h_errno == NETDB_INTERNAL) +- { +- result = -EAI_SYSTEM; +- goto free_and_return; +- } +- +- if (no_data != 0 && no_inet6_data != 0) +- { +- /* If both requests timed out report this. */ +- if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) +- result = -EAI_AGAIN; +- else +- /* We made requests but they turned out no data. The name +- is known, though. */ +- result = -EAI_NODATA; +- +- goto free_and_return; +- } ++ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0) ++ goto free_and_return; ++ else if (res.at != NULL) ++ goto process_list; + +- process_list: +- if (res.at == NULL) +- { +- result = -EAI_NONAME; +- goto free_and_return; +- } ++ /* None of the lookups worked, so name not found. */ ++ result = -EAI_NONAME; ++ goto free_and_return; + } + else + { +@@ -1089,6 +1097,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + } + ++process_list: + { + /* Set up the canonical name if we need it. */ + if ((result = process_canonname (req, orig_name, &res)) != 0) diff --git a/SOURCES/glibc-RHEL-2426-9.patch b/SOURCES/glibc-RHEL-2426-9.patch new file mode 100644 index 0000000..f669307 --- /dev/null +++ b/SOURCES/glibc-RHEL-2426-9.patch @@ -0,0 +1,156 @@ +commit 4d59769087f2143f619b4b38bf93590a86f5c806 +Author: Siddhesh Poyarekar +Date: Mon Mar 7 19:48:48 2022 +0530 + + gaih_inet: make gethosts into a function + + The macro is quite a pain to debug, so make gethosts into a function to + make it easier to maintain. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + (cherry picked from commit cfa3bd48cb19a70e4367a9978dbba09d9df27a72) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 145ea6fa381ad14b..6be109d07f7fcce0 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -268,63 +268,54 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + return true; + } + +-#define gethosts(_family) \ +- { \ +- struct hostent th; \ +- char *localcanon = NULL; \ +- no_data = 0; \ +- while (1) \ +- { \ +- status = DL_CALL_FCT (fct, (name, _family, &th, \ +- tmpbuf->data, tmpbuf->length, \ +- &errno, &h_errno, NULL, &localcanon)); \ +- if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL \ +- || errno != ERANGE) \ +- break; \ +- if (!scratch_buffer_grow (tmpbuf)) \ +- { \ +- __resolv_context_put (res_ctx); \ +- result = -EAI_MEMORY; \ +- goto out; \ +- } \ +- } \ +- if (status == NSS_STATUS_NOTFOUND \ +- || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \ +- { \ +- if (h_errno == NETDB_INTERNAL) \ +- { \ +- __resolv_context_put (res_ctx); \ +- result = -EAI_SYSTEM; \ +- goto out; \ +- } \ +- if (h_errno == TRY_AGAIN) \ +- no_data = EAI_AGAIN; \ +- else \ +- no_data = h_errno == NO_DATA; \ +- } \ +- else if (status == NSS_STATUS_SUCCESS) \ +- { \ +- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \ +- { \ +- __resolv_context_put (res_ctx); \ +- result = -EAI_SYSTEM; \ +- goto out; \ +- } \ +- \ +- if (localcanon != NULL && res->canon == NULL) \ +- { \ +- char *canonbuf = __strdup (localcanon); \ +- if (canonbuf == NULL) \ +- { \ +- __resolv_context_put (res_ctx); \ +- result = -EAI_SYSTEM; \ +- goto out; \ +- } \ +- res->canon = canonbuf; \ +- } \ +- } \ +- } ++static int ++gethosts (nss_gethostbyname3_r fct, int family, const char *name, ++ const struct addrinfo *req, struct scratch_buffer *tmpbuf, ++ struct gaih_result *res, enum nss_status *statusp, int *no_datap) ++{ ++ struct hostent th; ++ char *localcanon = NULL; ++ enum nss_status status; ++ ++ *no_datap = 0; ++ while (1) ++ { ++ *statusp = status = DL_CALL_FCT (fct, (name, family, &th, ++ tmpbuf->data, tmpbuf->length, ++ &errno, &h_errno, NULL, ++ &localcanon)); ++ if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL ++ || errno != ERANGE) ++ break; ++ if (!scratch_buffer_grow (tmpbuf)) ++ return -EAI_MEMORY; ++ } ++ if (status == NSS_STATUS_NOTFOUND ++ || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) ++ { ++ if (h_errno == NETDB_INTERNAL) ++ return -EAI_SYSTEM; ++ if (h_errno == TRY_AGAIN) ++ *no_datap = EAI_AGAIN; ++ else ++ *no_datap = h_errno == NO_DATA; ++ } ++ else if (status == NSS_STATUS_SUCCESS) ++ { ++ if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res)) ++ return -EAI_SYSTEM; ++ ++ if (localcanon != NULL && res->canon == NULL) ++ { ++ char *canonbuf = __strdup (localcanon); ++ if (canonbuf == NULL) ++ return -EAI_SYSTEM; ++ res->canon = canonbuf; ++ } ++ } + ++ return 0; ++} + + /* This function is called if a canonical name is requested, but if + the service function did not provide it. It tries to obtain the +@@ -741,7 +732,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req, + if (req->ai_family == AF_INET6 + || req->ai_family == AF_UNSPEC) + { +- gethosts (AF_INET6); ++ if ((result = gethosts (fct, AF_INET6, name, req, tmpbuf, ++ res, &status, &no_data)) != 0) ++ { ++ __resolv_context_put (res_ctx); ++ goto out; ++ } + no_inet6_data = no_data; + inet6_status = status; + } +@@ -753,7 +749,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req, + know we are not going to need them. */ + && ((req->ai_flags & AI_ALL) || !res->got_ipv6))) + { +- gethosts (AF_INET); ++ if ((result = gethosts (fct, AF_INET, name, req, tmpbuf, ++ res, &status, &no_data)) != 0) ++ { ++ __resolv_context_put (res_ctx); ++ goto out; ++ } + + if (req->ai_family == AF_INET) + { diff --git a/SOURCES/glibc-RHEL-2438.patch b/SOURCES/glibc-RHEL-2438.patch new file mode 100644 index 0000000..46f1c9a --- /dev/null +++ b/SOURCES/glibc-RHEL-2438.patch @@ -0,0 +1,973 @@ +commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215 +Author: Siddhesh Poyarekar +Date: Thu Mar 17 11:44:34 2022 +0530 + + Simplify allocations and fix merge and continue actions [BZ #28931] + + Allocations for address tuples is currently a bit confusing because of + the pointer chasing through PAT, making it hard to observe the sequence + in which allocations have been made. Narrow scope of the pointer + chasing through PAT so that it is only used where necessary. + + This also tightens actions behaviour with the hosts database in + getaddrinfo to comply with the manual text. The "continue" action + discards previous results and the "merge" action results in an immedate + lookup failure. Consequently, chaining of allocations across modules is + no longer necessary, thus opening up cleanup opportunities. + + A test has been added that checks some combinations to ensure that they + work correctly. + + Resolves: BZ #28931 + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: DJ Delorie + +Conflicts: + nss/Makefile + (Tests applied in different order from upstream) + +diff --git a/nss/Makefile b/nss/Makefile +index f01674a16e720b88..333edb1588ede881 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -77,6 +77,7 @@ tests-container := \ + tst-nss-db-endpwent \ + tst-nss-files-hosts-long \ + tst-nss-files-hosts-v4mapped \ ++ tst-nss-gai-actions \ + tst-nss-test3 \ + tst-reload1 \ + tst-reload2 \ +diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c +new file mode 100644 +index 0000000000000000..efca6cd1837a172a +--- /dev/null ++++ b/nss/tst-nss-gai-actions.c +@@ -0,0 +1,149 @@ ++/* Test continue and merge NSS actions for getaddrinfo. ++ Copyright 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++enum ++{ ++ ACTION_MERGE = 0, ++ ACTION_CONTINUE, ++}; ++ ++static const char * ++family_str (int family) ++{ ++ switch (family) ++ { ++ case AF_UNSPEC: ++ return "AF_UNSPEC"; ++ case AF_INET: ++ return "AF_INET"; ++ default: ++ __builtin_unreachable (); ++ } ++} ++ ++static const char * ++action_str (int action) ++{ ++ switch (action) ++ { ++ case ACTION_MERGE: ++ return "merge"; ++ case ACTION_CONTINUE: ++ return "continue"; ++ default: ++ __builtin_unreachable (); ++ } ++} ++ ++static void ++do_one_test (int action, int family, bool canon) ++{ ++ struct addrinfo hints = ++ { ++ .ai_family = family, ++ }; ++ ++ struct addrinfo *ai; ++ ++ if (canon) ++ hints.ai_flags = AI_CANONNAME; ++ ++ printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n", ++ action_str (action), family_str (family), ++ canon ? "AI_CANONNAME" : ""); ++ ++ int ret = getaddrinfo ("example.org", "80", &hints, &ai); ++ ++ switch (action) ++ { ++ case ACTION_MERGE: ++ if (ret == 0) ++ { ++ char *formatted = support_format_addrinfo (ai, ret); ++ ++ printf ("merge unexpectedly succeeded:\n %s\n", formatted); ++ support_record_failure (); ++ free (formatted); ++ } ++ else ++ return; ++ case ACTION_CONTINUE: ++ { ++ char *formatted = support_format_addrinfo (ai, ret); ++ ++ /* Verify that the result appears exactly once. */ ++ const char *expected = "address: STREAM/TCP 192.0.0.1 80\n" ++ "address: DGRAM/UDP 192.0.0.1 80\n" ++ "address: RAW/IP 192.0.0.1 80\n"; ++ ++ const char *contains = strstr (formatted, expected); ++ const char *contains2 = NULL; ++ ++ if (contains != NULL) ++ contains2 = strstr (contains + strlen (expected), expected); ++ ++ if (contains == NULL || contains2 != NULL) ++ { ++ printf ("continue failed:\n%s\n", formatted); ++ support_record_failure (); ++ } ++ ++ free (formatted); ++ break; ++ } ++ default: ++ __builtin_unreachable (); ++ } ++} ++ ++static void ++do_one_test_set (int action) ++{ ++ char buf[32]; ++ ++ snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files", ++ action_str (action)); ++ __nss_configure_lookup ("hosts", buf); ++ ++ do_one_test (action, AF_UNSPEC, false); ++ do_one_test (action, AF_INET, false); ++ do_one_test (action, AF_INET, true); ++} ++ ++static int ++do_test (void) ++{ ++ do_one_test_set (ACTION_CONTINUE); ++ do_one_test_set (ACTION_MERGE); ++ return 0; ++} ++ ++#include +diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf +new file mode 100644 +index 0000000000000000..d1a59f73a90f2993 +--- /dev/null ++++ b/nss/tst-nss-gai-actions.root/etc/host.conf +@@ -0,0 +1 @@ ++multi on +diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts +new file mode 100644 +index 0000000000000000..50ce9774dc2c21d9 +--- /dev/null ++++ b/nss/tst-nss-gai-actions.root/etc/hosts +@@ -0,0 +1,508 @@ ++192.0.0.1 example.org ++192.0.0.2 example.org ++192.0.0.3 example.org ++192.0.0.4 example.org ++192.0.0.5 example.org ++192.0.0.6 example.org ++192.0.0.7 example.org ++192.0.0.8 example.org ++192.0.0.9 example.org ++192.0.0.10 example.org ++192.0.0.11 example.org ++192.0.0.12 example.org ++192.0.0.13 example.org ++192.0.0.14 example.org ++192.0.0.15 example.org ++192.0.0.16 example.org ++192.0.0.17 example.org ++192.0.0.18 example.org ++192.0.0.19 example.org ++192.0.0.20 example.org ++192.0.0.21 example.org ++192.0.0.22 example.org ++192.0.0.23 example.org ++192.0.0.24 example.org ++192.0.0.25 example.org ++192.0.0.26 example.org ++192.0.0.27 example.org ++192.0.0.28 example.org ++192.0.0.29 example.org ++192.0.0.30 example.org ++192.0.0.31 example.org ++192.0.0.32 example.org ++192.0.0.33 example.org ++192.0.0.34 example.org ++192.0.0.35 example.org ++192.0.0.36 example.org ++192.0.0.37 example.org ++192.0.0.38 example.org ++192.0.0.39 example.org ++192.0.0.40 example.org ++192.0.0.41 example.org ++192.0.0.42 example.org ++192.0.0.43 example.org ++192.0.0.44 example.org ++192.0.0.45 example.org ++192.0.0.46 example.org ++192.0.0.47 example.org ++192.0.0.48 example.org ++192.0.0.49 example.org ++192.0.0.50 example.org ++192.0.0.51 example.org ++192.0.0.52 example.org ++192.0.0.53 example.org ++192.0.0.54 example.org ++192.0.0.55 example.org ++192.0.0.56 example.org ++192.0.0.57 example.org ++192.0.0.58 example.org ++192.0.0.59 example.org ++192.0.0.60 example.org ++192.0.0.61 example.org ++192.0.0.62 example.org ++192.0.0.63 example.org ++192.0.0.64 example.org ++192.0.0.65 example.org ++192.0.0.66 example.org ++192.0.0.67 example.org ++192.0.0.68 example.org ++192.0.0.69 example.org ++192.0.0.70 example.org ++192.0.0.71 example.org ++192.0.0.72 example.org ++192.0.0.73 example.org ++192.0.0.74 example.org ++192.0.0.75 example.org ++192.0.0.76 example.org ++192.0.0.77 example.org ++192.0.0.78 example.org ++192.0.0.79 example.org ++192.0.0.80 example.org ++192.0.0.81 example.org ++192.0.0.82 example.org ++192.0.0.83 example.org ++192.0.0.84 example.org ++192.0.0.85 example.org ++192.0.0.86 example.org ++192.0.0.87 example.org ++192.0.0.88 example.org ++192.0.0.89 example.org ++192.0.0.90 example.org ++192.0.0.91 example.org ++192.0.0.92 example.org ++192.0.0.93 example.org ++192.0.0.94 example.org ++192.0.0.95 example.org ++192.0.0.96 example.org ++192.0.0.97 example.org ++192.0.0.98 example.org ++192.0.0.99 example.org ++192.0.0.100 example.org ++192.0.0.101 example.org ++192.0.0.102 example.org ++192.0.0.103 example.org ++192.0.0.104 example.org ++192.0.0.105 example.org ++192.0.0.106 example.org ++192.0.0.107 example.org ++192.0.0.108 example.org ++192.0.0.109 example.org ++192.0.0.110 example.org ++192.0.0.111 example.org ++192.0.0.112 example.org ++192.0.0.113 example.org ++192.0.0.114 example.org ++192.0.0.115 example.org ++192.0.0.116 example.org ++192.0.0.117 example.org ++192.0.0.118 example.org ++192.0.0.119 example.org ++192.0.0.120 example.org ++192.0.0.121 example.org ++192.0.0.122 example.org ++192.0.0.123 example.org ++192.0.0.124 example.org ++192.0.0.125 example.org ++192.0.0.126 example.org ++192.0.0.127 example.org ++192.0.0.128 example.org ++192.0.0.129 example.org ++192.0.0.130 example.org ++192.0.0.131 example.org ++192.0.0.132 example.org ++192.0.0.133 example.org ++192.0.0.134 example.org ++192.0.0.135 example.org ++192.0.0.136 example.org ++192.0.0.137 example.org ++192.0.0.138 example.org ++192.0.0.139 example.org ++192.0.0.140 example.org ++192.0.0.141 example.org ++192.0.0.142 example.org ++192.0.0.143 example.org ++192.0.0.144 example.org ++192.0.0.145 example.org ++192.0.0.146 example.org ++192.0.0.147 example.org ++192.0.0.148 example.org ++192.0.0.149 example.org ++192.0.0.150 example.org ++192.0.0.151 example.org ++192.0.0.152 example.org ++192.0.0.153 example.org ++192.0.0.154 example.org ++192.0.0.155 example.org ++192.0.0.156 example.org ++192.0.0.157 example.org ++192.0.0.158 example.org ++192.0.0.159 example.org ++192.0.0.160 example.org ++192.0.0.161 example.org ++192.0.0.162 example.org ++192.0.0.163 example.org ++192.0.0.164 example.org ++192.0.0.165 example.org ++192.0.0.166 example.org ++192.0.0.167 example.org ++192.0.0.168 example.org ++192.0.0.169 example.org ++192.0.0.170 example.org ++192.0.0.171 example.org ++192.0.0.172 example.org ++192.0.0.173 example.org ++192.0.0.174 example.org ++192.0.0.175 example.org ++192.0.0.176 example.org ++192.0.0.177 example.org ++192.0.0.178 example.org ++192.0.0.179 example.org ++192.0.0.180 example.org ++192.0.0.181 example.org ++192.0.0.182 example.org ++192.0.0.183 example.org ++192.0.0.184 example.org ++192.0.0.185 example.org ++192.0.0.186 example.org ++192.0.0.187 example.org ++192.0.0.188 example.org ++192.0.0.189 example.org ++192.0.0.190 example.org ++192.0.0.191 example.org ++192.0.0.192 example.org ++192.0.0.193 example.org ++192.0.0.194 example.org ++192.0.0.195 example.org ++192.0.0.196 example.org ++192.0.0.197 example.org ++192.0.0.198 example.org ++192.0.0.199 example.org ++192.0.0.200 example.org ++192.0.0.201 example.org ++192.0.0.202 example.org ++192.0.0.203 example.org ++192.0.0.204 example.org ++192.0.0.205 example.org ++192.0.0.206 example.org ++192.0.0.207 example.org ++192.0.0.208 example.org ++192.0.0.209 example.org ++192.0.0.210 example.org ++192.0.0.211 example.org ++192.0.0.212 example.org ++192.0.0.213 example.org ++192.0.0.214 example.org ++192.0.0.215 example.org ++192.0.0.216 example.org ++192.0.0.217 example.org ++192.0.0.218 example.org ++192.0.0.219 example.org ++192.0.0.220 example.org ++192.0.0.221 example.org ++192.0.0.222 example.org ++192.0.0.223 example.org ++192.0.0.224 example.org ++192.0.0.225 example.org ++192.0.0.226 example.org ++192.0.0.227 example.org ++192.0.0.228 example.org ++192.0.0.229 example.org ++192.0.0.230 example.org ++192.0.0.231 example.org ++192.0.0.232 example.org ++192.0.0.233 example.org ++192.0.0.234 example.org ++192.0.0.235 example.org ++192.0.0.236 example.org ++192.0.0.237 example.org ++192.0.0.238 example.org ++192.0.0.239 example.org ++192.0.0.240 example.org ++192.0.0.241 example.org ++192.0.0.242 example.org ++192.0.0.243 example.org ++192.0.0.244 example.org ++192.0.0.245 example.org ++192.0.0.246 example.org ++192.0.0.247 example.org ++192.0.0.248 example.org ++192.0.0.249 example.org ++192.0.0.250 example.org ++192.0.0.251 example.org ++192.0.0.252 example.org ++192.0.0.253 example.org ++192.0.0.254 example.org ++192.0.1.1 example.org ++192.0.1.2 example.org ++192.0.1.3 example.org ++192.0.1.4 example.org ++192.0.1.5 example.org ++192.0.1.6 example.org ++192.0.1.7 example.org ++192.0.1.8 example.org ++192.0.1.9 example.org ++192.0.1.10 example.org ++192.0.1.11 example.org ++192.0.1.12 example.org ++192.0.1.13 example.org ++192.0.1.14 example.org ++192.0.1.15 example.org ++192.0.1.16 example.org ++192.0.1.17 example.org ++192.0.1.18 example.org ++192.0.1.19 example.org ++192.0.1.20 example.org ++192.0.1.21 example.org ++192.0.1.22 example.org ++192.0.1.23 example.org ++192.0.1.24 example.org ++192.0.1.25 example.org ++192.0.1.26 example.org ++192.0.1.27 example.org ++192.0.1.28 example.org ++192.0.1.29 example.org ++192.0.1.30 example.org ++192.0.1.31 example.org ++192.0.1.32 example.org ++192.0.1.33 example.org ++192.0.1.34 example.org ++192.0.1.35 example.org ++192.0.1.36 example.org ++192.0.1.37 example.org ++192.0.1.38 example.org ++192.0.1.39 example.org ++192.0.1.40 example.org ++192.0.1.41 example.org ++192.0.1.42 example.org ++192.0.1.43 example.org ++192.0.1.44 example.org ++192.0.1.45 example.org ++192.0.1.46 example.org ++192.0.1.47 example.org ++192.0.1.48 example.org ++192.0.1.49 example.org ++192.0.1.50 example.org ++192.0.1.51 example.org ++192.0.1.52 example.org ++192.0.1.53 example.org ++192.0.1.54 example.org ++192.0.1.55 example.org ++192.0.1.56 example.org ++192.0.1.57 example.org ++192.0.1.58 example.org ++192.0.1.59 example.org ++192.0.1.60 example.org ++192.0.1.61 example.org ++192.0.1.62 example.org ++192.0.1.63 example.org ++192.0.1.64 example.org ++192.0.1.65 example.org ++192.0.1.66 example.org ++192.0.1.67 example.org ++192.0.1.68 example.org ++192.0.1.69 example.org ++192.0.1.70 example.org ++192.0.1.71 example.org ++192.0.1.72 example.org ++192.0.1.73 example.org ++192.0.1.74 example.org ++192.0.1.75 example.org ++192.0.1.76 example.org ++192.0.1.77 example.org ++192.0.1.78 example.org ++192.0.1.79 example.org ++192.0.1.80 example.org ++192.0.1.81 example.org ++192.0.1.82 example.org ++192.0.1.83 example.org ++192.0.1.84 example.org ++192.0.1.85 example.org ++192.0.1.86 example.org ++192.0.1.87 example.org ++192.0.1.88 example.org ++192.0.1.89 example.org ++192.0.1.90 example.org ++192.0.1.91 example.org ++192.0.1.92 example.org ++192.0.1.93 example.org ++192.0.1.94 example.org ++192.0.1.95 example.org ++192.0.1.96 example.org ++192.0.1.97 example.org ++192.0.1.98 example.org ++192.0.1.99 example.org ++192.0.1.100 example.org ++192.0.1.101 example.org ++192.0.1.102 example.org ++192.0.1.103 example.org ++192.0.1.104 example.org ++192.0.1.105 example.org ++192.0.1.106 example.org ++192.0.1.107 example.org ++192.0.1.108 example.org ++192.0.1.109 example.org ++192.0.1.110 example.org ++192.0.1.111 example.org ++192.0.1.112 example.org ++192.0.1.113 example.org ++192.0.1.114 example.org ++192.0.1.115 example.org ++192.0.1.116 example.org ++192.0.1.117 example.org ++192.0.1.118 example.org ++192.0.1.119 example.org ++192.0.1.120 example.org ++192.0.1.121 example.org ++192.0.1.122 example.org ++192.0.1.123 example.org ++192.0.1.124 example.org ++192.0.1.125 example.org ++192.0.1.126 example.org ++192.0.1.127 example.org ++192.0.1.128 example.org ++192.0.1.129 example.org ++192.0.1.130 example.org ++192.0.1.131 example.org ++192.0.1.132 example.org ++192.0.1.133 example.org ++192.0.1.134 example.org ++192.0.1.135 example.org ++192.0.1.136 example.org ++192.0.1.137 example.org ++192.0.1.138 example.org ++192.0.1.139 example.org ++192.0.1.140 example.org ++192.0.1.141 example.org ++192.0.1.142 example.org ++192.0.1.143 example.org ++192.0.1.144 example.org ++192.0.1.145 example.org ++192.0.1.146 example.org ++192.0.1.147 example.org ++192.0.1.148 example.org ++192.0.1.149 example.org ++192.0.1.150 example.org ++192.0.1.151 example.org ++192.0.1.152 example.org ++192.0.1.153 example.org ++192.0.1.154 example.org ++192.0.1.155 example.org ++192.0.1.156 example.org ++192.0.1.157 example.org ++192.0.1.158 example.org ++192.0.1.159 example.org ++192.0.1.160 example.org ++192.0.1.161 example.org ++192.0.1.162 example.org ++192.0.1.163 example.org ++192.0.1.164 example.org ++192.0.1.165 example.org ++192.0.1.166 example.org ++192.0.1.167 example.org ++192.0.1.168 example.org ++192.0.1.169 example.org ++192.0.1.170 example.org ++192.0.1.171 example.org ++192.0.1.172 example.org ++192.0.1.173 example.org ++192.0.1.174 example.org ++192.0.1.175 example.org ++192.0.1.176 example.org ++192.0.1.177 example.org ++192.0.1.178 example.org ++192.0.1.179 example.org ++192.0.1.180 example.org ++192.0.1.181 example.org ++192.0.1.182 example.org ++192.0.1.183 example.org ++192.0.1.184 example.org ++192.0.1.185 example.org ++192.0.1.186 example.org ++192.0.1.187 example.org ++192.0.1.188 example.org ++192.0.1.189 example.org ++192.0.1.190 example.org ++192.0.1.191 example.org ++192.0.1.192 example.org ++192.0.1.193 example.org ++192.0.1.194 example.org ++192.0.1.195 example.org ++192.0.1.196 example.org ++192.0.1.197 example.org ++192.0.1.198 example.org ++192.0.1.199 example.org ++192.0.1.200 example.org ++192.0.1.201 example.org ++192.0.1.202 example.org ++192.0.1.203 example.org ++192.0.1.204 example.org ++192.0.1.205 example.org ++192.0.1.206 example.org ++192.0.1.207 example.org ++192.0.1.208 example.org ++192.0.1.209 example.org ++192.0.1.210 example.org ++192.0.1.211 example.org ++192.0.1.212 example.org ++192.0.1.213 example.org ++192.0.1.214 example.org ++192.0.1.215 example.org ++192.0.1.216 example.org ++192.0.1.217 example.org ++192.0.1.218 example.org ++192.0.1.219 example.org ++192.0.1.220 example.org ++192.0.1.221 example.org ++192.0.1.222 example.org ++192.0.1.223 example.org ++192.0.1.224 example.org ++192.0.1.225 example.org ++192.0.1.226 example.org ++192.0.1.227 example.org ++192.0.1.228 example.org ++192.0.1.229 example.org ++192.0.1.230 example.org ++192.0.1.231 example.org ++192.0.1.232 example.org ++192.0.1.233 example.org ++192.0.1.234 example.org ++192.0.1.235 example.org ++192.0.1.236 example.org ++192.0.1.237 example.org ++192.0.1.238 example.org ++192.0.1.239 example.org ++192.0.1.240 example.org ++192.0.1.241 example.org ++192.0.1.242 example.org ++192.0.1.243 example.org ++192.0.1.244 example.org ++192.0.1.245 example.org ++192.0.1.246 example.org ++192.0.1.247 example.org ++192.0.1.248 example.org ++192.0.1.249 example.org ++192.0.1.250 example.org ++192.0.1.251 example.org ++192.0.1.252 example.org ++192.0.1.253 example.org ++192.0.1.254 example.org +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 43dfc6739e350a58..f391dc0a59849aab 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -458,11 +458,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + + if (name != NULL) + { +- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); +- at->family = AF_UNSPEC; +- at->scopeid = 0; +- at->next = NULL; +- + if (req->ai_flags & AI_IDN) + { + char *out; +@@ -473,13 +468,21 @@ gaih_inet (const char *name, const struct gaih_service *service, + malloc_name = true; + } + +- if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0) ++ uint32_t addr[4]; ++ if (__inet_aton_exact (name, (struct in_addr *) addr) != 0) + { ++ at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); ++ at->scopeid = 0; ++ at->next = NULL; ++ + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) +- at->family = AF_INET; ++ { ++ memcpy (at->addr, addr, sizeof (at->addr)); ++ at->family = AF_INET; ++ } + else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) + { +- at->addr[3] = at->addr[0]; ++ at->addr[3] = addr[0]; + at->addr[2] = htonl (0xffff); + at->addr[1] = 0; + at->addr[0] = 0; +@@ -493,49 +496,62 @@ gaih_inet (const char *name, const struct gaih_service *service, + + if (req->ai_flags & AI_CANONNAME) + canon = name; ++ ++ goto process_list; + } +- else if (at->family == AF_UNSPEC) ++ ++ char *scope_delim = strchr (name, SCOPE_DELIMITER); ++ int e; ++ ++ if (scope_delim == NULL) ++ e = inet_pton (AF_INET6, name, addr); ++ else ++ e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr); ++ ++ if (e > 0) + { +- char *scope_delim = strchr (name, SCOPE_DELIMITER); +- int e; +- if (scope_delim == NULL) +- e = inet_pton (AF_INET6, name, at->addr); ++ at = alloca_account (sizeof (struct gaih_addrtuple), ++ alloca_used); ++ at->scopeid = 0; ++ at->next = NULL; ++ ++ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) ++ { ++ memcpy (at->addr, addr, sizeof (at->addr)); ++ at->family = AF_INET6; ++ } ++ else if (req->ai_family == AF_INET ++ && IN6_IS_ADDR_V4MAPPED (addr)) ++ { ++ at->addr[0] = addr[3]; ++ at->addr[1] = addr[1]; ++ at->addr[2] = addr[2]; ++ at->addr[3] = addr[3]; ++ at->family = AF_INET; ++ } + else +- e = __inet_pton_length (AF_INET6, name, scope_delim - name, +- at->addr); +- if (e > 0) + { +- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) +- at->family = AF_INET6; +- else if (req->ai_family == AF_INET +- && IN6_IS_ADDR_V4MAPPED (at->addr)) +- { +- at->addr[0] = at->addr[3]; +- at->family = AF_INET; +- } +- else +- { +- result = -EAI_ADDRFAMILY; +- goto free_and_return; +- } +- +- if (scope_delim != NULL +- && __inet6_scopeid_pton ((struct in6_addr *) at->addr, +- scope_delim + 1, +- &at->scopeid) != 0) +- { +- result = -EAI_NONAME; +- goto free_and_return; +- } ++ result = -EAI_ADDRFAMILY; ++ goto free_and_return; ++ } + +- if (req->ai_flags & AI_CANONNAME) +- canon = name; ++ if (scope_delim != NULL ++ && __inet6_scopeid_pton ((struct in6_addr *) at->addr, ++ scope_delim + 1, ++ &at->scopeid) != 0) ++ { ++ result = -EAI_NONAME; ++ goto free_and_return; + } ++ ++ if (req->ai_flags & AI_CANONNAME) ++ canon = name; ++ ++ goto process_list; + } + +- if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) ++ if ((req->ai_flags & AI_NUMERICHOST) == 0) + { +- struct gaih_addrtuple **pat = &at; + int no_data = 0; + int no_inet6_data = 0; + nss_action_list nip; +@@ -543,6 +559,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + enum nss_status status = NSS_STATUS_UNAVAIL; + int no_more; + struct resolv_context *res_ctx = NULL; ++ bool do_merge = false; + + /* If we do not have to look for IPv6 addresses or the canonical + name, use the simple, old functions, which do not support +@@ -579,7 +596,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + result = -EAI_MEMORY; + goto free_and_return; + } +- *pat = addrmem; ++ at = addrmem; + } + else + { +@@ -632,6 +649,8 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + + struct gaih_addrtuple *addrfree = addrmem; ++ struct gaih_addrtuple **pat = &at; ++ + for (int i = 0; i < air->naddrs; ++i) + { + socklen_t size = (air->family[i] == AF_INET +@@ -695,12 +714,6 @@ gaih_inet (const char *name, const struct gaih_service *service, + + free (air); + +- if (at->family == AF_UNSPEC) +- { +- result = -EAI_NONAME; +- goto free_and_return; +- } +- + goto process_list; + } + else if (err == 0) +@@ -732,6 +745,22 @@ gaih_inet (const char *name, const struct gaih_service *service, + + while (!no_more) + { ++ /* Always start afresh; continue should discard previous results ++ and the hosts database does not support merge. */ ++ at = NULL; ++ free (canonbuf); ++ free (addrmem); ++ canon = canonbuf = NULL; ++ addrmem = NULL; ++ got_ipv6 = false; ++ ++ if (do_merge) ++ { ++ __set_h_errno (NETDB_INTERNAL); ++ __set_errno (EBUSY); ++ break; ++ } ++ + no_data = 0; + nss_gethostbyname4_r *fct4 = NULL; + +@@ -744,12 +773,14 @@ gaih_inet (const char *name, const struct gaih_service *service, + { + while (1) + { +- status = DL_CALL_FCT (fct4, (name, pat, ++ status = DL_CALL_FCT (fct4, (name, &at, + tmpbuf->data, tmpbuf->length, + &errno, &h_errno, + NULL)); + if (status == NSS_STATUS_SUCCESS) + break; ++ /* gethostbyname4_r may write into AT, so reset it. */ ++ at = NULL; + if (status != NSS_STATUS_TRYAGAIN + || errno != ERANGE || h_errno != NETDB_INTERNAL) + { +@@ -774,7 +805,9 @@ gaih_inet (const char *name, const struct gaih_service *service, + no_data = 1; + + if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) +- canon = (*pat)->name; ++ canon = at->name; ++ ++ struct gaih_addrtuple **pat = &at; + + while (*pat != NULL) + { +@@ -826,6 +859,8 @@ gaih_inet (const char *name, const struct gaih_service *service, + + if (fct != NULL) + { ++ struct gaih_addrtuple **pat = &at; ++ + if (req->ai_family == AF_INET6 + || req->ai_family == AF_UNSPEC) + { +@@ -899,6 +934,10 @@ gaih_inet (const char *name, const struct gaih_service *service, + if (nss_next_action (nip, status) == NSS_ACTION_RETURN) + break; + ++ /* The hosts database does not support MERGE. */ ++ if (nss_next_action (nip, status) == NSS_ACTION_MERGE) ++ do_merge = true; ++ + nip++; + if (nip->module == NULL) + no_more = -1; +@@ -930,7 +969,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + } + + process_list: +- if (at->family == AF_UNSPEC) ++ if (at == NULL) + { + result = -EAI_NONAME; + goto free_and_return; diff --git a/SOURCES/glibc-RHEL-2491.patch b/SOURCES/glibc-RHEL-2491.patch new file mode 100644 index 0000000..79f18b8 --- /dev/null +++ b/SOURCES/glibc-RHEL-2491.patch @@ -0,0 +1,112 @@ +commit 849274d48fc59bfa6db3c713c8ced8026b20f3b7 +Author: Florian Weimer +Date: Thu Nov 16 19:55:35 2023 +0100 + + elf: Fix force_first handling in dlclose (bug 30981) + + The force_first parameter was ineffective because the dlclose'd + object was not necessarily the first in the maps array. Also + enable force_first handling unconditionally, regardless of namespace. + The initial object in a namespace should be destructed first, too. + + The _dl_sort_maps_dfs function had early returns for relocation + dependency processing which broke force_first handling, too, and + this is fixed in this change as well. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 95a03c9616c6a786..9d158c25498fd8ae 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -182,6 +182,16 @@ _dl_close_worker (struct link_map *map, bool force) + } + assert (idx == nloaded); + ++ /* Put the dlclose'd map first, so that its destructor runs first. ++ The map variable is NULL after a retry. */ ++ if (map != NULL) ++ { ++ maps[map->l_idx] = maps[0]; ++ maps[map->l_idx]->l_idx = map->l_idx; ++ maps[0] = map; ++ maps[0]->l_idx = 0; ++ } ++ + /* Keep track of the lowest index link map we have covered already. */ + int done_index = -1; + while (++done_index < nloaded) +@@ -255,9 +265,10 @@ _dl_close_worker (struct link_map *map, bool force) + } + } + +- /* Sort the entries. We can skip looking for the binary itself which is +- at the front of the search list for the main namespace. */ +- _dl_sort_maps (maps, nloaded, (nsid == LM_ID_BASE), true); ++ /* Sort the entries. Unless retrying, the maps[0] object (the ++ original argument to dlclose) needs to remain first, so that its ++ destructor runs first. */ ++ _dl_sort_maps (maps, nloaded, /* force_first */ map != NULL, true); + + /* Call all termination functions at once. */ + bool unload_any = false; +@@ -768,7 +779,11 @@ _dl_close_worker (struct link_map *map, bool force) + /* Recheck if we need to retry, release the lock. */ + out: + if (dl_close_state == rerun) +- goto retry; ++ { ++ /* The map may have been deallocated. */ ++ map = NULL; ++ goto retry; ++ } + + dl_close_state = not_pending; + } +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index e8ef5e8b3588ab53..937feb6e7008bc62 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -260,13 +260,12 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + The below memcpy is not needed in the do_reldeps case here, + since we wrote back to maps[] during DFS traversal. */ + if (maps_head == maps) +- return; ++ break; + } + assert (maps_head == maps); +- return; + } +- +- memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); ++ else ++ memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); + + /* Skipping the first object at maps[0] is not valid in general, + since traversing along object dependency-links may "find" that +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +index 4bf9052db16fb352..cf6453e9eb85ac65 100644 +--- a/elf/dso-sort-tests-1.def ++++ b/elf/dso-sort-tests-1.def +@@ -56,14 +56,16 @@ output: b>a>{}b->c->d order). +-# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based +-# dynamic_sort=2 algorithm does, although it is still arguable whether going +-# beyond spec to do this is the right thing to do. ++# The older dynamic_sort=1 algorithm originally did not achieve this, ++# but this was a bug in the way _dl_sort_maps was called from _dl_close_worker, ++# effectively disabling proper force_first handling. ++# The new dynamic_sort=2 algorithm shows the effect of the simpler force_first ++# handling: the a object is simply moved to the front. + # The below expected outputs are what the two algorithms currently produce + # respectively, for regression testing purposes. + tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c +-output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[ +Date: Tue Sep 19 11:52:44 2023 -0400 + + tunables: Terminate if end of input is reached (CVE-2023-4911) + + The string parsing routine may end up writing beyond bounds of tunestr + if the input tunable string is malformed, of the form name=name=val. + This gets processed twice, first as name=name=val and next as name=val, + resulting in tunestr being name=name=val:name=val, thus overflowing + tunestr. + + Terminate the parsing loop at the first instance itself so that tunestr + does not overflow. + + This also fixes up tst-env-setuid-tunables to actually handle failures + correct and add new tests to validate the fix for this CVE. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Carlos O'Donell +--- +Tested on x86_64. + + NEWS | 5 +++++ + elf/dl-tunables.c | 17 ++++++++++------- + elf/tst-env-setuid-tunables.c | 36 +++++++++++++++++++++++++++-------- + 3 files changed, 43 insertions(+), 15 deletions(-) + +Conflicts: + NEWS + (Dropped) + elf/tst-env-setuid-tunables.c + (Trivial HAVE_TUNABLES conflict) + +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index 8009e54ee5db32be..837474b5044cb5d7 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -188,11 +188,7 @@ parse_tunables (char *tunestr, char *valstring) + /* If we reach the end of the string before getting a valid name-value + pair, bail out. */ + if (p[len] == '\0') +- { +- if (__libc_enable_secure) +- tunestr[off] = '\0'; +- return; +- } ++ break; + + /* We did not find a valid name-value pair before encountering the + colon. */ +@@ -252,9 +248,16 @@ parse_tunables (char *tunestr, char *valstring) + } + } + +- if (p[len] != '\0') +- p += len + 1; ++ /* We reached the end while processing the tunable string. */ ++ if (p[len] == '\0') ++ break; ++ ++ p += len + 1; + } ++ ++ /* Terminate tunestr before we leave. */ ++ if (__libc_enable_secure) ++ tunestr[off] = '\0'; + } + #endif + +diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c +index 05619c9adc8b2698..cd4e84364074c613 100644 +--- a/elf/tst-env-setuid-tunables.c ++++ b/elf/tst-env-setuid-tunables.c +@@ -52,6 +52,8 @@ const char *teststrings[] = + "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", + "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096", + "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.check=2", + "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2", + "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096", + ":glibc.malloc.garbage=2:glibc.malloc.check=1", +@@ -70,6 +72,8 @@ const char *resultstrings[] = + "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "", + "", + "", + "", +@@ -84,11 +88,18 @@ test_child (int off) + const char *val = getenv ("GLIBC_TUNABLES"); + + #if HAVE_TUNABLES ++ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val); ++ fflush (stdout); + if (val != NULL && strcmp (val, resultstrings[off]) == 0) + return 0; + + if (val != NULL) +- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); ++ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n", ++ off, val, resultstrings[off]); ++ else ++ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off); ++ ++ fflush (stdout); + + return 1; + #else +@@ -117,21 +128,26 @@ do_test (int argc, char **argv) + if (ret != 0) + exit (1); + +- exit (EXIT_SUCCESS); ++ /* Special return code to make sure that the child executed all the way ++ through. */ ++ exit (42); + } + else + { +- int ret = 0; +- + /* Spawn tests. */ + for (int i = 0; i < array_length (teststrings); i++) + { + char buf[INT_BUFSIZE_BOUND (int)]; + +- printf ("Spawned test for %s (%d)\n", teststrings[i], i); ++ printf ("[%d] Spawned test for %s\n", i, teststrings[i]); + snprintf (buf, sizeof (buf), "%d\n", i); ++ fflush (stdout); + if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) +- exit (1); ++ { ++ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i); ++ support_record_failure (); ++ continue; ++ } + + int status = support_capture_subprogram_self_sgid (buf); + +@@ -139,9 +155,14 @@ do_test (int argc, char **argv) + if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) + return EXIT_UNSUPPORTED; + +- ret |= status; ++ if (WEXITSTATUS (status) != 42) ++ { ++ printf (" [%d] child failed with status %d\n", i, ++ WEXITSTATUS (status)); ++ support_record_failure (); ++ } + } +- return ret; ++ return 0; + } + } + diff --git a/SOURCES/glibc-RHEL-3397.patch b/SOURCES/glibc-RHEL-3397.patch new file mode 100644 index 0000000..7dbd1e4 --- /dev/null +++ b/SOURCES/glibc-RHEL-3397.patch @@ -0,0 +1,83 @@ +commit c00b984fcd53f679ca2dafcd1aee2c89836e6e73 +Author: Florian Weimer +Date: Tue Aug 29 08:28:31 2023 +0200 + + nscd: Skip unusable entries in first pass in prune_cache (bug 30800) + + Previously, if an entry was marked unusable for any reason, but had + not timed out yet, the assert would trigger. + + One way to get into such state is if a data change is detected during + re-validation of an entry. This causes the entry to be marked as not + usable. If exits nscd soon after that, then the clock jumps + backwards, and nscd restarted, the cache re-validation run after + startup triggers the removed assert. + + The change is more complicated than just the removal of the assert + because entries marked as not usable should be garbage-collected in + the second pass. To make this happen, it is necessary to update some + book-keeping data. + + Reviewed-by: DJ Delorie + +diff --git a/nscd/cache.c b/nscd/cache.c +index 78b2269788699e6f..ac5902ae10b791bb 100644 +--- a/nscd/cache.c ++++ b/nscd/cache.c +@@ -371,8 +371,11 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + serv2str[runp->type], str, dh->timeout); + } + +- /* Check whether the entry timed out. */ +- if (dh->timeout < now) ++ /* Check whether the entry timed out. Timed out entries ++ will be revalidated. For unusable records, it is still ++ necessary to record that the bucket needs to be scanned ++ again below. */ ++ if (dh->timeout < now || !dh->usable) + { + /* This hash bucket could contain entries which need to + be looked at. */ +@@ -384,7 +387,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + /* We only have to look at the data of the first entries + since the count information is kept in the data part + which is shared. */ +- if (runp->first) ++ if (runp->first && dh->usable) + { + + /* At this point there are two choices: we reload the +@@ -400,9 +403,6 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + { + /* Remove the value. */ + dh->usable = false; +- +- /* We definitely have some garbage entries now. */ +- any = true; + } + else + { +@@ -414,18 +414,15 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + + time_t timeout = readdfcts[runp->type] (table, runp, dh); + next_timeout = MIN (next_timeout, timeout); +- +- /* If the entry has been replaced, we might need +- cleanup. */ +- any |= !dh->usable; + } + } ++ ++ /* If the entry has been replaced, we might need cleanup. */ ++ any |= !dh->usable; + } + else +- { +- assert (dh->usable); +- next_timeout = MIN (next_timeout, dh->timeout); +- } ++ /* Entry has not timed out and is usable. */ ++ next_timeout = MIN (next_timeout, dh->timeout); + + run = runp->next; + } diff --git a/SOURCES/glibc-rh2234716.patch b/SOURCES/glibc-rh2234716.patch new file mode 100644 index 0000000..cdf298e --- /dev/null +++ b/SOURCES/glibc-rh2234716.patch @@ -0,0 +1,187 @@ +commit bd77dd7e73e3530203be1c52c8a29d08270cb25d +Author: Florian Weimer +Date: Wed Sep 13 14:10:56 2023 +0200 + + CVE-2023-4527: Stack read overflow with large TCP responses in no-aaaa mode + + Without passing alt_dns_packet_buffer, __res_context_search can only + store 2048 bytes (what fits into dns_packet_buffer). However, + the function returns the total packet size, and the subsequent + DNS parsing code in _nss_dns_gethostbyname4_r reads beyond the end + of the stack-allocated buffer. + + Fixes commit f282cdbe7f436c75864e5640a4 ("resolv: Implement no-aaaa + stub resolver option") and bug 30842. + +Conflits: + resolv/Makefile + (missing tests) + +diff --git a/resolv/Makefile b/resolv/Makefile +index ea1518ec2da860c1..2c43d52122ef4343 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -102,6 +102,7 @@ tests += \ + tst-resolv-invalid-cname \ + tst-resolv-network \ + tst-resolv-noaaaa \ ++ tst-resolv-noaaaa-vc \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ +@@ -280,6 +281,7 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ + $(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-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 36789965c06757d0..3d261b6810bba5c9 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -428,7 +428,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + { + n = __res_context_search (ctx, name, C_IN, T_A, + dns_packet_buffer, sizeof (dns_packet_buffer), +- NULL, NULL, NULL, NULL, NULL); ++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); + if (n >= 0) + status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, + &abuf, pat, errnop, herrnop, ttlp); +diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c +new file mode 100644 +index 0000000000000000..9f5aebd99f2d74a2 +--- /dev/null ++++ b/resolv/tst-resolv-noaaaa-vc.c +@@ -0,0 +1,129 @@ ++/* Test the RES_NOAAAA resolver option with a large response. ++ Copyright (C) 2022-2023 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to keep track of the number of queries. */ ++static volatile unsigned int queries; ++ ++/* If true, add a large TXT record at the start of the answer section. */ ++static volatile bool stuff_txt; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* If not using TCP, just force its use. */ ++ if (!ctx->tcp) ++ { ++ struct resolv_response_flags flags = {.tc = true}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ /* The test needs to send four queries, the first three are used to ++ grow the NSS buffer via the ERANGE handshake. */ ++ ++queries; ++ TEST_VERIFY (queries <= 4); ++ ++ /* AAAA queries are supposed to be disabled. */ ++ TEST_COMPARE (qtype, T_A); ++ TEST_COMPARE (qclass, C_IN); ++ TEST_COMPARE_STRING (qname, "example.com"); ++ ++ 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); ++ ++ if (stuff_txt) ++ { ++ resolv_response_open_record (b, qname, qclass, T_TXT, 60); ++ int zero = 0; ++ for (int i = 0; i <= 15000; ++i) ++ resolv_response_add_data (b, &zero, sizeof (zero)); ++ resolv_response_close_record (b); ++ } ++ ++ for (int i = 0; i < 200; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, qtype, 60); ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ resolv_response_close_record (b); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ _res.options |= RES_NOAAAA; ++ ++ for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt) ++ { ++ queries = 0; ++ stuff_txt = do_stuff_txt; ++ ++ struct addrinfo *ai = NULL; ++ int ret; ++ ret = getaddrinfo ("example.com", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ ++ char *expected_result; ++ { ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ for (int i = 0; i < 200; ++i) ++ fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1); ++ xfclose_memstream (&mem); ++ expected_result = mem.buffer; ++ } ++ ++ check_addrinfo ("example.com", ai, ret, expected_result); ++ ++ free (expected_result); ++ freeaddrinfo (ai); ++ } ++ ++ resolv_test_end (obj); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rhel-17157.patch b/SOURCES/glibc-rhel-17157.patch new file mode 100644 index 0000000..5ea1f99 --- /dev/null +++ b/SOURCES/glibc-rhel-17157.patch @@ -0,0 +1,95 @@ +commit 472894d2cfee5751b44c0aaa71ed87df81c8e62e +Author: Adhemerval Zanella +Date: Wed Oct 11 13:43:56 2023 -0300 + + malloc: Use __get_nprocs on arena_get2 (BZ 30945) + + This restore the 2.33 semantic for arena_get2. It was changed by + 11a02b035b46 to avoid arena_get2 call malloc (back when __get_nproc + was refactored to use an scratch_buffer - 903bc7dcc2acafc). The + __get_nproc was refactored over then and now it also avoid to call + malloc. + + The 11a02b035b46 did not take in consideration any performance + implication, which should have been discussed properly. The + __get_nprocs_sched is still used as a fallback mechanism if procfs + and sysfs is not acessible. + + Checked on x86_64-linux-gnu. + Reviewed-by: DJ Delorie + +diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h +index c490561581..65742b1036 100644 +--- a/include/sys/sysinfo.h ++++ b/include/sys/sysinfo.h +@@ -14,10 +14,6 @@ libc_hidden_proto (__get_nprocs_conf) + extern int __get_nprocs (void); + libc_hidden_proto (__get_nprocs) + +-/* Return the number of available processors which the process can +- be scheduled. */ +-extern int __get_nprocs_sched (void) attribute_hidden; +- + /* Return number of physical pages of memory in the system. */ + extern long int __get_phys_pages (void); + libc_hidden_proto (__get_phys_pages) +diff --git a/malloc/arena.c b/malloc/arena.c +index d1e214ac2e..a1a75e5a2b 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -824,7 +824,7 @@ arena_get2 (size_t size, mstate avoid_arena) + narenas_limit = mp_.arena_max; + else if (narenas > mp_.arena_test) + { +- int n = __get_nprocs_sched (); ++ int n = __get_nprocs (); + + if (n >= 1) + narenas_limit = NARENAS_FROM_NCORES (n); +diff --git a/misc/getsysstats.c b/misc/getsysstats.c +index 5f36adc0e8..23cc112074 100644 +--- a/misc/getsysstats.c ++++ b/misc/getsysstats.c +@@ -44,12 +44,6 @@ weak_alias (__get_nprocs, get_nprocs) + link_warning (get_nprocs, "warning: get_nprocs will always return 1") + + +-int +-__get_nprocs_sched (void) +-{ +- return 1; +-} +- + long int + __get_phys_pages (void) + { +diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c +index 5184e5eee1..d3834f3b69 100644 +--- a/sysdeps/mach/getsysstats.c ++++ b/sysdeps/mach/getsysstats.c +@@ -62,12 +62,6 @@ __get_nprocs (void) + libc_hidden_def (__get_nprocs) + weak_alias (__get_nprocs, get_nprocs) + +-int +-__get_nprocs_sched (void) +-{ +- return __get_nprocs (); +-} +- + /* Return the number of physical pages on the system. */ + long int + __get_phys_pages (void) +diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c +index b0b6c154ac..1ea7f1f01f 100644 +--- a/sysdeps/unix/sysv/linux/getsysstats.c ++++ b/sysdeps/unix/sysv/linux/getsysstats.c +@@ -29,7 +29,7 @@ + #include + #include + +-int ++static int + __get_nprocs_sched (void) + { + enum diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index b055feb..a573345 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -155,7 +155,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: 82%{?dist} +Release: 100%{?dist} # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -747,6 +747,67 @@ Patch506: glibc-rh2166710-2.patch Patch507: glibc-rh2166710-3.patch Patch508: glibc-rh2222188-6.patch Patch509: glibc-rh2213907-7.patch +Patch510: glibc-RHEL-1017-1.patch +Patch511: glibc-RHEL-1017-2.patch +Patch512: glibc-RHEL-1017-3.patch +Patch513: glibc-RHEL-1017-4.patch +# (Reverted fixes for RHEL-2491 were here.) +Patch519: glibc-rh2234716.patch +Patch520: glibc-RHEL-2438.patch +Patch521: glibc-RHEL-2426-1.patch +Patch522: glibc-RHEL-2426-2.patch +Patch523: glibc-RHEL-2426-3.patch +Patch524: glibc-RHEL-2426-4.patch +Patch525: glibc-RHEL-2426-5.patch +Patch526: glibc-RHEL-2426-6.patch +Patch527: glibc-RHEL-2426-7.patch +Patch528: glibc-RHEL-2426-8.patch +Patch529: glibc-RHEL-2426-9.patch +Patch530: glibc-RHEL-2426-10.patch +Patch531: glibc-RHEL-2426-11.patch +Patch532: glibc-RHEL-2426-12.patch +Patch533: glibc-RHEL-2426-13.patch +Patch534: glibc-RHEL-3000.patch +Patch535: glibc-RHEL-2426-14.patch +Patch536: glibc-RHEL-2426-15.patch +Patch537: glibc-RHEL-1191.patch +Patch538: glibc-RHEL-3397.patch +Patch539: glibc-RHEL-2123.patch +Patch540: glibc-RHEL-16275.patch +Patch541: glibc-RHEL-2491.patch +Patch542: glibc-RHEL-14383-1.patch +Patch543: glibc-RHEL-14383-2.patch +Patch544: glibc-RHEL-2338-1.patch +Patch545: glibc-RHEL-2338-2.patch +Patch546: glibc-RHEL-2338-3.patch +Patch547: glibc-RHEL-2338-4.patch +Patch548: glibc-RHEL-15343-1.patch +Patch549: glibc-RHEL-15343-2.patch +Patch550: glibc-RHEL-15343-3.patch +Patch551: glibc-RHEL-15343-4.patch +Patch552: glibc-rhel-17157.patch +Patch553: glibc-RHEL-16016-1.patch +Patch554: glibc-RHEL-16016-2.patch +Patch555: glibc-RHEL-16016-3.patch +Patch556: glibc-RHEL-16016-4.patch +Patch557: glibc-RHEL-16016-5.patch +Patch558: glibc-RHEL-16016-6.patch +Patch559: glibc-RHEL-16016-7.patch +Patch560: glibc-RHEL-17319-1.patch +Patch561: glibc-RHEL-17319-2.patch +Patch562: glibc-RHEL-17319-3.patch +Patch563: glibc-RHEL-17319-4.patch +Patch564: glibc-RHEL-17465-1.patch +Patch565: glibc-RHEL-17465-2.patch +Patch566: glibc-RHEL-19862.patch +Patch567: glibc-RHEL-16643-1.patch +Patch568: glibc-RHEL-16643-2.patch +Patch569: glibc-RHEL-16643-3.patch +Patch570: glibc-RHEL-16643-4.patch +Patch571: glibc-RHEL-16643-5.patch +Patch572: glibc-RHEL-16643-6.patch +Patch573: glibc-RHEL-19444.patch +Patch574: glibc-RHEL-21556.patch ############################################################################## # Continued list of core "glibc" package information: @@ -1914,6 +1975,7 @@ gzip -9nvf %{glibc_sysroot}%{_infodir}/libc* # Copy the debugger interface documentation over to the right location mkdir -p %{glibc_sysroot}%{_docdir}/glibc cp elf/rtld-debugger-interface.txt %{glibc_sysroot}%{_docdir}/glibc +cp posix/gai.conf %{glibc_sysroot}%{_docdir}/glibc %else rm -f %{glibc_sysroot}%{_infodir}/dir rm -f %{glibc_sysroot}%{_infodir}/libc.info* @@ -2904,6 +2966,82 @@ update_gconv_modules_cache () %endif %changelog +* Wed Jan 24 2024 Patsy Griffin - 2.34-100 +- manual: fix order of arguments of memalign and aligned_alloc (RHEL-21556) + +* Tue Jan 09 2024 Arjun Shankar - 2.34-99 +- getaddrinfo: Return correct error EAI_MEMORY when out-of-memory (RHEL-19444) + +* Mon Jan 8 2024 Arjun Shankar - 2.34-98 +- getaddrinfo: Fix occasionally empty result due to nscd cache order (RHEL-16643) + +* Tue Jan 2 2024 Florian Weimer - 2.34-97 +- Re-enable output buffering for wide stdio streams (RHEL-19862) + +* Thu Dec 21 2023 Carlos O'Donell - 2.34-96 +- Fix TLS corruption during dlopen()/dlclose() sequences (RHEL-17465) + +* Fri Dec 8 2023 Florian Weimer - 2.34-95 +- Improve compatibility between underlinking and IFUNC resolvers (RHEL-17319) + +* Thu Dec 7 2023 Patsy Griffin - 2.34-94 +- Update syscall-names.list for Linux 6.6. (RHEL-16016) + +* Wed Dec 6 2023 Patsy Griffin - 2.34-93 +- malloc: Use __get_nprocs on arena_get2. (RHEL-17157) + +* Fri Dec 1 2023 Patsy Griffin - 2.34-92 +- Improve test coverage for wcsdup, strdup and strndup. (RHEL-15343) + +* Fri Nov 24 2023 Florian Weimer - 2.34-91 +- fstat performance enhancement (RHEL-2338) + +* Tue Nov 21 2023 Florian Weimer - 2.34-90 +- ldconfig should skip temporary files created by RPM (RHEL-14383) + +* Mon Nov 20 2023 Florian Weimer - 2.34-89 +- Fix force-first handling in dlclose (RHEL-2491) + +* Wed Nov 15 2023 Arjun Shankar - 2.34-88 +- nscd: Refer to /run instead of /var/run in systemd socket file + (RHEL-16275) + +* Fri Nov 10 2023 Florian Weimer - 2.34-87 +- Fix slow tls access after dlopen (RHEL-2123) + +* Tue Oct 24 2023 Arjun Shankar - 2.34-86 +- Add /usr/share/doc/glibc/gai.conf to glibc-doc (RHEL-14545) + +* Fri Oct 20 2023 Florian Weimer - 2.34-85 +- nscd: Skip unusable entries in first pass in prune_cache (RHEL-3397) + +* Mon Oct 9 2023 Florian Weimer - 2.34-84 +- x86-64: Report non-zero cache sizes under TDX hypervisors (RHEL-1191) + +* Mon Sep 25 2023 Florian Weimer - 2.34-83.7 +- Fix memory leak regression in getaddrinfo (RHEL-2426) + +* Tue Sep 19 2023 Carlos O'Donell - 2.34-83.6 +- CVE-2023-4911 glibc: buffer overflow in ld.so leading to privilege escalation (RHEL-3000) + +* Tue Sep 19 2023 Florian Weimer - 2.34-83.5 +- Revert: Always call destructors in reverse constructor order (RHEL-2491) + +* Mon Sep 18 2023 Siddhesh Poyarekar - 2.34-83.4 +- CVE-2023-4806 glibc: potential use-after-free in getaddrinfo (RHEL-2426) + +* Fri Sep 15 2023 Siddhesh Poyarekar - 2.34-83.3 +- CVE-2023-4813: potential use-after-free in gaih_inet (RHEL-2438) + +* Fri Sep 15 2023 Carlos O'Donell - 2.34-83.2 +- CVE-2023-4527: Stack read overflow in getaddrinfo in no-aaaa mode (#2234716) + +* Thu Sep 14 2023 Carlos O'Donell - 2.34-83.1 +- Always call destructors in reverse constructor order (RHEL-2491) + +* Wed Sep 13 2023 DJ Delorie - 2.34-83 +- Add support for ppc64le hwcaps tunables (RHEL-1017) + * Tue Aug 15 2023 Carlos O'Donell - 2.34-82 - Fix string and memory function tuning on small systems (#2213907)