Compare commits

...

No commits in common. 'i10c-beta' and 'c9' have entirely different histories.

4
.gitignore vendored

@ -1 +1,3 @@
SOURCES/glibc-2.39.tar.xz SOURCES/glibc-2.34.tar.xz
SOURCES/glibc-c-utf8-locale-2.patch
SOURCES/glibc-upstream-2.34-373.patch

@ -1 +1,3 @@
4b043eaba31efbdfc92c85d062e975141870295e SOURCES/glibc-2.39.tar.xz 7c3b8890a6346793b6334cc5f2fea5d437d307b8 SOURCES/glibc-2.34.tar.xz
47cf1a27ae2e86b37e44c49f6bf4630a1adabd9a SOURCES/glibc-c-utf8-locale-2.patch
6022f103e5596ad229f22bc966327d71208f7016 SOURCES/glibc-upstream-2.34-373.patch

File diff suppressed because it is too large Load Diff

@ -1,79 +0,0 @@
commit 95f61610f3e481d191b6184432342236fd59186d
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jul 24 12:06:47 2024 +0200
resolv: Support clearing option flags with a “-” prefix (bug 14799)
I think using a “-” prefix is less confusing than introducing
double-negation construct (“no-no-tld-query”).
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 263263d474721545..243532b3ade338d8 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -682,27 +682,29 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options)
{
char str[22];
uint8_t len;
- uint8_t clear;
unsigned long int flag;
} options[] = {
#define STRnLEN(str) str, sizeof (str) - 1
- { STRnLEN ("rotate"), 0, RES_ROTATE },
- { STRnLEN ("edns0"), 0, RES_USE_EDNS0 },
- { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP },
- { STRnLEN ("single-request"), 0, RES_SNGLKUP },
- { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY },
- { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY },
- { STRnLEN ("no-reload"), 0, RES_NORELOAD },
- { STRnLEN ("use-vc"), 0, RES_USEVC },
- { STRnLEN ("trust-ad"), 0, RES_TRUSTAD },
- { STRnLEN ("no-aaaa"), 0, RES_NOAAAA },
+ { STRnLEN ("rotate"), RES_ROTATE },
+ { STRnLEN ("edns0"), RES_USE_EDNS0 },
+ { STRnLEN ("single-request-reopen"), RES_SNGLKUPREOP },
+ { STRnLEN ("single-request"), RES_SNGLKUP },
+ { STRnLEN ("no_tld_query"), RES_NOTLDQUERY },
+ { STRnLEN ("no-tld-query"), RES_NOTLDQUERY },
+ { STRnLEN ("no-reload"), RES_NORELOAD },
+ { STRnLEN ("use-vc"), RES_USEVC },
+ { STRnLEN ("trust-ad"), RES_TRUSTAD },
+ { STRnLEN ("no-aaaa"), RES_NOAAAA },
};
#define noptions (sizeof (options) / sizeof (options[0]))
+ bool negate_option = *cp == '-';
+ if (negate_option)
+ ++cp;
for (int i = 0; i < noptions; ++i)
if (strncmp (cp, options[i].str, options[i].len) == 0)
{
- if (options[i].clear)
- parser->template.options &= options[i].flag;
+ if (negate_option)
+ parser->template.options &= ~options[i].flag;
else
parser->template.options |= options[i].flag;
break;
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index 6bef62cde2cbf8cd..d3a19eb305d41467 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -679,6 +679,16 @@ struct test_case test_cases[] =
"; nameserver[0]: [192.0.2.1]:53\n",
.res_options = "attempts:5 ndots:3 edns0 ",
},
+ {.name = "RES_OPTIONS can clear flags",
+ .conf = "options ndots:2 use-vc no-aaaa edns0\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "options ndots:3 use-vc\n"
+ "search example.com\n"
+ "; search[0]: example.com\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n",
+ .res_options = "ndots:3 -edns0 -no-aaaa",
+ },
{.name = "many search list entries (bug 19569)",
.conf = "nameserver 192.0.2.1\n"
"search corp.example.com support.example.com"

@ -1,204 +0,0 @@
commit 765325951ac5c7d072278c9424930b29657e9758
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jul 24 12:06:47 2024 +0200
resolv: Implement strict-error stub resolver option (bug 27929)
For now, do not enable this mode by default due to the potential
impact on compatibility with existing deployments.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 243532b3ade338d8..b838dc70642e1935 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -695,6 +695,7 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options)
{ STRnLEN ("use-vc"), RES_USEVC },
{ STRnLEN ("trust-ad"), RES_TRUSTAD },
{ STRnLEN ("no-aaaa"), RES_NOAAAA },
+ { STRnLEN ("strict-error"), RES_STRICTERR },
};
#define noptions (sizeof (options) / sizeof (options[0]))
bool negate_option = *cp == '-';
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 9c77613f374e5469..9a284ed44aa8cc2e 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -1234,21 +1234,38 @@ send_dg(res_state statp,
if (thisansp_error) {
next_ns:
- if (recvresp1 || (buf2 != NULL && recvresp2)) {
- *resplen2 = 0;
- return resplen;
- }
- if (buf2 != NULL && !single_request)
+ /* Outside of strict-error mode, use the first
+ response even if the second response is an
+ error. This allows parallel resolution to
+ succeed even if the recursive resolver
+ always answers with SERVFAIL for AAAA
+ queries (which still happens in practice
+ unfortunately).
+
+ In strict-error mode, always switch to the
+ next server and try to get a response from
+ there. */
+ if ((statp->options & RES_STRICTERR) == 0)
{
- /* No data from the first reply. */
- resplen = 0;
- /* We are waiting for a possible second reply. */
- if (matching_query == 1)
- recvresp1 = 1;
- else
- recvresp2 = 1;
-
- goto wait;
+ if (recvresp1 || (buf2 != NULL && recvresp2))
+ {
+ *resplen2 = 0;
+ return resplen;
+ }
+
+ if (buf2 != NULL && !single_request)
+ {
+ /* No data from the first reply. */
+ resplen = 0;
+ /* We are waiting for a possible
+ second reply. */
+ if (matching_query == 1)
+ recvresp1 = 1;
+ else
+ recvresp2 = 1;
+
+ goto wait;
+ }
}
/* don't retry if called from dig */
diff --git a/resolv/resolv.h b/resolv/resolv.h
index f40d6c58cee0f585..b8a0f66a5fd50e22 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -133,6 +133,7 @@ struct res_sym {
#define RES_NORELOAD 0x02000000 /* No automatic configuration reload. */
#define RES_TRUSTAD 0x04000000 /* Request AD bit, keep it in responses. */
#define RES_NOAAAA 0x08000000 /* Suppress AAAA queries. */
+#define RES_STRICTERR 0x10000000 /* Report more DNS errors as errors. */
#define RES_DEFAULT (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH)
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index d3a19eb305d41467..e41bcebd9d9a8024 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -129,6 +129,7 @@ print_resp (FILE *fp, res_state resp)
print_option_flag (fp, &options, RES_NORELOAD, "no-reload");
print_option_flag (fp, &options, RES_TRUSTAD, "trust-ad");
print_option_flag (fp, &options, RES_NOAAAA, "no-aaaa");
+ print_option_flag (fp, &options, RES_STRICTERR, "strict-error");
fputc ('\n', fp);
if (options != 0)
fprintf (fp, "; error: unresolved option bits: 0x%x\n", options);
@@ -741,6 +742,15 @@ struct test_case test_cases[] =
"nameserver 192.0.2.1\n"
"; nameserver[0]: [192.0.2.1]:53\n"
},
+ {.name = "strict-error flag",
+ .conf = "options strict-error\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "options strict-error\n"
+ "search example.com\n"
+ "; search[0]: example.com\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ },
{ NULL }
};
diff --git a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c
index aa9798b5a7dfaa88..b7681210f450bb5a 100644
--- a/resolv/tst-resolv-semi-failure.c
+++ b/resolv/tst-resolv-semi-failure.c
@@ -67,6 +67,9 @@ response (const struct resolv_response_context *ctx,
resolv_response_close_record (b);
}
+/* Set to 1 if strict error checking is enabled. */
+static int do_strict_error;
+
static void
check_one (void)
{
@@ -83,7 +86,10 @@ check_one (void)
struct addrinfo *ai;
int ret = getaddrinfo ("www.example", "80", &hints, &ai);
const char *expected;
- if (ret == 0 && ai->ai_next != NULL)
+ /* In strict-error mode, a switch to the second name server
+ happens, and both responses are received, so a single
+ response is a bug. */
+ if (do_strict_error || (ret == 0 && ai->ai_next != NULL))
expected = ("address: STREAM/TCP 192.0.2.17 80\n"
"address: STREAM/TCP 2001:db8::1 80\n");
else
@@ -99,33 +105,36 @@ check_one (void)
static int
do_test (void)
{
- for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup)
- {
- struct resolv_test *aux = resolv_test_start
- ((struct resolv_redirect_config)
- {
- .response_callback = response,
- });
+ for (do_strict_error = 0; do_strict_error < 2; ++do_strict_error)
+ for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup)
+ {
+ struct resolv_test *aux = resolv_test_start
+ ((struct resolv_redirect_config)
+ {
+ .response_callback = response,
+ });
- if (do_single_lookup)
- _res.options |= RES_SNGLKUP;
+ if (do_strict_error)
+ _res.options |= RES_STRICTERR;
+ if (do_single_lookup)
+ _res.options |= RES_SNGLKUP;
- for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa)
- {
- fail_aaaa = do_fail_aaaa;
+ for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa)
+ {
+ fail_aaaa = do_fail_aaaa;
- rcode = 2; /* SERVFAIL. */
- check_one ();
+ rcode = 2; /* SERVFAIL. */
+ check_one ();
- rcode = 4; /* NOTIMP. */
- check_one ();
+ rcode = 4; /* NOTIMP. */
+ check_one ();
- rcode = 5; /* REFUSED. */
- check_one ();
- }
+ rcode = 5; /* REFUSED. */
+ check_one ();
+ }
- resolv_test_end (aux);
- }
+ resolv_test_end (aux);
+ }
return 0;
}

@ -0,0 +1,432 @@
From e4ca6de1bc5e4ba3f94cf0c501a293c5bc827b10 Mon Sep 17 00:00:00 2001
From: Anton Blanchard <anton@ozlabs.org>
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 <tuliom@linux.ibm.com>
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

@ -0,0 +1,83 @@
From f2a15dd668913c5a1388ba7e1131b25162b2ea75 Mon Sep 17 00:00:00 2001
From: Anton Blanchard <anton@ozlabs.org>
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 <tuliom@linux.ibm.com>
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);

@ -0,0 +1,703 @@
From 60b4dd25790342b40e8942e3a4115f511a6b6911 Mon Sep 17 00:00:00 2001
From: Anton Blanchard <anton@ozlabs.org>
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 <tuliom@linux.ibm.com>
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);

@ -0,0 +1,652 @@
From 21841f0d562f0e944c4d267a28cc3ebd19c847e9 Mon Sep 17 00:00:00 2001
From: Mahesh Bodapati <bmahi496@linux.ibm.com>
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 <adhemerval.zanella@linaro.org>
[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
- <https://www.gnu.org/licenses/>. */
-
-#include <stdint.h>
-#include <cpu-features.h>
-
-#if HAVE_TUNABLES
-# include <elf/dl-tunables.h>
-#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
- <https://www.gnu.org/licenses/>. */
-
-#ifndef __CPU_FEATURES_POWERPC_H
-# define __CPU_FEATURES_POWERPC_H
-
-#include <stdbool.h>
-
-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 <unistd.h>
#include <shlib-compat.h>
#include <dl-procinfo.h>
+#include <cpu-features.c>
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 <wchar.h>
#include <ldsodefs.h>
#include <ifunc-impl-list.h>
+#include <cpu-features.h>
/* 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 @@
<https://www.gnu.org/licenses/>. */
#include <ldsodefs.h>
+#include <cpu-features.h>
/* 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 <dl-tls.h>
#include <sysdep.h>
#include <hwcapinfo.h>
-#include <cpu-features.c>
#include <dl-static-tls.h>
#include <dl-funcdesc.h>
#include <dl-machine-rel.h>
@@ -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 @@
<https://www.gnu.org/licenses/>. */
#include <assert.h>
+#include <cpu-features.h>
#include <string.h>
#include <wchar.h>
#include <ldsodefs.h>
@@ -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
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <stdint.h>
+#include <cpu-features.h>
+#include <elf/dl-tunables.h>
+#include <unistd.h>
+#include <string.h>
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef __CPU_FEATURES_POWERPC_H
+# define __CPU_FEATURES_POWERPC_H
+
+#include <stdbool.h>
+#include <sys/auxv.h>
+
+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
+ <http://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <getopt.h>
+#include <ifunc-impl-list.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <sys/auxv.h>
+#include <sys/wait.h>
+
+/* 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 <support/test-driver.c>

@ -0,0 +1,69 @@
commit 1493622f4f9048ffede3fbedb64695efa49d662a
Author: H.J. Lu <hjl.tools@gmail.com>
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,

@ -0,0 +1,72 @@
commit 2aa0974d2573441bffd596b07bff8698b1f2f18c
Author: Florian Weimer <fweimer@redhat.com>
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 <adhemerval.zanella@linaro.org>
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)
{

@ -0,0 +1,61 @@
commit cfb5a97a93ea656e3b2263e42142a4032986d9ba
Author: Florian Weimer <fweimer@redhat.com>
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;
}

@ -0,0 +1,26 @@
commit 1626d8a521c7c771d4118b1328421fea113cab64
Author: Joe Simmons-Talbott <josimmon@redhat.com>
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 <adhemerval.zanella@linaro.org>
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; \

@ -0,0 +1,233 @@
commit eaaad78db41724e5a18a42becb238bfc4e683998
Author: Joe Simmons-Talbott <josimmon@redhat.com>
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 <adhemerval.zanella@linaro.org>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+
+#ifdef WIDE
+# include <wchar.h>
+# 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 <support/test-driver.c>

@ -0,0 +1,232 @@
commit 0c48aa0551151ea201f7f528492e89a0b08a6890
Author: Joe Simmons-Talbott <josimmon@redhat.com>
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 <adhemerval.zanella@linaro.org>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+
+#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 <support/test-driver.c>

@ -0,0 +1,33 @@
commit 0aa5b28a504c6f1f17b387d8147715d1496fff62
Author: Joe Simmons-Talbott <josimmon@redhat.com>
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 <adhemerval.zanella@linaro.org>
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"

@ -0,0 +1,26 @@
commit 919b9bfaa969c9517fe86c753c001b96ee4ea840
Author: Joseph Myers <joseph@codesourcery.com>
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

@ -0,0 +1,24 @@
commit 5ab9b2c92411eb52f7b7a8e6074f0740d9bd727b
Author: Joseph Myers <joseph@codesourcery.com>
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

@ -0,0 +1,26 @@
commit f8e8effa2629c74769a3552aba33175746b710bb
Author: Joseph Myers <joseph@codesourcery.com>
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

@ -0,0 +1,26 @@
commit eeef96f56ce399f2c3fc1d93c0ba1dde34f3ae41
Author: Joseph Myers <joseph@codesourcery.com>
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

@ -0,0 +1,83 @@
commit 1a21693e16a3f3d10f41c486b97fbecb53dd2087
Author: Joseph Myers <joseph@codesourcery.com>
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

@ -0,0 +1,338 @@
commit 72511f539cc34681ec61c6a0dc2fe6d684760ffe
Author: Joseph Myers <joseph@codesourcery.com>
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

@ -0,0 +1,350 @@
commit 582383b37d95b133c1ee6855ffaa2b1f5cb3d3b8
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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

@ -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

@ -0,0 +1,211 @@
commit 06890c7ba553e82393413c59bb3131db5815a337
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
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;
}

@ -0,0 +1,584 @@
commit bc0d18d873abf2cda6842ad8bb4df2a31dc0fbac
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
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 ();
}

@ -0,0 +1,90 @@
commit d3f2c2c8b57bdf9d963db8fa2372d6c1b86a337e
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
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. */

@ -0,0 +1,32 @@
commit c9226c03da0276593a0918eaa9a14835183343e8
Author: Jörg Sonnenberger <joerg@bec.de>
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 <siddhesh@sourceware.org>
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;

@ -0,0 +1,25 @@
commit 3bf7bab88b0da01d4f5ef20afbbb45203185501e
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
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

@ -0,0 +1,23 @@
commit 61bac1a9d2ab80ebcbc51484722e6ea43414bec7
Author: Florian Weimer <fweimer@redhat.com>
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 <carlos@redhat.com>
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)
{

@ -0,0 +1,35 @@
commit b893410be304ddcea0bd43f537a13e8b18d37cf2
Author: Florian Weimer <fweimer@redhat.com>
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 <carlos@redhat.com>
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?

@ -0,0 +1,121 @@
commit a74c2e1cbc8673dd7e97aae2f2705392e2ccc3f6
Author: Florian Weimer <fweimer@redhat.com>
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 <carlos@redhat.com>
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. */

@ -0,0 +1,224 @@
commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec
Author: Florian Weimer <fweimer@redhat.com>
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 <carlos@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+/* 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
+ <https://www.gnu.org/licenses/>. */
+
+/* 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-nodeps2-mod.so", RTLD_NOW);
+ xdlclose (handle);
+ return 0;
+}
+
+#include <support/test-driver.c>

@ -0,0 +1,41 @@
commit b3bee76c5f59498b9c189608f0a3132e2013fa1a
Author: Florian Weimer <fweimer@redhat.com>
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 <carlos@redhat.com>
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;

@ -0,0 +1,47 @@
commit 3921c5b40f293c57cb326f58713c924b0662ef59
Author: Hector Martin <marcan@marcan.st>
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 <szabolcs.nagy@arm.com>
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;
}

@ -0,0 +1,198 @@
commit 980450f12685326729d63ff72e93a996113bf073
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
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 <adhemerval.zanella@linaro.org>
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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+#include <support/check.h>
+
+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 <support/test-driver.c>

@ -0,0 +1,29 @@
commit 5eabdb6a6ac1599d23dd5966a37417215950245f
Author: Andreas Schwab <schwab@suse.de>
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)
{

@ -0,0 +1,27 @@
commit ecc7c3deb9f347649c2078fcc0f94d4cedf92d60
Author: Florian Weimer <fweimer@redhat.com>
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. */

@ -0,0 +1,369 @@
From 317f1c0a8a71a862b1e600ff5386b08e02cf4b95 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 26 Jan 2023 08:26:18 -0800
Subject: [PATCH] x86-64: Add glibc.cpu.prefer_map_32bit_exec [BZ #28656]
Content-type: text/plain; charset=UTF-8
Crossing 2GB boundaries with indirect calls and jumps can use more
branch prediction resources on Intel Golden Cove CPU (see the
"Misprediction for Branches >2GB" section in Intel 64 and IA-32
Architectures Optimization Reference Manual.) There is visible
performance improvement on workloads with many PLT calls when executable
and shared libraries are mmapped below 2GB. Add the Prefer_MAP_32BIT_EXEC
bit so that mmap will try to map executable or denywrite pages in shared
libraries with MAP_32BIT first.
NB: Prefer_MAP_32BIT_EXEC reduces bits available for address space
layout randomization (ASLR), which is always disabled for SUID programs
and can only be enabled by the tunable, glibc.cpu.prefer_map_32bit_exec,
or the environment variable, LD_PREFER_MAP_32BIT_EXEC. This works only
between shared libraries or between shared libraries and executables with
addresses below 2GB. PIEs are usually loaded at a random address above
4GB by the kernel.
Conflicts:
manual/tunables.texi
(line numbers)
sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list
(merged local @order list)
sysdeps/x86/cpu-features.c
(line numbers)
---
manual/tunables.texi | 33 ++++++++++----
sysdeps/unix/sysv/linux/x86_64/64/Makefile | 25 +++++++++++
.../sysv/linux/x86_64/64/dl-tunables.list | 29 +++++++++++++
.../unix/sysv/linux/x86_64/64/mmap_internal.h | 43 +++++++++++++++++++
.../sysv/linux/x86_64/64/tst-map-32bit-1a.c | 34 +++++++++++++++
.../sysv/linux/x86_64/64/tst-map-32bit-1b.c | 1 +
.../sysv/linux/x86_64/64/tst-map-32bit-mod.c | 33 ++++++++++++++
sysdeps/x86/cpu-features.c | 15 +++++++
...cpu-features-preferred_feature_index_1.def | 1 +
9 files changed, 205 insertions(+), 9 deletions(-)
create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list
create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h
create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c
create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c
create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 0be7231e36..c76c5c53cd 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -35,27 +35,32 @@ tunables with minimum and maximum values:
@example
$ /lib64/ld-linux-x86-64.so.2 --list-tunables
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
-glibc.elision.skip_lock_after_retries: 3 (min: -2147483648, max: 2147483647)
+glibc.elision.skip_lock_after_retries: 3 (min: 0, max: 2147483647)
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff)
glibc.malloc.perturb: 0 (min: 0, max: 255)
glibc.cpu.x86_shared_cache_size: 0x100000 (min: 0x0, max: 0xffffffffffffffff)
+glibc.pthread.rseq: 1 (min: 0, max: 1)
+glibc.cpu.prefer_map_32bit_exec: 0 (min: 0, max: 1)
glibc.mem.tagging: 0 (min: 0, max: 255)
-glibc.elision.tries: 3 (min: -2147483648, max: 2147483647)
+glibc.elision.tries: 3 (min: 0, max: 2147483647)
glibc.elision.enable: 0 (min: 0, max: 1)
-glibc.cpu.x86_rep_movsb_threshold: 0x1000 (min: 0x100, max: 0xffffffffffffffff)
+glibc.malloc.hugetlb: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.cpu.x86_rep_movsb_threshold: 0x2000 (min: 0x100, max: 0xffffffffffffffff)
glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0xffffffffffffffff)
-glibc.elision.skip_lock_busy: 3 (min: -2147483648, max: 2147483647)
-glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.rtld.dynamic_sort: 2 (min: 1, max: 2)
+glibc.elision.skip_lock_busy: 3 (min: 0, max: 2147483647)
+glibc.malloc.top_pad: 0x20000 (min: 0x0, max: 0xffffffffffffffff)
glibc.cpu.x86_rep_stosb_threshold: 0x800 (min: 0x1, max: 0xffffffffffffffff)
-glibc.cpu.x86_non_temporal_threshold: 0xc0000 (min: 0x4040, max: 0x0fffffffffffffff)
+glibc.cpu.x86_non_temporal_threshold: 0xc0000 (min: 0x4040, max: 0xfffffffffffffff)
glibc.cpu.x86_shstk:
+glibc.pthread.stack_cache_size: 0x2800000 (min: 0x0, max: 0xffffffffffffffff)
glibc.cpu.hwcap_mask: 0x6 (min: 0x0, max: 0xffffffffffffffff)
-glibc.malloc.mmap_max: 0 (min: -2147483648, max: 2147483647)
-glibc.elision.skip_trylock_internal_abort: 3 (min: -2147483648, max: 2147483647)
+glibc.malloc.mmap_max: 0 (min: 0, max: 2147483647)
+glibc.elision.skip_trylock_internal_abort: 3 (min: 0, max: 2147483647)
glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0xffffffffffffffff)
glibc.cpu.x86_ibt:
glibc.cpu.hwcaps:
-glibc.elision.skip_lock_internal_abort: 3 (min: -2147483648, max: 2147483647)
+glibc.elision.skip_lock_internal_abort: 3 (min: 0, max: 2147483647)
glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0xffffffffffffffff)
glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff)
glibc.cpu.x86_data_cache_size: 0x8000 (min: 0x0, max: 0xffffffffffffffff)
@@ -569,6 +574,16 @@ instead.
This tunable is specific to i386 and x86-64.
@end deftp
+@deftp Tunable glibc.cpu.prefer_map_32bit_exec
+When this tunable is set to \code{1}, shared libraries of non-setuid
+programs will be loaded below 2GB with MAP_32BIT.
+
+Note that the @env{LD_PREFER_MAP_32BIT_EXEC} environment is an alias of
+this tunable.
+
+This tunable is specific to 64-bit x86-64.
+@end deftp
+
@node Memory Related Tunables
@section Memory Related Tunables
@cindex memory related tunables
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/Makefile b/sysdeps/unix/sysv/linux/x86_64/64/Makefile
index a7b6dc5a53..8ff4f27786 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/Makefile
+++ b/sysdeps/unix/sysv/linux/x86_64/64/Makefile
@@ -1,2 +1,27 @@
# The default ABI is 64.
default-abi := 64
+
+ifeq ($(subdir),elf)
+ifneq ($(have-tunables),no)
+
+tests-map-32bit = \
+ tst-map-32bit-1a \
+ tst-map-32bit-1b \
+# tests-map-32bit
+tst-map-32bit-1a-no-pie = yes
+tst-map-32bit-1b-no-pie = yes
+tests += $(tests-map-32bit)
+
+modules-map-32bit = \
+ tst-map-32bit-mod \
+# modules-map-32bit
+modules-names += $(modules-map-32bit)
+
+$(objpfx)tst-map-32bit-mod.so: $(libsupport)
+tst-map-32bit-1a-ENV = LD_PREFER_MAP_32BIT_EXEC=1
+$(objpfx)tst-map-32bit-1a: $(objpfx)tst-map-32bit-mod.so
+tst-map-32bit-1b-ENV = GLIBC_TUNABLES=glibc.cpu.prefer_map_32bit_exec=1
+$(objpfx)tst-map-32bit-1b: $(objpfx)tst-map-32bit-mod.so
+
+endif
+endif
diff -rup a/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list
--- a/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list 2024-03-06 17:52:50.968514369 -0500
+++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list 2024-03-06 17:55:48.778264896 -0500
@@ -1,3 +1,33 @@
+# x86-64 specific tunables.
+# 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
+# <https://www.gnu.org/licenses/>.
+
+glibc {
+ cpu {
+ prefer_map_32bit_exec {
+ type: INT_32
+ minval: 0
+ maxval: 1
+ env_alias: LD_PREFER_MAP_32BIT_EXEC
+ security_level: SXID_IGNORE
+ }
+ }
+}
+
# Order of tunables in RHEL 9.1.z.
@order glibc.rtld.nns
@order glibc.elision.skip_lock_after_retries
@@ -35,3 +65,5 @@
@order glibc.malloc.check
@order glibc.gmon.minarcs
@order glibc.gmon.maxarcs
+# Order of tunables in RHEL 9.5.z
+@order glibc.cpu.prefer_map_32bit_exec
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h b/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h
new file mode 100644
index 0000000000..33dec3f805
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h
@@ -0,0 +1,43 @@
+/* Linux mmap system call. x86-64 version.
+ Copyright (C) 2015-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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef MMAP_X86_64_INTERNAL_H
+#define MMAP_X86_64_INTERNAL_H
+
+#include <ldsodefs.h>
+
+/* If the Prefer_MAP_32BIT_EXEC bit is set, try to map executable or
+ denywrite pages with MAP_32BIT first. */
+#define MMAP_PREPARE(addr, len, prot, flags, fd, offset) \
+ if ((addr) == NULL \
+ && (((prot) & PROT_EXEC) != 0 \
+ || ((flags) & MAP_DENYWRITE) != 0) \
+ && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC)) \
+ { \
+ void *ret = (void*) INLINE_SYSCALL_CALL (mmap, (addr), (len), \
+ (prot), \
+ (flags) | MAP_32BIT, \
+ (fd), (offset)); \
+ if (ret != MAP_FAILED) \
+ return ret; \
+ }
+
+#include_next <mmap_internal.h>
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c
new file mode 100644
index 0000000000..abc396589e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c
@@ -0,0 +1,34 @@
+/* Check that LD_PREFER_MAP_32BIT_EXEC works in PDE and shared library.
+ 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <support/check.h>
+
+extern void dso_check_map_32bit (void);
+
+static int
+do_test (void)
+{
+ printf ("do_test: %p\n", do_test);
+ TEST_VERIFY ((uintptr_t) do_test < 0xffffffffUL);
+ dso_check_map_32bit ();
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c
new file mode 100644
index 0000000000..34ab01c773
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c
@@ -0,0 +1 @@
+#include "tst-map-32bit-1a.c"
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c
new file mode 100644
index 0000000000..78d4b6133c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c
@@ -0,0 +1,33 @@
+/* Check that LD_PREFER_MAP_32BIT_EXEC works in shared library.
+ 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <support/check.h>
+
+static void
+dso_do_test (void)
+{
+}
+
+void
+dso_check_map_32bit (void)
+{
+ printf ("dso_do_test: %p\n", dso_do_test);
+ TEST_VERIFY ((uintptr_t) dso_do_test < 0xffffffffUL);
+}
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index a2197ed211..822688e21f 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -27,6 +27,16 @@
extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *)
attribute_hidden;
+# ifdef __LP64__
+static void
+TUNABLE_CALLBACK (set_prefer_map_32bit_exec) (tunable_val_t *valp)
+{
+ if (valp->numval)
+ GLRO(dl_x86_cpu_features).preferred[index_arch_Prefer_MAP_32BIT_EXEC]
+ |= bit_arch_Prefer_MAP_32BIT_EXEC;
+}
+# endif
+
# if CET_ENABLED
extern void TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *)
attribute_hidden;
@@ -949,6 +959,11 @@ no_cpuid:
#if HAVE_TUNABLES
TUNABLE_GET (hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps));
+# ifdef __LP64__
+ TUNABLE_GET (prefer_map_32bit_exec, tunable_val_t *,
+ TUNABLE_CALLBACK (set_prefer_map_32bit_exec));
+# endif
+
bool disable_xsave_features = false;
if (!CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE))
diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
index e45f9cb159..d20c5b3196 100644
--- a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
+++ b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
@@ -26,6 +26,7 @@ BIT (I586)
BIT (I686)
BIT (Slow_SSE4_2)
BIT (AVX_Fast_Unaligned_Load)
+BIT (Prefer_MAP_32BIT_EXEC)
BIT (Prefer_No_VZEROUPPER)
BIT (Prefer_ERMS)
BIT (Prefer_No_AVX512)
--
2.39.3

@ -0,0 +1,29 @@
From 188ecdb7774145050a6e167a277f45f03dac5fe8 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 22 Feb 2023 20:04:26 -0800
Subject: [PATCH] tunables.texi: Change \code{1} to @code{1}
Content-type: text/plain; charset=UTF-8
Update
317f1c0a8a x86-64: Add glibc.cpu.prefer_map_32bit_exec [BZ #28656]
---
manual/tunables.texi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/manual/tunables.texi b/manual/tunables.texi
index c76c5c53cd..70dd2264c5 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -589,7 +589,7 @@ This tunable is specific to i386 and x86-64.
@end deftp
@deftp Tunable glibc.cpu.prefer_map_32bit_exec
-When this tunable is set to \code{1}, shared libraries of non-setuid
+When this tunable is set to @code{1}, shared libraries of non-setuid
programs will be loaded below 2GB with MAP_32BIT.
Note that the @env{LD_PREFER_MAP_32BIT_EXEC} environment is an alias of
--
2.39.3

@ -0,0 +1,317 @@
commit d2123d68275acc0f061e73d5f86ca504e0d5a344
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
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 <adhemerval.zanella@linaro.org>
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);
}

@ -0,0 +1,33 @@
commit c06c8aeb61708249d8eb0b17a676d16771ea640b
Author: Dennis Brendel <dbrendel@redhat.com>
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 <carlos@redhat.com>
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}.

@ -0,0 +1,73 @@
commit 85860ad6eaf4c9739318f6b2a1ff7c2fa6b12ab5
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Aug 15 16:45:40 2022 +0200
malloc: Do not use MAP_NORESERVE to allocate heap segments
Address space for heap segments is reserved in a mmap call with
MAP_ANONYMOUS | MAP_PRIVATE and protection flags PROT_NONE. This
reservation does not count against the RSS limit of the process or
system. Backing memory is allocated using mprotect in alloc_new_heap
and grow_heap, and at this point, the allocator expects the kernel
to provide memory (subject to memory overcommit).
The SIGSEGV that might generate due to MAP_NORESERVE (according to
the mmap manual page) does not seem to occur in practice, it's always
SIGKILL from the OOM killer. Even if there is a way that SIGSEGV
could be generated, it is confusing to applications that this only
happens for secondary heaps, not for large mmap-based allocations,
and not for the main arena.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflicts:
malloc/arena.c
(huge page support was added upstream)
diff --git a/malloc/arena.c b/malloc/arena.c
index 667484630ed0afa5..2852783355d3d869 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -466,8 +466,7 @@ new_heap (size_t size, size_t top_pad)
p2 = MAP_FAILED;
if (aligned_heap_area)
{
- p2 = (char *) MMAP (aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE,
- MAP_NORESERVE);
+ p2 = (char *) MMAP (aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE, 0);
aligned_heap_area = NULL;
if (p2 != MAP_FAILED && ((unsigned long) p2 & (HEAP_MAX_SIZE - 1)))
{
@@ -477,7 +476,7 @@ new_heap (size_t size, size_t top_pad)
}
if (p2 == MAP_FAILED)
{
- p1 = (char *) MMAP (0, HEAP_MAX_SIZE << 1, PROT_NONE, MAP_NORESERVE);
+ p1 = (char *) MMAP (0, HEAP_MAX_SIZE << 1, PROT_NONE, 0);
if (p1 != MAP_FAILED)
{
p2 = (char *) (((unsigned long) p1 + (HEAP_MAX_SIZE - 1))
@@ -493,7 +492,7 @@ new_heap (size_t size, size_t top_pad)
{
/* Try to take the chance that an allocation of only HEAP_MAX_SIZE
is already aligned. */
- p2 = (char *) MMAP (0, HEAP_MAX_SIZE, PROT_NONE, MAP_NORESERVE);
+ p2 = (char *) MMAP (0, HEAP_MAX_SIZE, PROT_NONE, 0);
if (p2 == MAP_FAILED)
return 0;
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 375f50f5db13e234..fe80b8239756a7c9 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1112,10 +1112,6 @@ static mchunkptr mremap_chunk(mchunkptr p, size_t new_size);
# define MAP_ANONYMOUS MAP_ANON
#endif
-#ifndef MAP_NORESERVE
-# define MAP_NORESERVE 0
-#endif
-
#define MMAP(addr, size, prot, flags) \
__mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)

@ -0,0 +1,229 @@
commit f21962ddfc8bb23e92597da1f98e313dbde11cc1
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 25 14:15:28 2023 +0200
manual: Document ld.so --list-diagnostics output
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/manual/dynlink.texi b/manual/dynlink.texi
index 45bf5a5b55..df41c56bfc 100644
--- a/manual/dynlink.texi
+++ b/manual/dynlink.texi
@@ -13,9 +13,216 @@ as plugins) later at run time.
Dynamic linkers are sometimes called @dfn{dynamic loaders}.
@menu
+* Dynamic Linker Invocation:: Explicit invocation of the dynamic linker.
* Dynamic Linker Introspection:: Interfaces for querying mapping information.
@end menu
+@node Dynamic Linker Invocation
+
+@cindex program interpreter
+When a dynamically linked program starts, the operating system
+automatically loads the dynamic linker along with the program.
+@Theglibc{} also supports invoking the dynamic linker explicitly to
+launch a program. This command uses the implied dynamic linker
+(also sometimes called the @dfn{program interpreter}):
+
+@smallexample
+sh -c 'echo "Hello, world!"'
+@end smallexample
+
+This command specifies the dynamic linker explicitly:
+
+@smallexample
+ld.so /bin/sh -c 'echo "Hello, world!"'
+@end smallexample
+
+Note that @command{ld.so} does not search the @env{PATH} environment
+variable, so the full file name of the executable needs to be specified.
+
+The @command{ld.so} program supports various options. Options start
+@samp{--} and need to come before the program that is being launched.
+Some of the supported options are listed below.
+
+@table @code
+@item --list-diagnostics
+Print system diagnostic information in a machine-readable format.
+@xref{Dynamic Linker Diagnostics}.
+@end table
+
+@menu
+* Dynamic Linker Diagnostics:: Obtaining system diagnostic information.
+@end menu
+
+@node Dynamic Linker Diagnostics
+@section Dynamic Linker Diagnostics
+@cindex diagnostics (dynamic linker)
+
+The @samp{ld.so --list-diagnostics} produces machine-readable
+diagnostics output. This output contains system data that affects the
+behavior of @theglibc{}, and potentially application behavior as well.
+
+The exact set of diagnostic items can change between releases of
+@theglibc{}. The output format itself is not expected to change
+radically.
+
+The following table shows some example lines that can be written by the
+diagnostics command.
+
+@table @code
+@item dl_pagesize=0x1000
+The system page size is 4096 bytes.
+
+@item env[0x14]="LANG=en_US.UTF-8"
+This item indicates that the 21st environment variable at process
+startup contains a setting for @code{LANG}.
+
+@item env_filtered[0x22]="DISPLAY"
+The 35th environment variable is @code{DISPLAY}. Its value is not
+included in the output for privacy reasons because it is not recognized
+as harmless by the diagnostics code.
+
+@item path.prefix="/usr"
+This means that @theglibc{} was configured with @code{--prefix=/usr}.
+
+@item path.system_dirs[0x0]="/lib64/"
+@itemx path.system_dirs[0x1]="/usr/lib64/"
+The built-in dynamic linker search path contains two directories,
+@code{/lib64} and @code{/usr/lib64}.
+@end table
+
+@subsection Dynamic Linker Diagnostics Output Format
+
+As seen above, diagnostic lines assign values (integers or strings) to a
+sequence of labeled subscripts, separated by @samp{.}. Some subscripts
+have integer indices associated with them. The subscript indices are
+not necessarily contiguous or small, so an associative array should be
+used to store them. Currently, all integers fit into the 64-bit
+unsigned integer range. Every access path to a value has a fixed type
+(string or integer) independent of subscript index values. Likewise,
+whether a subscript is indexed does not depend on previous indices (but
+may depend on previous subscript labels).
+
+A syntax description in ABNF (RFC 5234) follows. Note that
+@code{%x30-39} denotes the range of decimal digits. Diagnostic output
+lines are expected to match the @code{line} production.
+
+@c ABNF-START
+@smallexample
+HEXDIG = %x30-39 / %x61-6f ; lowercase a-f only
+ALPHA = %x41-5a / %x61-7a / %x7f ; letters and underscore
+ALPHA-NUMERIC = ALPHA / %x30-39 / "_"
+DQUOTE = %x22 ; "
+
+; Numbers are always hexadecimal and use a 0x prefix.
+hex-value-prefix = %x30 %x78
+hex-value = hex-value-prefix 1*HEXDIG
+
+; Strings use octal escape sequences and \\, \".
+string-char = %x20-21 / %x23-5c / %x5d-7e ; printable but not "\
+string-quoted-octal = %x30-33 2*2%x30-37
+string-quoted = "\" ("\" / DQUOTE / string-quoted-octal)
+string-value = DQUOTE *(string-char / string-quoted) DQUOTE
+
+value = hex-value / string-value
+
+label = ALPHA *ALPHA-NUMERIC
+index = "[" hex-value "]"
+subscript = label [index]
+
+line = subscript *("." subscript) "=" value
+@end smallexample
+
+@subsection Dynamic Linker Diagnostics Values
+
+As mentioned above, the set of diagnostics may change between
+@theglibc{} releases. Nevertheless, the following table documents a few
+common diagnostic items. All numbers are in hexadecimal, with a
+@samp{0x} prefix.
+
+@table @code
+@item dl_dst_lib=@var{string}
+The @code{$LIB} dynamic string token expands to @var{string}.
+
+@cindex HWCAP (diagnostics)
+@item dl_hwcap=@var{integer}
+@itemx dl_hwcap2=@var{integer}
+The HWCAP and HWCAP2 values, as returned for @code{getauxval}, and as
+used in other places depending on the architecture.
+
+@cindex page size (diagnostics)
+@item dl_pagesize=@var{integer}
+The system page size is @var{integer} bytes.
+
+@item dl_platform=@var{string}
+The @code{$PLATFORM} dynamic string token expands to @var{string}.
+
+@item dso.libc=@var{string}
+This is the soname of the shared @code{libc} object that is part of
+@theglibc{}. On most architectures, this is @code{libc.so.6}.
+
+@item env[@var{index}]=@var{string}
+@itemx env_filtered[@var{index}]=@var{string}
+An environment variable from the process environment. The integer
+@var{index} is the array index in the environment array. Variables
+under @code{env} include the variable value after the @samp{=} (assuming
+that it was present), variables under @code{env_filtered} do not.
+
+@item path.prefix=@var{string}
+This indicates that @theglibc{} was configured using
+@samp{--prefix=@var{string}}.
+
+@item path.sysconfdir=@var{string}
+@Theglibc{} was configured (perhaps implicitly) with
+@samp{--sysconfdir=@var{string}} (typically @code{/etc}).
+
+@item path.system_dirs[@var{index}]=@var{string}
+These items list the elements of the built-in array that describes the
+default library search path. The value @var{string} is a directory file
+name with a trailing @samp{/}.
+
+@item path.rtld=@var{string}
+This string indicates the application binary interface (ABI) file name
+of the run-time dynamic linker.
+
+@item version.release="stable"
+@itemx version.release="development"
+The value @code{"stable"} indicates that this build of @theglibc{} is
+from a release branch. Releases labeled as @code{"development"} are
+unreleased development versions.
+
+@cindex version (diagnostics)
+@item version.version="@var{major}.@var{minor}"
+@itemx version.version="@var{major}.@var{minor}.9000"
+@Theglibc{} version. Development releases end in @samp{.9000}.
+
+@cindex auxiliary vector (diagnostics)
+@item auxv[@var{index}].a_type=@var{type}
+@itemx auxv[@var{index}].a_val=@var{integer}
+@itemx auxv[@var{index}].a_val_string=@var{string}
+An entry in the auxiliary vector (specific to Linux). The values
+@var{type} (an integer) and @var{integer} correspond to the members of
+@code{struct auxv}. If the value is a string, @code{a_val_string} is
+used instead of @code{a_val}, so that values have consistent types.
+
+The @code{AT_HWCAP} and @code{AT_HWCAP2} values in this output do not
+reflect adjustment by @theglibc{}.
+
+@item uname.sysname=@var{string}
+@itemx uname.nodename=@var{string}
+@itemx uname.release=@var{string}
+@itemx uname.version=@var{string}
+@itemx uname.machine=@var{string}
+@itemx uname.domain=@var{string}
+These Linux-specific items show the values of @code{struct utsname}, as
+reported by the @code{uname} function. @xref{Platform Type}.
+
+@cindex CPUID (diagnostics)
+@item x86.cpu_features.@dots{}
+These items are specific to the i386 and x86-64 architectures. They
+reflect supported CPU features and information on cache geometry, mostly
+collected using the @code{CPUID} instruction.
+@end table
+
@node Dynamic Linker Introspection
@section Dynamic Linker Introspection

@ -0,0 +1,74 @@
commit d99609a3eb8bc96c3af841fd35294a679e0fea7f
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Sep 6 18:37:21 2023 +0200
manual: Fix ld.so diagnostics menu/section structure
And shorten the section/node names a bit, so that the menu
entries become easier to read.
Texinfo 6.5 fails to process the previous structure:
./dynlink.texi:56: warning: node `Dynamic Linker Introspection' is
next for `Dynamic Linker Diagnostics' in sectioning but not in menu
./dynlink.texi:56: warning: node up `Dynamic Linker Diagnostics'
in menu `Dynamic Linker Invocation' and
in sectioning `Dynamic Linker' differ
./dynlink.texi:1: node `Dynamic Linker' lacks menu item for
`Dynamic Linker Diagnostics' despite being its Up target
./dynlink.texi:226: warning: node prev `Dynamic Linker Introspection' in menu `Dynamic Linker Invocation'
and in sectioning `Dynamic Linker Diagnostics' differ
Texinfo 7.0.2 does not report an error.
This fixes commit f21962ddfc8bb23e92597da1f98e313dbde11cc1
("manual: Document ld.so --list-diagnostics output").
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
diff --git a/manual/dynlink.texi b/manual/dynlink.texi
index df41c56bfc..06a6c15533 100644
--- a/manual/dynlink.texi
+++ b/manual/dynlink.texi
@@ -18,6 +18,7 @@ Dynamic linkers are sometimes called @dfn{dynamic loaders}.
@end menu
@node Dynamic Linker Invocation
+@section Dynamic Linker Invocation
@cindex program interpreter
When a dynamically linked program starts, the operating system
@@ -54,7 +55,7 @@ Print system diagnostic information in a machine-readable format.
@end menu
@node Dynamic Linker Diagnostics
-@section Dynamic Linker Diagnostics
+@subsection Dynamic Linker Diagnostics
@cindex diagnostics (dynamic linker)
The @samp{ld.so --list-diagnostics} produces machine-readable
@@ -90,7 +91,13 @@ The built-in dynamic linker search path contains two directories,
@code{/lib64} and @code{/usr/lib64}.
@end table
-@subsection Dynamic Linker Diagnostics Output Format
+@menu
+* Dynamic Linker Diagnostics Format:: Format of ld.so output.
+* Dynamic Linker Diagnostics Values:: Data contain in ld.so output.
+@end menu
+
+@node Dynamic Linker Diagnostics Format
+@subsubsection Dynamic Linker Diagnostics Format
As seen above, diagnostic lines assign values (integers or strings) to a
sequence of labeled subscripts, separated by @samp{.}. Some subscripts
@@ -132,7 +139,8 @@ subscript = label [index]
line = subscript *("." subscript) "=" value
@end smallexample
-@subsection Dynamic Linker Diagnostics Values
+@node Dynamic Linker Diagnostics Values
+@subsubsection Dynamic Linker Diagnostics Values
As mentioned above, the set of diagnostics may change between
@theglibc{} releases. Nevertheless, the following table documents a few

@ -0,0 +1,144 @@
commit f8d8b1b1e6d3b8b93f224efc796b7ea083fdb83f
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Apr 8 16:48:55 2024 +0200
aarch64: Enhanced CPU diagnostics for ld.so
This prints some information from struct cpu_features, and the midr_el1
and dczid_el0 system register contents on every CPU.
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
Modified for RHEL by: Patsy Griffin <patsy@redhat.com>
Diagnostics for the cpu_features mops and prefer_sve_ifuncs are not
currently supported on aarch64.
diff -Nrup a/manual/dynlink.texi b/manual/dynlink.texi
--- a/manual/dynlink.texi 2024-05-31 20:55:08.238959456 -0400
+++ b/manual/dynlink.texi 2024-05-31 20:55:41.298121623 -0400
@@ -224,6 +224,40 @@ reflect adjustment by @theglibc{}.
These Linux-specific items show the values of @code{struct utsname}, as
reported by the @code{uname} function. @xref{Platform Type}.
+@item aarch64.cpu_features.@dots{}
+These items are specific to the AArch64 architectures. They report data
+@theglibc{} uses to activate conditionally supported features such as
+BTI and MTE, and to select alternative function implementations.
+
+@item aarch64.processor[@var{index}].@dots{}
+These are additional items for the AArch64 architecture and are
+described below.
+
+@item aarch64.processor[@var{index}].requested=@var{kernel-cpu}
+The kernel is told to run the subsequent probing on the CPU numbered
+@var{kernel-cpu}. The values @var{kernel-cpu} and @var{index} can be
+distinct if there are gaps in the process CPU affinity mask. This line
+is not included if CPU affinity mask information is not available.
+
+@item aarch64.processor[@var{index}].observed=@var{kernel-cpu}
+This line reports the kernel CPU number @var{kernel-cpu} on which the
+probing code initially ran. If the CPU number cannot be obtained,
+this line is not printed.
+
+@item aarch64.processor[@var{index}].observed_node=@var{node}
+This reports the observed NUMA node number, as reported by the
+@code{getcpu} system call. If this information cannot be obtained, this
+line is not printed.
+
+@item aarch64.processor[@var{index}].midr_el1=@var{value}
+The value of the @code{midr_el1} system register on the processor
+@var{index}. This line is only printed if the kernel indicates that
+this system register is supported.
+
+@item aarch64.processor[@var{index}].dczid_el0=@var{value}
+The value of the @code{dczid_el0} system register on the processor
+@var{index}.
+
@cindex CPUID (diagnostics)
@item x86.cpu_features.@dots{}
These items are specific to the i386 and x86-64 architectures. They
diff -Nrup a/sysdeps/aarch64/dl-diagnostics-cpu.c b/sysdeps/aarch64/dl-diagnostics-cpu.c
--- a/sysdeps/aarch64/dl-diagnostics-cpu.c 1969-12-31 19:00:00.000000000 -0500
+++ b/sysdeps/aarch64/dl-diagnostics-cpu.c 2024-05-31 20:57:23.536623129 -0400
@@ -0,0 +1,81 @@
+/* Print CPU diagnostics data in ld.so. AArch64 version.
+ Copyright (C) 2021-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dl-diagnostics.h>
+
+#include <cpu-features.h>
+#include <dl-iterate_cpu.h>
+#include <ldsodefs.h>
+#include <sys/auxv.h>
+
+static void
+print_cpu_features_value (const char *label, uint64_t value)
+{
+ _dl_printf ("aarch64.cpu_features.");
+ _dl_diagnostics_print_labeled_value (label, value);
+}
+
+static void
+print_per_cpu_value (const struct dl_iterate_cpu *dic,
+ const char *label, uint64_t value)
+{
+ _dl_printf ("aarch64.processor[0x%x].", dic->processor_index);
+ _dl_diagnostics_print_labeled_value (label, value);
+}
+
+void
+_dl_diagnostics_cpu (void)
+{
+ print_cpu_features_value ("bti", GLRO (dl_aarch64_cpu_features).bti);
+ print_cpu_features_value ("midr_el1",
+ GLRO (dl_aarch64_cpu_features).midr_el1);
+ print_cpu_features_value ("mte_state",
+ GLRO (dl_aarch64_cpu_features).mte_state);
+ print_cpu_features_value ("sve", GLRO (dl_aarch64_cpu_features).sve);
+ print_cpu_features_value ("zva_size",
+ GLRO (dl_aarch64_cpu_features).zva_size);
+
+ struct dl_iterate_cpu dic;
+ _dl_iterate_cpu_init (&dic);
+
+ while (_dl_iterate_cpu_next (&dic))
+ {
+ if (dic.requested_cpu >= 0)
+ _dl_printf ("aarch64.processor[0x%x].requested=0x%x\n",
+ dic.processor_index, dic.requested_cpu);
+ if (dic.actual_cpu >= 0)
+ _dl_printf ("aarch64.processor[0x%x].observed=0x%x\n",
+ dic.processor_index, dic.actual_cpu);
+ if (dic.actual_node >= 0)
+ _dl_printf ("aarch64.processor[0x%x].observed_node=0x%x\n",
+ dic.processor_index, dic.actual_node);
+
+ if (GLRO (dl_hwcap) & HWCAP_CPUID)
+ {
+ uint64_t midr_el1;
+ asm ("mrs %0, midr_el1" : "=r" (midr_el1));
+ print_per_cpu_value (&dic, "midr_el1", midr_el1);
+ }
+
+ {
+ uint64_t dczid_el0;
+ asm ("mrs %0, dczid_el0" : "=r" (dczid_el0));
+ print_per_cpu_value (&dic, "dczid_el0", dczid_el0);
+ }
+ }
+}

@ -0,0 +1,510 @@
commit 7a430f40c46acfa7ce4c3bff193b278c190b2efc
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Apr 8 16:48:55 2024 +0200
x86: Add generic CPUID data dumper to ld.so --list-diagnostics
This is surprisingly difficult to implement if the goal is to produce
reasonably sized output. With the current approaches to output
compression (suppressing zeros and repeated results between CPUs,
folding ranges of identical subleaves, dealing with the %ecx
reflection issue), the output is less than 600 KiB even for systems
with 256 logical CPUs.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
diff -Nrup a/manual/dynlink.texi b/manual/dynlink.texi
--- a/manual/dynlink.texi 2024-06-03 08:42:17.011026573 -0400
+++ b/manual/dynlink.texi 2024-06-03 08:55:18.607771972 -0400
@@ -262,7 +262,90 @@ The value of the @code{dczid_el0} system
@item x86.cpu_features.@dots{}
These items are specific to the i386 and x86-64 architectures. They
reflect supported CPU features and information on cache geometry, mostly
-collected using the @code{CPUID} instruction.
+collected using the CPUID instruction.
+
+@item x86.processor[@var{index}].@dots{}
+These are additional items for the i386 and x86-64 architectures, as
+described below. They mostly contain raw data from the CPUID
+instruction. The probes are performed for each active CPU for the
+@code{ld.so} process, and data for different probed CPUs receives a
+uniqe @var{index} value. Some CPUID data is expected to differ from CPU
+core to CPU core. In some cases, CPUs are not correctly initialized and
+indicate the presence of different feature sets.
+
+@item x86.processor[@var{index}].requested=@var{kernel-cpu}
+The kernel is told to run the subsequent probing on the CPU numbered
+@var{kernel-cpu}. The values @var{kernel-cpu} and @var{index} can be
+distinct if there are gaps in the process CPU affinity mask. This line
+is not included if CPU affinity mask information is not available.
+
+@item x86.processor[@var{index}].observed=@var{kernel-cpu}
+This line reports the kernel CPU number @var{kernel-cpu} on which the
+probing code initially ran. If the CPU number cannot be obtained,
+this line is not printed.
+
+@item x86.processor[@var{index}].observed_node=@var{node}
+This reports the observed NUMA node number, as reported by the
+@code{getcpu} system call. If this information cannot be obtained, this
+line is not printed.
+
+@item x86.processor[@var{index}].cpuid_leaves=@var{count}
+This line indicates that @var{count} distinct CPUID leaves were
+encountered. (This reflects internal @code{ld.so} storage space, it
+does not directly correspond to @code{CPUID} enumeration ranges.)
+
+@item x86.processor[@var{index}].ecx_limit=@var{value}
+The CPUID data extraction code uses a brute-force approach to enumerate
+subleaves (see the @samp{.subleaf_eax} lines below). The last
+@code{%rcx} value used in a CPUID query on this probed CPU was
+@var{value}.
+
+@item x86.processor[@var{index}].cpuid.eax[@var{query_eax}].eax=@var{eax}
+@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].ebx=@var{ebx}
+@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].ecx=@var{ecx}
+@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].edx=@var{edx}
+These lines report the register contents after executing the CPUID
+instruction with @samp{%rax == @var{query_eax}} and @samp{%rcx == 0} (a
+@dfn{leaf}). For the first probed CPU (with a zero @var{index}), only
+leaves with non-zero register contents are reported. For subsequent
+CPUs, only leaves whose register contents differs from the previously
+probed CPUs (with @var{index} one less) are reported.
+
+Basic and extended leaves are reported using the same syntax. This
+means there is a large jump in @var{query_eax} for the first reported
+extended leaf.
+
+@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].eax=@var{eax}
+@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ebx=@var{ebx}
+@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ecx=@var{ecx}
+@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].edx=@var{edx}
+This is similar to the leaves above, but for a @dfn{subleaf}. For
+subleaves, the CPUID instruction is executed with @samp{%rax ==
+@var{query_eax}} and @samp{%rcx == @var{query_ecx}}, so the result
+depends on both register values. The same rules about filtering zero
+and identical results apply.
+
+@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].until_ecx=@var{ecx_limit}
+Some CPUID results are the same regardless the @var{query_ecx} value.
+If this situation is detected, a line with the @samp{.until_ecx}
+selector ins included, and this indicates that the CPUID register
+contents is the same for @code{%rcx} values between @var{query_ecx}
+and @var{ecx_limit} (inclusive).
+
+@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ecx_query_mask=0xff
+This line indicates that in an @samp{.until_ecx} range, the CPUID
+instruction preserved the lowested 8 bits of the input @code{%rcx} in
+the output @code{%rcx} registers. Otherwise, the subleaves in the range
+have identical values. This special treatment is necessary to report
+compact range information in case such copying occurs (because the
+subleaves would otherwise be all different).
+
+@item x86.processor[@var{index}].xgetbv.ecx[@var{query_ecx}]=@var{result}
+This line shows the 64-bit @var{result} value in the @code{%rdx:%rax}
+register pair after executing the XGETBV instruction with @code{%rcx}
+set to @var{query_ecx}. Zero values and values matching the previously
+probed CPU are omitted. Nothing is printed if the system does not
+support the XGETBV instruction.
@end table
@node Dynamic Linker Introspection
diff -Nrup a/sysdeps/x86/dl-diagnostics-cpu.c b/sysdeps/x86/dl-diagnostics-cpu.c
--- a/sysdeps/x86/dl-diagnostics-cpu.c 2024-06-03 08:42:16.825025689 -0400
+++ b/sysdeps/x86/dl-diagnostics-cpu.c 2024-06-03 09:49:47.528510916 -0400
@@ -17,7 +17,18 @@
<https://www.gnu.org/licenses/>. */
#include <dl-diagnostics.h>
+
+#include <array_length.h>
+#include <cpu-features.h>
+#include <cpuid.h>
+#include <dl-iterate_cpu.h>
#include <ldsodefs.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sysdep.h>
+
+/* The generic CPUID dumping code. */
+static void _dl_diagnostics_cpuid (void);
static void
print_cpu_features_value (const char *label, uint64_t value)
@@ -119,4 +130,377 @@ _dl_diagnostics_cpu (void)
"last cpu_features field has been printed");
print_cpu_features_value ("cachesize_non_temporal_divisor",
__rtld_global_ro_cachesize_non_temporal_divisor);
+
+ _dl_diagnostics_cpuid ();
+}
+
+/* The following code implements a generic CPUID dumper that tries to
+ gather CPUID data without knowing about CPUID implementation
+ details. */
+
+/* Register arguments to CPUID. Multiple ECX subleaf values yielding
+ the same result are combined, to shorten the output. Both
+ identical matches (EAX to EDX are the same) and matches where EAX,
+ EBX, EDX, and ECX are equal except in the lower byte, which must
+ match the query ECX value. The latter is needed to compress ranges
+ on CPUs which preserve the lowest byte in ECX if an unknown leaf is
+ queried. */
+struct cpuid_query
+{
+ unsigned int eax;
+ unsigned ecx_first;
+ unsigned ecx_last;
+ bool ecx_preserves_query_byte;
+};
+
+/* Single integer value that can be used for sorting/ordering
+ comparisons. Uses Q->eax and Q->ecx_first only because ecx_last is
+ always greater than the previous ecx_first value and less than the
+ subsequent one. */
+static inline unsigned long long int
+cpuid_query_combined (struct cpuid_query *q)
+{
+ /* ecx can be -1 (that is, ~0U). If this happens, this the only ecx
+ value for this eax value, so the ordering does not matter. */
+ return ((unsigned long long int) q->eax << 32) | (unsigned int) q->ecx_first;
+};
+
+/* Used for differential reporting of zero/non-zero values. */
+static const struct cpuid_registers cpuid_registers_zero;
+
+/* Register arguments to CPUID paired with the results that came back. */
+struct cpuid_query_result
+{
+ struct cpuid_query q;
+ struct cpuid_registers r;
+};
+
+/* During a first enumeration pass, we try to collect data for
+ cpuid_initial_subleaf_limit subleaves per leaf/EAX value. If we run
+ out of space, we try once more with applying the lower limit. */
+enum { cpuid_main_leaf_limit = 128 };
+enum { cpuid_initial_subleaf_limit = 512 };
+enum { cpuid_subleaf_limit = 32 };
+
+/* Offset of the extended leaf area. */
+enum {cpuid_extended_leaf_offset = 0x80000000 };
+
+/* Collected CPUID data. Everything is stored in a statically sized
+ array that is sized so that the second pass will collect some data
+ for all leaves, after the limit is applied. On the second pass,
+ ecx_limit is set to cpuid_subleaf_limit. */
+struct cpuid_collected_data
+{
+ unsigned int used;
+ unsigned int ecx_limit;
+ uint64_t xgetbv_ecx_0;
+ struct cpuid_query_result qr[cpuid_main_leaf_limit
+ * 2 * cpuid_subleaf_limit];
+};
+
+/* Fill in the result of a CPUID query. Returns true if there is
+ room, false if nothing could be stored. */
+static bool
+_dl_diagnostics_cpuid_store (struct cpuid_collected_data *ccd,
+ unsigned eax, int ecx)
+{
+ if (ccd->used >= array_length (ccd->qr))
+ return false;
+
+ /* Tentatively fill in the next value. */
+ __cpuid_count (eax, ecx,
+ ccd->qr[ccd->used].r.eax,
+ ccd->qr[ccd->used].r.ebx,
+ ccd->qr[ccd->used].r.ecx,
+ ccd->qr[ccd->used].r.edx);
+
+ /* If the ECX subleaf is next subleaf after the previous one (for
+ the same leaf), and the values are the same, merge the result
+ with the already-stored one. Do this before skipping zero
+ leaves, which avoids artifiacts for ECX == 256 queries. */
+ if (ccd->used > 0
+ && ccd->qr[ccd->used - 1].q.eax == eax
+ && ccd->qr[ccd->used - 1].q.ecx_last + 1 == ecx)
+ {
+ /* Exact match of the previous result. Ignore the value of
+ ecx_preserves_query_byte if this is a singleton range so far
+ because we can treat ECX as fixed if the same value repeats. */
+ if ((!ccd->qr[ccd->used - 1].q.ecx_preserves_query_byte
+ || (ccd->qr[ccd->used - 1].q.ecx_first
+ == ccd->qr[ccd->used - 1].q.ecx_last))
+ && memcmp (&ccd->qr[ccd->used - 1].r, &ccd->qr[ccd->used].r,
+ sizeof (ccd->qr[ccd->used].r)) == 0)
+ {
+ ccd->qr[ccd->used - 1].q.ecx_last = ecx;
+ /* ECX is now fixed because the same value has been observed
+ twice, even if we had a low-byte match before. */
+ ccd->qr[ccd->used - 1].q.ecx_preserves_query_byte = false;
+ return true;
+ }
+ /* Match except for the low byte in ECX, which must match the
+ incoming ECX value. */
+ if (ccd->qr[ccd->used - 1].q.ecx_preserves_query_byte
+ && (ecx & 0xff) == (ccd->qr[ccd->used].r.ecx & 0xff)
+ && ccd->qr[ccd->used].r.eax == ccd->qr[ccd->used - 1].r.eax
+ && ccd->qr[ccd->used].r.ebx == ccd->qr[ccd->used - 1].r.ebx
+ && ((ccd->qr[ccd->used].r.ecx & 0xffffff00)
+ == (ccd->qr[ccd->used - 1].r.ecx & 0xffffff00))
+ && ccd->qr[ccd->used].r.edx == ccd->qr[ccd->used - 1].r.edx)
+ {
+ ccd->qr[ccd->used - 1].q.ecx_last = ecx;
+ return true;
+ }
+ }
+
+ /* Do not store zero results. All-zero values usually mean that the
+ subleaf is unsupported. */
+ if (ccd->qr[ccd->used].r.eax == 0
+ && ccd->qr[ccd->used].r.ebx == 0
+ && ccd->qr[ccd->used].r.ecx == 0
+ && ccd->qr[ccd->used].r.edx == 0)
+ return true;
+
+ /* The result needs to be stored. Fill in the query parameters and
+ consume the storage. */
+ ccd->qr[ccd->used].q.eax = eax;
+ ccd->qr[ccd->used].q.ecx_first = ecx;
+ ccd->qr[ccd->used].q.ecx_last = ecx;
+ ccd->qr[ccd->used].q.ecx_preserves_query_byte
+ = (ecx & 0xff) == (ccd->qr[ccd->used].r.ecx & 0xff);
+ ++ccd->used;
+ return true;
+}
+
+/* Collected CPUID data into *CCD. If LIMIT, apply per-leaf limits to
+ avoid exceeding the pre-allocated space. Return true if all data
+ could be stored, false if the retrying without a limit is
+ requested. */
+static bool
+_dl_diagnostics_cpuid_collect_1 (struct cpuid_collected_data *ccd, bool limit)
+{
+ ccd->used = 0;
+ ccd->ecx_limit
+ = (limit ? cpuid_subleaf_limit : cpuid_initial_subleaf_limit) - 1;
+ _dl_diagnostics_cpuid_store (ccd, 0x00, 0x00);
+ if (ccd->used == 0)
+ /* CPUID reported all 0. Should not happen. */
+ return true;
+ unsigned int maximum_leaf = ccd->qr[0x00].r.eax;
+ if (limit && maximum_leaf >= cpuid_main_leaf_limit)
+ maximum_leaf = cpuid_main_leaf_limit - 1;
+
+ for (unsigned int eax = 1; eax <= maximum_leaf; ++eax)
+ {
+ for (unsigned int ecx = 0; ecx <= ccd->ecx_limit; ++ecx)
+ if (!_dl_diagnostics_cpuid_store (ccd, eax, ecx))
+ return false;
+ }
+
+ if (!_dl_diagnostics_cpuid_store (ccd, cpuid_extended_leaf_offset, 0x00))
+ return false;
+ maximum_leaf = ccd->qr[ccd->used - 1].r.eax;
+ if (maximum_leaf < cpuid_extended_leaf_offset)
+ /* No extended CPUID information. */
+ return true;
+ if (limit
+ && maximum_leaf - cpuid_extended_leaf_offset >= cpuid_main_leaf_limit)
+ maximum_leaf = cpuid_extended_leaf_offset + cpuid_main_leaf_limit - 1;
+ for (unsigned int eax = cpuid_extended_leaf_offset + 1;
+ eax <= maximum_leaf; ++eax)
+ {
+ for (unsigned int ecx = 0; ecx <= ccd->ecx_limit; ++ecx)
+ if (!_dl_diagnostics_cpuid_store (ccd, eax, ecx))
+ return false;
+ }
+ return true;
+}
+
+/* Call _dl_diagnostics_cpuid_collect_1 twice if necessary, the
+ second time with the limit applied. */
+static void
+_dl_diagnostics_cpuid_collect (struct cpuid_collected_data *ccd)
+{
+ if (!_dl_diagnostics_cpuid_collect_1 (ccd, false))
+ _dl_diagnostics_cpuid_collect_1 (ccd, true);
+
+ /* Re-use the result of the official feature probing here. */
+ const struct cpu_features *cpu_features = __get_cpu_features ();
+ if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE))
+ {
+ unsigned int xcrlow;
+ unsigned int xcrhigh;
+ asm ("xgetbv" : "=a" (xcrlow), "=d" (xcrhigh) : "c" (0));
+ ccd->xgetbv_ecx_0 = ((uint64_t) xcrhigh << 32) + xcrlow;
+ }
+ else
+ ccd->xgetbv_ecx_0 = 0;
+}
+
+/* Print a CPUID register value (passed as REG_VALUE) if it differs
+ from the expected REG_REFERENCE value. PROCESSOR_INDEX is the
+ process sequence number (always starting at zero; not a kernel ID). */
+static void
+_dl_diagnostics_cpuid_print_reg (unsigned int processor_index,
+ const struct cpuid_query *q,
+ const char *reg_label, unsigned int reg_value,
+ bool subleaf)
+{
+ if (subleaf)
+ _dl_printf ("x86.processor[0x%x].cpuid.subleaf_eax[0x%x]"
+ ".ecx[0x%x].%s=0x%x\n",
+ processor_index, q->eax, q->ecx_first, reg_label, reg_value);
+ else
+ _dl_printf ("x86.processor[0x%x].cpuid.eax[0x%x].%s=0x%x\n",
+ processor_index, q->eax, reg_label, reg_value);
+}
+
+/* Print CPUID result values in *RESULT for the query in
+ CCD->qr[CCD_IDX]. PROCESSOR_INDEX is the process sequence number
+ (always starting at zero; not a kernel ID). */
+static void
+_dl_diagnostics_cpuid_print_query (unsigned int processor_index,
+ struct cpuid_collected_data *ccd,
+ unsigned int ccd_idx,
+ const struct cpuid_registers *result)
+{
+ /* Treat this as a value if subleaves if ecx isn't zero (maybe
+ within the [ecx_fist, ecx_last] range), or if eax matches its
+ neighbors. If the range is [0, ecx_limit], then the subleaves
+ are not distinct (independently of ecx_preserves_query_byte),
+ so do not report them separately. */
+ struct cpuid_query *q = &ccd->qr[ccd_idx].q;
+ bool subleaf = (q->ecx_first > 0
+ || (q->ecx_first != q->ecx_last
+ && !(q->ecx_first == 0 && q->ecx_last == ccd->ecx_limit))
+ || (ccd_idx > 0 && q->eax == ccd->qr[ccd_idx - 1].q.eax)
+ || (ccd_idx + 1 < ccd->used
+ && q->eax == ccd->qr[ccd_idx + 1].q.eax));
+ _dl_diagnostics_cpuid_print_reg (processor_index, q, "eax", result->eax,
+ subleaf);
+ _dl_diagnostics_cpuid_print_reg (processor_index, q, "ebx", result->ebx,
+ subleaf);
+ _dl_diagnostics_cpuid_print_reg (processor_index, q, "ecx", result->ecx,
+ subleaf);
+ _dl_diagnostics_cpuid_print_reg (processor_index, q, "edx", result->edx,
+ subleaf);
+
+ if (subleaf && q->ecx_first != q->ecx_last)
+ {
+ _dl_printf ("x86.processor[0x%x].cpuid.subleaf_eax[0x%x]"
+ ".ecx[0x%x].until_ecx=0x%x\n",
+ processor_index, q->eax, q->ecx_first, q->ecx_last);
+ if (q->ecx_preserves_query_byte)
+ _dl_printf ("x86.processor[0x%x].cpuid.subleaf_eax[0x%x]"
+ ".ecx[0x%x].ecx_query_mask=0xff\n",
+ processor_index, q->eax, q->ecx_first);
+ }
+}
+
+/* Perform differential reporting of the data in *CURRENT against
+ *BASE. REQUESTED_CPU is the kernel CPU ID the thread was
+ configured to run on, or -1 if no configuration was possible.
+ PROCESSOR_INDEX is the process sequence number (always starting at
+ zero; not a kernel ID). */
+static void
+_dl_diagnostics_cpuid_report (struct dl_iterate_cpu *dci,
+ struct cpuid_collected_data *current,
+ struct cpuid_collected_data *base)
+{
+ if (dci->requested_cpu >= 0)
+ _dl_printf ("x86.processor[0x%x].requested=0x%x\n",
+ dci->processor_index, dci->requested_cpu);
+ if (dci->actual_cpu >= 0)
+ _dl_printf ("x86.processor[0x%x].observed=0x%x\n",
+ dci->processor_index, dci->actual_cpu);
+ if (dci->actual_node >= 0)
+ _dl_printf ("x86.processor[0x%x].observed_node=0x%x\n",
+ dci->processor_index, dci->actual_node);
+
+ _dl_printf ("x86.processor[0x%x].cpuid_leaves=0x%x\n",
+ dci->processor_index, current->used);
+ _dl_printf ("x86.processor[0x%x].ecx_limit=0x%x\n",
+ dci->processor_index, current->ecx_limit);
+
+ unsigned int base_idx = 0;
+ for (unsigned int current_idx = 0; current_idx < current->used;
+ ++current_idx)
+ {
+ /* Report missing data on the current CPU as 0. */
+ unsigned long long int current_query
+ = cpuid_query_combined (&current->qr[current_idx].q);
+ while (base_idx < base->used
+ && cpuid_query_combined (&base->qr[base_idx].q) < current_query)
+ {
+ _dl_diagnostics_cpuid_print_query (dci->processor_index,
+ base, base_idx,
+ &cpuid_registers_zero);
+ ++base_idx;
+ }
+
+ if (base_idx < base->used
+ && cpuid_query_combined (&base->qr[base_idx].q) == current_query)
+ {
+ _Static_assert (sizeof (struct cpuid_registers) == 4 * 4,
+ "no padding in struct cpuid_registers");
+ if (current->qr[current_idx].q.ecx_last
+ != base->qr[base_idx].q.ecx_last
+ || memcmp (&current->qr[current_idx].r,
+ &base->qr[base_idx].r,
+ sizeof (struct cpuid_registers)) != 0)
+ /* The ECX range or the values have changed. Show the
+ new values. */
+ _dl_diagnostics_cpuid_print_query (dci->processor_index,
+ current, current_idx,
+ &current->qr[current_idx].r);
+ ++base_idx;
+ }
+ else
+ /* Data is absent in the base reference. Report the new data. */
+ _dl_diagnostics_cpuid_print_query (dci->processor_index,
+ current, current_idx,
+ &current->qr[current_idx].r);
+ }
+
+ if (current->xgetbv_ecx_0 != base->xgetbv_ecx_0)
+ {
+ /* Re-use the 64-bit printing routine. */
+ _dl_printf ("x86.processor[0x%x].", dci->processor_index);
+ _dl_diagnostics_print_labeled_value ("xgetbv.ecx[0x0]",
+ current->xgetbv_ecx_0);
+ }
+}
+
+static void
+_dl_diagnostics_cpuid (void)
+{
+#if !HAS_CPUID
+ /* CPUID is not supported, so there is nothing to dump. */
+ if (__get_cpuid_max (0, 0) == 0)
+ return;
+#endif
+
+ struct dl_iterate_cpu dic;
+ _dl_iterate_cpu_init (&dic);
+
+ /* Two copies of the data are used. Data is written to the index
+ (dic.processor_index & 1). The previous version against which the
+ data dump is reported is at index !(processor_index & 1). */
+ struct cpuid_collected_data ccd[2];
+
+ /* The initial data is presumed to be all zero. Zero results are
+ not recorded. */
+ ccd[1].used = 0;
+ ccd[1].xgetbv_ecx_0 = 0;
+
+ /* Run the CPUID probing on a specific CPU. There are expected
+ differences for encoding core IDs and topology information in
+ CPUID output, but some firmware/kernel bugs also may result in
+ asymmetric data across CPUs in some cases. */
+ while (_dl_iterate_cpu_next (&dic))
+ {
+ _dl_diagnostics_cpuid_collect (&ccd[dic.processor_index & 1]);
+ _dl_diagnostics_cpuid_report
+ (&dic, &ccd[dic.processor_index & 1],
+ &ccd[!(dic.processor_index & 1)]);
+ }
}

@ -0,0 +1,262 @@
commit 5653ccd847f0cd3a98906e44c97c71d68652d326
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Apr 8 16:48:55 2024 +0200
elf: Add CPU iteration support for future use in ld.so diagnostics
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
diff --git a/elf/dl-iterate_cpu.h b/elf/dl-iterate_cpu.h
new file mode 100644
index 0000000000..60db167b13
--- /dev/null
+++ b/elf/dl-iterate_cpu.h
@@ -0,0 +1,136 @@
+/* Iterate over all CPUs, for CPU-specific diagnostics.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef DL_ITERATE_CPU_H
+#define DL_ITERATE_CPU_H
+
+#include <dl-affinity.h>
+#include <stdbool.h>
+
+struct dl_iterate_cpu
+{
+ /* Sequential iteration count, starting at 0. */
+ unsigned int processor_index;
+
+ /* Requested CPU. Can be -1 if affinity could not be set. */
+ int requested_cpu;
+
+ /* Observed current CPU. -1 if unavailable. */
+ int actual_cpu;
+
+ /* Observed node ID for the CPU. -1 if unavailable. */
+ int actual_node;
+
+ /* Internal fields to implement the iteration. */
+
+ /* Affinity as obtained by _dl_iterate_cpu_init, using
+ _dl_getaffinity. Space for 8,192 CPUs. */
+ unsigned long int mask_reference[8192 / sizeof (unsigned long int) / 8];
+
+ /* This array is used by _dl_setaffinity calls. */
+ unsigned long int mask_request[8192 / sizeof (unsigned long int) / 8];
+
+ /* Return value from the initial _dl_getaffinity call. */
+ int length_reference;
+};
+
+static void
+_dl_iterate_cpu_init (struct dl_iterate_cpu *dic)
+{
+ dic->length_reference
+ = _dl_getaffinity (dic->mask_reference, sizeof (dic->mask_reference));
+ /* Prepare for the first _dl_iterate_cpu_next call. */
+ dic->processor_index = -1;
+ dic->requested_cpu = -1;
+}
+
+static bool
+_dl_iterate_cpu_next (struct dl_iterate_cpu *dic)
+{
+ ++dic->processor_index;
+
+ if (dic->length_reference > 0)
+ {
+ /* Search for the next CPU to switch to. */
+ while (true)
+ {
+ ++dic->requested_cpu;
+
+ /* Array index and bit number within the array. */
+ unsigned int long_index
+ = dic->requested_cpu / sizeof (unsigned long int) / 8;
+ unsigned int bit_index
+ = dic->requested_cpu % (sizeof (unsigned long int) * 8);
+
+ if (long_index * sizeof (unsigned long int) >= dic->length_reference)
+ /* All possible CPUs have been covered. */
+ return false;
+
+ unsigned long int bit = 1UL << bit_index;
+ if (dic->mask_reference[long_index] & bit)
+ {
+ /* The CPU is available. Try to select it. */
+ dic->mask_request[long_index] = bit;
+ if (_dl_setaffinity (dic->mask_request,
+ (long_index + 1)
+ * sizeof (unsigned long int)) < 0)
+ {
+ /* Record that we could not perform a CPU request. */
+ dic->length_reference = -1;
+
+ if (dic->processor_index > 0)
+ /* We already reported something. There is no need to
+ continue because the new data is probably not useful. */
+ return false;
+ }
+
+ /* Clear the bit in case the next iteration switches to the
+ next long value. */
+ dic->mask_request[long_index] = 0;
+
+ /* We found a CPU to run on. */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* No way to set CPU affinity. Iterate just once. */
+ if (dic->processor_index > 0)
+ return false;
+ }
+
+ /* Fill in the actual CPU information. CPU pinning may not actually
+ be effective, depending on the container host. */
+ unsigned int cpu, node;
+ if (_dl_getcpu (&cpu, &node) < 0)
+ {
+ /* No CPU information available. */
+ dic->actual_cpu = -1;
+ dic->actual_node = -1;
+ }
+ else
+ {
+ dic->actual_cpu = cpu;
+ dic->actual_node = node;
+ }
+
+ return true;
+}
+
+#endif /* DL_ITERATE_CPU_H */
diff --git a/sysdeps/generic/dl-affinity.h b/sysdeps/generic/dl-affinity.h
new file mode 100644
index 0000000000..d117f737e9
--- /dev/null
+++ b/sysdeps/generic/dl-affinity.h
@@ -0,0 +1,54 @@
+/* CPU affinity handling for the dynamic linker. Stub version.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef DL_AFFINITY_H
+#define DL_AFFINITY_H
+
+#include <errno.h>
+#include <stddef.h>
+
+/* On success, write the current CPU ID to *CPU, and the current node
+ ID to *NODE, and return 0. Return a negative error code on
+ failure. */
+static inline int
+_dl_getcpu (unsigned int *cpu, unsigned int *node)
+{
+ return -ENOSYS;
+}
+
+/* On success, write CPU ID affinity bits for the current thread to
+ *BITS, which must be SIZE bytes long, and return the number of
+ bytes updated, a multiple of sizeof (unsigned long int). On
+ failure, return a negative error code. */
+static int
+_dl_getaffinity (unsigned long int *bits, size_t size)
+{
+ return -ENOSYS;
+}
+
+/* Set the CPU affinity mask for the current thread to *BITS, using
+ the SIZE bytes from that array, which should be a multiple of
+ sizeof (unsigned long int). Return 0 on success, and a negative
+ error code on failure. */
+static int
+_dl_setaffinity (const unsigned long int *bits, size_t size)
+{
+ return -ENOSYS;
+}
+
+#endif /* DL_AFFINITY_H */
diff --git a/sysdeps/unix/sysv/linux/dl-affinity.h b/sysdeps/unix/sysv/linux/dl-affinity.h
new file mode 100644
index 0000000000..bbfede7750
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-affinity.h
@@ -0,0 +1,46 @@
+/* CPU affinity handling for the dynamic linker. Linux version.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* See sysdeps/generic/dl-affinity.h for documentation of these interfaces. */
+
+#ifndef DL_AFFINITY_H
+#define DL_AFFINITY_H
+
+#include <sysdep.h>
+#include <stddef.h>
+#include <unistd.h>
+
+static inline int
+_dl_getcpu (unsigned int *cpu, unsigned int *node)
+{
+ return INTERNAL_SYSCALL_CALL (getcpu, cpu, node);
+}
+
+static int
+_dl_getaffinity (unsigned long int *bits, size_t size)
+{
+ return INTERNAL_SYSCALL_CALL (sched_getaffinity, /* TID */ 0, size, bits);
+}
+
+static int
+_dl_setaffinity (const unsigned long int *bits, size_t size)
+{
+ return INTERNAL_SYSCALL_CALL (sched_setaffinity, /* TID */ 0, size, bits);
+}
+
+#endif /* DL_AFFINITY_H */

@ -1,121 +0,0 @@
commit 5361ad3910c257bc327567be76fde532ed238e42
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Apr 19 14:38:17 2024 +0200
login: Use unsigned 32-bit types for seconds-since-epoch
These fields store timestamps when the system was running. No Linux
systems existed before 1970, so these values are unused. Switching
to unsigned types allows continued use of the existing struct layouts
beyond the year 2038.
The intent is to give distributions more time to switch to improved
interfaces that also avoid locking/data corruption issues.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/bits/utmp.h b/bits/utmp.h
index f2d1c13d8cd205b2..27cb536800c46d67 100644
--- a/bits/utmp.h
+++ b/bits/utmp.h
@@ -36,7 +36,7 @@
struct lastlog
{
#if __WORDSIZE_TIME64_COMPAT32
- int32_t ll_time;
+ __uint32_t ll_time;
#else
__time_t ll_time;
#endif
@@ -76,7 +76,7 @@ struct utmp
int32_t ut_session; /* Session ID, used for windowing. */
struct
{
- int32_t tv_sec; /* Seconds. */
+ __uint32_t tv_sec; /* Seconds. */
int32_t tv_usec; /* Microseconds. */
} ut_tv; /* Time entry was made. */
#else
diff --git a/login/Makefile b/login/Makefile
index f91190e3dcd1e6c6..84563230ef665f9c 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -44,9 +44,11 @@ subdir-dirs = programs
vpath %.c programs
tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
- tst-pututxline-lockfail tst-pututxline-cache tst-utmp-size tst-utmp-size-64
+ tst-pututxline-lockfail tst-pututxline-cache tst-utmp-size tst-utmp-size-64 \
+ tst-utmp-unsigned tst-utmp-unsigned-64
CFLAGS-tst-utmp-size-64.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-tst-utmp-unsigned-64.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
# Empty compatibility library for old binaries.
extra-libs := libutil
diff --git a/login/tst-utmp-unsigned-64.c b/login/tst-utmp-unsigned-64.c
new file mode 100644
index 0000000000000000..940e7654f8dc5fd6
--- /dev/null
+++ b/login/tst-utmp-unsigned-64.c
@@ -0,0 +1 @@
+#include "tst-utmp-unsigned.c"
diff --git a/login/tst-utmp-unsigned.c b/login/tst-utmp-unsigned.c
new file mode 100644
index 0000000000000000..27ad03a7d608e83d
--- /dev/null
+++ b/login/tst-utmp-unsigned.c
@@ -0,0 +1,40 @@
+/* Check that struct utmp, struct utmpx, struct lastlog use unsigned epoch.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <utmp.h>
+#include <utmpx.h>
+#include <utmp-size.h>
+
+/* Undefined. Used to check that the conditions below are optimized away. */
+void link_failure_utmp (void);
+void link_failure_utmpx (void);
+void link_failure_lastlog (void);
+
+static int
+do_test (void)
+{
+ if ((struct utmp) { .ut_tv = { 0x80000000U, }, }.ut_tv.tv_sec <= 0)
+ link_failure_utmp ();
+ if ((struct utmpx) { .ut_tv = { 0x80000000U, }, }.ut_tv.tv_sec <= 0)
+ link_failure_utmpx ();
+ if ((struct lastlog) { .ll_time = 0x80000000U, }.ll_time <= 0)
+ link_failure_lastlog ();
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/gnu/bits/utmpx.h b/sysdeps/gnu/bits/utmpx.h
index 34b4afbc6ac25968..ed0df9bd8141d4e6 100644
--- a/sysdeps/gnu/bits/utmpx.h
+++ b/sysdeps/gnu/bits/utmpx.h
@@ -74,7 +74,7 @@ struct utmpx
__int32_t ut_session; /* Session ID, used for windowing. */
struct
{
- __int32_t tv_sec; /* Seconds. */
+ __uint32_t tv_sec; /* Seconds. */
__int32_t tv_usec; /* Microseconds. */
} ut_tv; /* Time entry was made. */
#else

@ -0,0 +1,47 @@
commit c3b023a7822185c9176cfb96eeca4ada3d662c4b
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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

@ -0,0 +1,36 @@
commit c7f05bd5342517f3f751e6ea8dec1916b80bee8a
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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

@ -0,0 +1,30 @@
commit e6547d635b991651600fab31f788ed5facd77610
Author: WANG Xuerui <git@xen0n.name>
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 <adhemerval.zanella@linaro.org>
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

@ -0,0 +1,157 @@
commit 551101e8240b7514fc646d1722f8b79c90362b8f
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <sys/stat.h>
+#undef __fstat
+#undef fstat
#include <fcntl.h>
-#include <kernel_stat.h>
-#include <stat_t64_cp.h>
+#include <internal-stat.h>
#include <errno.h>
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 <sys/stat.h>
#include <fcntl.h>
#include <string.h>
-#include <kernel_stat.h>
#include <sysdep.h>
#include <time.h>
-#include <kstat_cp.h>
-#include <stat_t64_cp.h>
#include <sys/sysmacros.h>
+#include <internal-stat.h>
#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
+ <https://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <stat_t64_cp.h>
+#include <kernel_stat.h>
+#include <kstat_cp.h>
+
+#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

@ -0,0 +1,140 @@
commit 6a04404521ac4119ae36827eeb288ea84eee7cf6
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Feb 17 09:17:04 2024 +0100
Linux: Switch back to assembly syscall wrapper for prctl (bug 29770)
Commit ff026950e280bc3e9487b41b460fb31bc5b57721 ("Add a C wrapper for
prctl [BZ #25896]") replaced the assembler wrapper with a C function.
However, on powerpc64le-linux-gnu, the C variadic function
implementation requires extra work in the caller to set up the
parameter save area. Calling a function that needs a parameter save
area without one (because the prototype used indicates the function is
not variadic) corrupts the caller's stack. The Linux manual pages
project documents prctl as a non-variadic function. This has resulted
in various projects over the years using non-variadic prototypes,
including the sanitizer libraries in LLVm and GCC (GCC PR 113728).
This commit switches back to the assembler implementation on most
targets and only keeps the C implementation for x86-64 x32.
Also add the __prctl_time64 alias from commit
b39ffab860cd743a82c91946619f1b8158b0b65e ("Linux: Add time64 alias for
prctl") to sysdeps/unix/sysv/linux/syscalls.list; it was not yet
present in commit ff026950e280bc3e9487b41b460fb31bc5b57721.
This restores the old ABI on powerpc64le-linux-gnu, thus fixing
bug 29770.
Reviewed-By: Simon Chopin <simon.chopin@canonical.com>
Resolved conflicts:
sysdeps/unix/sysv/linux/syscalls.list
sysdeps/unix/sysv/linux/x86_64/x32/prctl.c
diff -Nrup a/sysdeps/unix/sysv/linux/prctl.c b/sysdeps/unix/sysv/linux/prctl.c
--- a/sysdeps/unix/sysv/linux/prctl.c 2021-08-01 21:33:43.000000000 -0400
+++ b/sysdeps/unix/sysv/linux/prctl.c 1969-12-31 19:00:00.000000000 -0500
@@ -1,45 +0,0 @@
-/* prctl - Linux specific syscall.
- Copyright (C) 2020-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
- <https://www.gnu.org/licenses/>. */
-
-#include <sysdep.h>
-#include <stdarg.h>
-#include <sys/prctl.h>
-
-/* Unconditionally read all potential arguments. This may pass
- garbage values to the kernel, but avoids the need for teaching
- glibc the argument counts of individual options (including ones
- that are added to the kernel in the future). */
-
-int
-__prctl (int option, ...)
-{
- va_list arg;
- va_start (arg, option);
- unsigned long int arg2 = va_arg (arg, unsigned long int);
- unsigned long int arg3 = va_arg (arg, unsigned long int);
- unsigned long int arg4 = va_arg (arg, unsigned long int);
- unsigned long int arg5 = va_arg (arg, unsigned long int);
- va_end (arg);
- return INLINE_SYSCALL_CALL (prctl, option, arg2, arg3, arg4, arg5);
-}
-
-libc_hidden_def (__prctl)
-weak_alias (__prctl, prctl)
-#if __TIMESIZE != 64
-weak_alias (__prctl, __prctl_time64)
-#endif
diff -Nrup a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
--- a/sysdeps/unix/sysv/linux/syscalls.list 2021-08-01 21:33:43.000000000 -0400
+++ b/sysdeps/unix/sysv/linux/syscalls.list 2024-02-27 14:33:01.594782897 -0500
@@ -41,6 +41,7 @@ munlockall - munlockall i: munlockall
nfsservctl EXTRA nfsservctl i:ipp __compat_nfsservctl nfsservctl@GLIBC_2.0:GLIBC_2.28
pipe - pipe i:f __pipe pipe
pipe2 - pipe2 i:fi __pipe2 pipe2
+prctl EXTRA prctl i:iiiii __prctl prctl __prctl_time64
pivot_root EXTRA pivot_root i:ss pivot_root
query_module EXTRA query_module i:sipip __compat_query_module query_module@GLIBC_2.0:GLIBC_2.23
quotactl EXTRA quotactl i:isip quotactl
diff -Nrup a/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c b/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c
--- a/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c 1969-12-31 19:00:00.000000000 -0500
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c 2024-02-27 14:35:03.388602623 -0500
@@ -0,0 +1,42 @@
+/* prctl - Linux specific syscall. x86-64 x32 version.
+ Copyright (C) 2020-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
+ <https://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <stdarg.h>
+#include <sys/prctl.h>
+
+/* Unconditionally read all potential arguments. This may pass
+ garbage values to the kernel, but avoids the need for teaching
+ glibc the argument counts of individual options (including ones
+ that are added to the kernel in the future). */
+
+int
+__prctl (int option, ...)
+{
+ va_list arg;
+ va_start (arg, option);
+ unsigned long int arg2 = va_arg (arg, unsigned long int);
+ unsigned long int arg3 = va_arg (arg, unsigned long int);
+ unsigned long int arg4 = va_arg (arg, unsigned long int);
+ unsigned long int arg5 = va_arg (arg, unsigned long int);
+ va_end (arg);
+ return INLINE_SYSCALL_CALL (prctl, option, arg2, arg3, arg4, arg5);
+}
+
+libc_hidden_def (__prctl)
+weak_alias (__prctl, prctl)

@ -0,0 +1,41 @@
commit 01671608a3bddde369cdd42aed12e1c019b87158
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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)
{

@ -0,0 +1,178 @@
commit 6e3fed9d20d6b7ef4b69dd7cfcdd7bbaf1c9a9cb
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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:
{

@ -0,0 +1,208 @@
commit 92478a808f477480adbc5ca3d9a4a1bc27fc13ae
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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);

@ -0,0 +1,34 @@
commit cc4544ef8069a14c67a46b7e8e28eff1dc102050
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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;
}
}

@ -0,0 +1,316 @@
commit e09ee267c03e3150c2c9ba28625ab130705a485e
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
(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
+ <https://www.gnu.org/licenses/>. */
+
+#include <nss.h>
+#include <stdlib.h>
+#include <string.h>
+#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
+ <https://www.gnu.org/licenses/>. */
+
+#include <nss.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#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 <support/test-driver.c>
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);

@ -0,0 +1,37 @@
commit 57e349b1b0df1aee2dcd19dae1f324bde25ff8f0
Author: H.J. Lu <hjl.tools@gmail.com>
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 <carlos@redhat.com>
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

@ -0,0 +1,84 @@
commit ec6b95c3303c700eb89eebeda2d7264cc184a796
Author: Romain Geissler <romain.geissler@amadeus.com>
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 <siddhesh@sourceware.org>
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 <netdb.h>
#include <stdlib.h>
#include <string.h>
+#include <mcheck.h>
#include <support/check.h>
#include <support/xstdio.h>
#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;
}

@ -0,0 +1,248 @@
commit b195fd86c616b147dad3a63498b79e0dedb4662b
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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;
}

@ -0,0 +1,86 @@
commit f7efb43738f255db32cfa4e84a491c09f6da66e2
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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;
}

@ -0,0 +1,285 @@
commit e05e5889b8a307fe4be55b03bcbd7a1c62fc2f2d
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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));

File diff suppressed because it is too large Load Diff

@ -0,0 +1,179 @@
commit 3b5a3e5009088a029525277f36228eeb95032358
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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;

@ -0,0 +1,328 @@
commit 5914a1d55b468ccf0fb6d997a7a4e378339df735
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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;

@ -0,0 +1,673 @@
commit ec71cb961121760f81e55af5489e658dc89e96e6
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Mar 7 15:56:22 2022 +0530
gaih_inet: separate nss lookup loop into its own function
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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)

@ -0,0 +1,156 @@
commit 4d59769087f2143f619b4b38bf93590a86f5c806
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(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)
{

@ -0,0 +1,973 @@
commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+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 <support/test-driver.c>
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;

@ -0,0 +1,112 @@
commit 849274d48fc59bfa6db3c713c8ced8026b20f3b7
Author: Florian Weimer <fweimer@redhat.com>
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 <adhemerval.zanella@linaro.org>
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>{}<a<b
# relocation(dynamic) dependencies. While this is technically unspecified, the
# presumed reasonable practical behavior is for the destructor order to respect
# the static DT_NEEDED links (here this means the 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[<a<c<d<g<f<b<e];}
-output(glibc.rtld.dynamic_sort=2): {+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[<g<f<a<b<c<d<e];}
+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[<a<b<c<d<g<f<e];}
+output(glibc.rtld.dynamic_sort=2): {+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[<a<g<f<b<c<d<e];}
# Test that even in the presence of dependency loops involving dlopen'ed
# object, that object is initialized last (and not unloaded prematurely).

@ -1,25 +1,30 @@
commit 7fc8242bf87828c935ac5df5cafb9dc7ab635fd9 From dfb05f8e704edac70db38c4c8ee700769d91a413 Mon Sep 17 00:00:00 2001
Author: H.J. Lu <hjl.tools@gmail.com> From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri Feb 16 07:17:10 2024 -0800 Date: Fri, 16 Feb 2024 07:17:10 -0800
Subject: [PATCH] x86-64: Save APX registers in ld.so trampoline
Content-type: text/plain; charset=UTF-8
x86-64: Save APX registers in ld.so trampoline Add APX registers to STATE_SAVE_MASK so that APX registers are saved in
ld.so trampoline. This fixes BZ #31371.
Add APX registers to STATE_SAVE_MASK so that APX registers are saved in Also update STATE_SAVE_OFFSET and STATE_SAVE_MASK for i386 which will
ld.so trampoline. This fixes BZ #31371. be used by i386 _dl_tlsdesc_dynamic.
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
Also update STATE_SAVE_OFFSET and STATE_SAVE_MASK for i386 which will Conflicts:
be used by i386 _dl_tlsdesc_dynamic. sysdeps/x86/sysdep.h
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com> (rebased for context and line numbers)
---
(cherry picked from commit dfb05f8e704edac70db38c4c8ee700769d91a413) sysdeps/x86/sysdep.h | 52 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 46 insertions(+), 6 deletions(-)
diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h
index 85d0a8c943cbb218..837fd28734914a1c 100644 index 85d0a8c943..837fd28734 100644
--- a/sysdeps/x86/sysdep.h --- a/sysdeps/x86/sysdep.h
+++ b/sysdeps/x86/sysdep.h +++ b/sysdeps/x86/sysdep.h
@@ -21,14 +21,54 @@ @@ -48,14 +48,54 @@
# define SHSTK_ENABLED 0
#include <sysdeps/generic/sysdep.h> #endif
+/* The extended state feature IDs in the state component bitmap. */ +/* The extended state feature IDs in the state component bitmap. */
+#define X86_XSTATE_X87_ID 0 +#define X86_XSTATE_X87_ID 0
@ -78,3 +83,6 @@ index 85d0a8c943cbb218..837fd28734914a1c 100644
/* Constants for bits in __x86_string_control: */ /* Constants for bits in __x86_string_control: */
--
2.39.3

@ -1,4 +1,4 @@
commit 9de9cd17e73db0ba9af9ef11dc12d490fb59720c commit 127fc56152347d73cb7c1c283e60e1cb1f15e9f9
Author: sayan paul <saypaul@redhat.com> Author: sayan paul <saypaul@redhat.com>
Date: Wed May 29 15:31:04 2024 +0530 Date: Wed May 29 15:31:04 2024 +0530
@ -13,20 +13,22 @@ Date: Wed May 29 15:31:04 2024 +0530
Reviewed-by: Arjun Shankar <arjun@redhat.com> Reviewed-by: Arjun Shankar <arjun@redhat.com>
Reviewed-by: Zack Weinberg <zack@owlfolio.org> Reviewed-by: Zack Weinberg <zack@owlfolio.org>
(cherry picked from commit 127fc56152347d73cb7c1c283e60e1cb1f15e9f9) Conflicts:
malloc/Makefile
(usual tests conflict)
diff --git a/malloc/Makefile b/malloc/Makefile diff --git a/malloc/Makefile b/malloc/Makefile
index c1a03f3cb02c464d..cc14cf66c9661f99 100644 index 9b70831d383cb522..cb4e027d28b179f0 100644
--- a/malloc/Makefile --- a/malloc/Makefile
+++ b/malloc/Makefile +++ b/malloc/Makefile
@@ -34,6 +34,7 @@ tests := \ @@ -43,6 +43,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
tst-interpose-nothread \ tst-tcfree1 tst-tcfree2 tst-tcfree3 \
tst-interpose-thread \ tst-safe-linking \
tst-malloc \ tst-mallocalign1 \
+ tst-malloc-alternate-path \ + tst-malloc-alternate-path \
tst-malloc-backtrace \
tst-malloc-check \ tests-static := \
tst-malloc-fork-deadlock \ tst-interpose-static-nothread \
diff --git a/malloc/tst-malloc-alternate-path.c b/malloc/tst-malloc-alternate-path.c diff --git a/malloc/tst-malloc-alternate-path.c b/malloc/tst-malloc-alternate-path.c
new file mode 100644 new file mode 100644
index 0000000000000000..43ae916815d6ff47 index 0000000000000000..43ae916815d6ff47

@ -0,0 +1,26 @@
From a07e000e82cb71238259e674529c37c12dc7d423 Mon Sep 17 00:00:00 2001
From: DJ Delorie <dj@redhat.com>
Date: Fri, 10 May 2024 17:34:29 -0400
Subject: manual: add dup3
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/manual/llio.texi b/manual/llio.texi
index fae49d1433..fe1807a849 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -3415,6 +3415,14 @@ middle of calling @code{dup2} at which @var{new} is closed and not yet a
duplicate of @var{old}.
@end deftypefun
+@deftypefun int dup3 (int @var{old}, int @var{new}, int @var{flags})
+@standards{Linux, unistd.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+This function is the same as @code{dup2} but creates the new
+descriptor as if it had been opened with flags @var{flags}. The only
+allowed flag is @code{O_CLOEXEC}.
+@end deftypefun
+
@deftypevr Macro int F_DUPFD
@standards{POSIX.1, fcntl.h}
This macro is used as the @var{command} argument to @code{fcntl}, to

@ -0,0 +1,341 @@
From 6c0be74305745c8f78bcfb69442c8c379459d99b Mon Sep 17 00:00:00 2001
From: DJ Delorie <dj@redhat.com>
Date: Mon, 8 Jul 2024 17:52:15 -0400
Subject: manual: add syscalls
The purpose of this patch is to add some system calls that (1) aren't
otherwise documented, and (2) are merely redirected to the kernel, so
can refer to their documentation; and define a standard way of doing
so in the future. A more detailed explaination of how system calls
are wrapped is added along with reference to the Linux Man-Pages
project.
Default version of man-pages is in configure.ac but can be overridden
by --with-man-pages=X.Y
Reviewed-by: Alejandro Colomar <alx@kernel.org>
diff --git a/config.make.in b/config.make.in
index 55e8b7563b..36096881b7 100644
--- a/config.make.in
+++ b/config.make.in
@@ -101,6 +101,7 @@ build-hardcoded-path-in-tests= @hardcode
build-pt-chown = @build_pt_chown@
have-tunables = @have_tunables@
pthread-in-libc = @pthread_in_libc@
+man-pages-version = @man_pages_version@
# Build tools.
CC = @CC@
diff --git a/configure b/configure
index 55e8b7563b..36096881b7 100644
--- a/configure 2024-07-17 15:45:55.033649362 -0400
+++ b/configure 2024-07-17 15:47:44.281886629 -0400
@@ -681,6 +681,7 @@ force_install
bindnow
hardcoded_path_in_tests
enable_timezone_tools
+man_pages_version
rtld_early_cflags
extra_nonshared_cflags
use_default_link
@@ -763,6 +764,7 @@ with_headers
with_default_link
with_nonshared_cflags
with_rtld_early_cflags
+with_man_pages
enable_sanity_checks
enable_shared
enable_profile
@@ -1483,6 +1485,8 @@ Optional Packages:
build nonshared libraries with additional CFLAGS
--with-rtld-early-cflags=CFLAGS
build early initialization with additional CFLAGS
+ --with-man-pages=VERSION
+ tie manual to a specific man-pages version
--with-cpu=CPU select code for CPU variant
Some influential environment variables:
@@ -3396,6 +3400,15 @@ fi
+man_pages_version=6.9.1
+
+
+# Check whether --with-man-pages was given.
+if test "${with_man_pages+set}" = set; then :
+ withval=$with_man_pages; man_pages_version=$withval
+fi
+
+
# Check whether --enable-sanity-checks was given.
if test "${enable_sanity_checks+set}" = set; then :
diff --git a/configure.ac b/configure.ac
index e48957f318..9cbc0bf68f 100644
--- a/configure.ac 2024-07-17 15:45:52.181538742 -0400
+++ b/configure.ac 2024-07-17 15:46:29.885001095 -0400
@@ -169,6 +169,15 @@ AC_ARG_WITH([rtld-early-cflags],
[rtld_early_cflags=])
AC_SUBST(rtld_early_cflags)
+man_pages_version=6.9.1
+
+AC_ARG_WITH([man-pages],
+ AS_HELP_STRING([--with-man-pages=VERSION],
+ [tie manual to a specific man-pages version]),
+ [man_pages_version=$withval],
+ [])
+AC_SUBST(man_pages_version)
+
AC_ARG_ENABLE([sanity-checks],
AS_HELP_STRING([--disable-sanity-checks],
[really do not use threads (should not be used except in special situations) @<:@default=yes@:>@]),
diff --git a/manual/Makefile b/manual/Makefile
index b5fda4a7ae..a6c05db540 100644
--- a/manual/Makefile
+++ b/manual/Makefile
@@ -117,6 +117,7 @@ $(objpfx)stamp-pkgvers: $(common-objpfx)config.make
echo "@set PKGVERSION_DEFAULT" >> $(objpfx)pkgvers-tmp; \
fi
echo "@set REPORT_BUGS_TO $(REPORT_BUGS_TEXI)" >> $(objpfx)pkgvers-tmp
+ echo "@set man_pages_version $(man-pages-version)" >> $(objpfx)pkgvers-tmp; \
echo "@end ifclear" >> $(objpfx)pkgvers-tmp
$(move-if-change) $(objpfx)pkgvers-tmp $(objpfx)pkgvers.texi
touch $@
diff --git a/manual/intro.texi b/manual/intro.texi
index ff43c5a7fb..879c1b38d9 100644
--- a/manual/intro.texi
+++ b/manual/intro.texi
@@ -85,6 +85,7 @@ standards each function or symbol comes from.
* Berkeley Unix:: BSD and SunOS.
* SVID:: The System V Interface Description.
* XPG:: The X/Open Portability Guide.
+* Linux Kernel:: The Linux kernel.
@end menu
@node ISO C, POSIX, , Standards and Portability
@@ -941,7 +942,7 @@ inter-process communication and shared memory, the @code{hsearch} and
@code{drand48} families of functions, @code{fmtmsg} and several of the
mathematical functions.
-@node XPG, , SVID, Standards and Portability
+@node XPG, Linux Kernel, SVID, Standards and Portability
@subsection XPG (The X/Open Portability Guide)
The X/Open Portability Guide, published by the X/Open Company, Ltd., is
@@ -960,6 +961,20 @@ fulfilling the XPG standard with the Unix extensions is a
precondition for getting the Unix brand chances are good that the
functionality is available on commercial systems.
+@node Linux Kernel, , XPG, Standards and Portability
+@subsection Linux (The Linux Kernel)
+
+@Theglibc{} includes by reference the Linux man-pages
+@value{man_pages_version} documentation to document the listed
+syscalls for the Linux kernel. For reference purposes only the latest
+@uref{https://www.kernel.org/doc/man-pages/,Linux man-pages Project}
+documentation can be accessed from the
+@uref{https://www.kernel.org,Linux kernel} website. Where the syscall
+has more specific documentation in this manual that more specific
+documentation is considered authoritative.
+
+Additional details on the Linux system call interface can be found in
+@xref{System Calls}.
@node Using the Library, Roadmap to the Manual, Standards and Portability, Introduction
@section Using the Library
diff --git a/manual/llio.texi b/manual/llio.texi
index 78c7c79913..6f0a48609b 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -65,6 +65,7 @@ directly.)
* Interrupt Input:: Getting an asynchronous signal when
input arrives.
* IOCTLs:: Generic I/O Control operations.
+* Other Low-Level I/O APIs:: Other low-level-I/O-related functions.
@end menu
@@ -2324,6 +2325,8 @@ file descriptor, or until the timeout period expires.
There is another example showing the use of @code{select} to multiplex
input from multiple sockets in @ref{Server Example}.
+For an alternate interface to this functionality, see @code{poll}
+(@pxref{Other Low-Level I/O APIs}).
@node Synchronizing I/O
@section Synchronizing I/O operations
@@ -3407,7 +3410,9 @@ require additional arguments to be supplied. These additional arguments
and the return value and error conditions are given in the detailed
descriptions of the individual commands.
-Briefly, here is a list of what the various commands are.
+Briefly, here is a list of what the various commands are. For an
+exhaustive list of kernel-specific options, please see @xref{System
+Calls}.
@vtable @code
@item F_DUPFD
@@ -4743,5 +4748,28 @@ Most IOCTLs are OS-specific and/or only used in special system utilities,
and are thus beyond the scope of this document. For an example of the use
of an IOCTL, see @ref{Out-of-Band Data}.
-@c FIXME this is undocumented:
-@c dup3
+@node Other Low-Level I/O APIs
+@section Other low-level-I/O-related functions
+
+@deftp {Data Type} {struct pollfd}
+@standards{POSIX.1,poll.h}
+@end deftp
+
+@deftp {Data Type} {struct epoll_event}
+@standards{Linux,sys/epoll.h}
+@end deftp
+
+@deftypefun int poll (struct pollfd *@var{fds}, nfds_t @var{nfds}, int @var{timeout})
+
+@manpagefunctionstub{poll,2}
+@end deftypefun
+
+@deftypefun int epoll_create(int @var{size})
+
+@manpagefunctionstub{epoll_create,2}
+@end deftypefun
+
+@deftypefun int epoll_wait(int @var{epfd}, struct epoll_event *@var{events}, int @var{maxevents}, int @var{timeout})
+
+@manpagefunctionstub{epoll_wait,2}
+@end deftypefun
diff --git a/manual/macros.texi b/manual/macros.texi
index 4a2e22f473..579da3fb81 100644
--- a/manual/macros.texi
+++ b/manual/macros.texi
@@ -282,4 +282,11 @@ cwd\comments\
@macro standardsx {element, standard, header}
@end macro
+@macro manpagefunctionstub {func,sec}
+This documentation is a stub. For additional information on this
+function, consult the manual page
+@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html}.
+@xref{Linux Kernel}.
+@end macro
+
@end ifclear
diff --git a/manual/socket.texi b/manual/socket.texi
index f0e35d9e13..8708cbb07c 100644
--- a/manual/socket.texi
+++ b/manual/socket.texi
@@ -41,6 +41,7 @@ aren't documented either so far.
is to make it work with Inetd.
* Socket Options:: Miscellaneous low-level socket options.
* Networks Database:: Accessing the database of network names.
+* Other Socket APIs:: Other socket-related functions.
@end menu
@node Socket Concepts
@@ -3134,38 +3135,8 @@ You can use plain @code{recv} (@pxref{Receiving Data}) instead of
treat all possible senders alike). Even @code{read} can be used if
you don't want to specify @var{flags} (@pxref{I/O Primitives}).
-@ignore
-@c sendmsg and recvmsg are like readv and writev in that they
-@c use a series of buffers. It's not clear this is worth
-@c supporting or that we support them.
-@c !!! they can do more; it is hairy
-
-@deftp {Data Type} {struct msghdr}
-@standards{BSD, sys/socket.h}
-@end deftp
-
-@deftypefun ssize_t sendmsg (int @var{socket}, const struct msghdr *@var{message}, int @var{flags})
-@standards{BSD, sys/socket.h}
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-
-This function is defined as a cancellation point in multi-threaded
-programs, so one has to be prepared for this and make sure that
-allocated resources (like memory, files descriptors, semaphores or
-whatever) are freed even if the thread is cancel.
-@c @xref{pthread_cleanup_push}, for a method how to do this.
-@end deftypefun
-
-@deftypefun ssize_t recvmsg (int @var{socket}, struct msghdr *@var{message}, int @var{flags})
-@standards{BSD, sys/socket.h}
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-
-This function is defined as a cancellation point in multi-threaded
-programs, so one has to be prepared for this and make sure that
-allocated resources (like memory, files descriptors, semaphores or
-whatever) are freed even if the thread is canceled.
-@c @xref{pthread_cleanup_push}, for a method how to do this.
-@end deftypefun
-@end ignore
+If you need more flexibility and/or control over sending and receiving
+packets, see @code{sendmsg} and @code{recvmsg} (@pxref{Other Socket APIs}).
@node Datagram Example
@subsection Datagram Socket Example
@@ -3664,3 +3635,20 @@ returns a null pointer if there are no more entries.
@c libc_lock_unlock @aculock
This function closes the networks database.
@end deftypefun
+
+@node Other Socket APIs
+@section Other Socket APIs
+
+@deftp {Data Type} {struct msghdr}
+@standards{BSD, sys/socket.h}
+@end deftp
+
+@deftypefun ssize_t sendmsg (int @var{socket}, const struct msghdr *@var{message}, int @var{flags})
+
+@manpagefunctionstub{sendmsg,2}
+@end deftypefun
+
+@deftypefun ssize_t recvmsg (int @var{socket}, struct msghdr *@var{message}, int @var{flags})
+
+@manpagefunctionstub{recvmsg,2}
+@end deftypefun
diff --git a/manual/startup.texi b/manual/startup.texi
index 224dd98c1e..747beed4d9 100644
--- a/manual/startup.texi
+++ b/manual/startup.texi
@@ -689,7 +689,25 @@ you don't need to know about it because you can just use @theglibc{}'s
@code{chmod} function.
@cindex kernel call
-System calls are sometimes called kernel calls.
+System calls are sometimes called syscalls or kernel calls, and this
+interface is mostly a purely mechanical translation from the kernel's
+ABI to the C ABI. For the set of syscalls where we do not guarantee
+POSIX Thread cancellation the wrappers only organize the incoming
+arguments from the C calling convention to the calling convention of
+the target kernel. For the set of syscalls where we provided POSIX
+Thread cancellation the wrappers set some internal state in the
+library to support cancellation, but this does not impact the
+behaviour of the syscall provided by the kernel.
+
+In some cases, if @theglibc{} detects that a system call has been
+superseded by a more capable one, the wrapper may map the old call to
+the new one. For example, @code{dup2} is implemented via @code{dup3}
+by passing an additional empty flags argument, and @code{open} calls
+@code{openat} passing the additional @code{AT_FDCWD}. Sometimes even
+more is done, such as converting between 32-bit and 64-bit time
+values. In general, though, such processing is only to make the
+system call better match the C ABI, rather than change its
+functionality.
However, there are times when you want to make a system call explicitly,
and for that, @theglibc{} provides the @code{syscall} function.
@@ -711,6 +729,8 @@ we won't describe it here either because anyone who is coding
library source code as a specification of the interface between them
anyway.
+@code{syscall} does not provide cancellation logic, even if the system
+call you're calling is listed as cancellable above.
@code{syscall} is declared in @file{unistd.h}.

@ -0,0 +1,188 @@
From a4c3f5f46e850c977cda81c251036475aab8313c Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu, 23 Nov 2023 14:29:14 -0300
Subject: [PATCH] elf: Add a way to check if tunable is set (BZ 27069)
Content-type: text/plain; charset=UTF-8
The patch adds two new macros, TUNABLE_GET_DEFAULT and TUNABLE_IS_INITIALIZED,
here the former get the default value with a signature similar to
TUNABLE_GET, while the later returns whether the tunable was set by
the environment variable.
Checked on x86_64-linux-gnu.
Reviewed-by: DJ Delorie <dj@redhat.com>
Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Conflicts:
elf/Versions
(removed to preserve ABI)
elf/dl-tunable-types.h
(line numbers)
scripts/gen-tunables.awk
(account for missing TUNABLE_SECLEVEL patch)
---
elf/dl-tunable-types.h | 1 +
elf/dl-tunables.c | 40 ++++++++++++++++++++++++++++++++++++++++
elf/dl-tunables.h | 28 ++++++++++++++++++++++++++++
elf/dl-tunables.list | 1 +
scripts/gen-tunables.awk | 4 ++--
6 files changed, 73 insertions(+), 2 deletions(-)
diff -rup a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h
--- a/elf/dl-tunable-types.h 2021-08-01 21:33:43.000000000 -0400
+++ b/elf/dl-tunable-types.h 2024-03-26 18:23:22.211504813 -0400
@@ -61,6 +61,7 @@ struct _tunable
{
const char name[TUNABLE_NAME_MAX]; /* Internal name of the tunable. */
tunable_type_t type; /* Data type of the tunable. */
+ const tunable_val_t def; /* The value. */
tunable_val_t val; /* The value. */
bool initialized; /* Flag to indicate that the tunable is
initialized. */
diff -rup a/elf/dl-tunables.c b/elf/dl-tunables.c
--- a/elf/dl-tunables.c 2024-03-26 18:21:10.090681748 -0400
+++ b/elf/dl-tunables.c 2024-03-26 18:23:22.214504923 -0400
@@ -152,6 +152,13 @@ tunable_initialize (tunable_t *cur, cons
do_tunable_update_val (cur, &val, NULL, NULL);
}
+bool
+__tunable_is_initialized (tunable_id_t id)
+{
+ return tunable_list[id].initialized;
+}
+rtld_hidden_def (__tunable_is_initialized)
+
void
__tunable_set_val (tunable_id_t id, tunable_val_t *valp, tunable_num_t *minp,
tunable_num_t *maxp)
@@ -399,6 +406,39 @@ __tunables_print (void)
}
}
+void
+__tunable_get_default (tunable_id_t id, void *valp)
+{
+ tunable_t *cur = &tunable_list[id];
+
+ switch (cur->type.type_code)
+ {
+ case TUNABLE_TYPE_UINT_64:
+ {
+ *((uint64_t *) valp) = (uint64_t) cur->def.numval;
+ break;
+ }
+ case TUNABLE_TYPE_INT_32:
+ {
+ *((int32_t *) valp) = (int32_t) cur->def.numval;
+ break;
+ }
+ case TUNABLE_TYPE_SIZE_T:
+ {
+ *((size_t *) valp) = (size_t) cur->def.numval;
+ break;
+ }
+ case TUNABLE_TYPE_STRING:
+ {
+ *((const char **)valp) = cur->def.strval;
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+rtld_hidden_def (__tunable_get_default)
+
/* Set the tunable value. This is called by the module that the tunable exists
in. */
void
diff -rup a/elf/dl-tunables.h b/elf/dl-tunables.h
--- a/elf/dl-tunables.h 2021-08-01 21:33:43.000000000 -0400
+++ b/elf/dl-tunables.h 2024-03-26 18:23:22.217505032 -0400
@@ -53,18 +53,26 @@ typedef void (*tunable_callback_t) (tuna
extern void __tunables_init (char **);
extern void __tunables_print (void);
+extern bool __tunable_is_initialized (tunable_id_t);
extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t);
extern void __tunable_set_val (tunable_id_t, tunable_val_t *, tunable_num_t *,
tunable_num_t *);
+extern void __tunable_get_default (tunable_id_t id, void *valp);
rtld_hidden_proto (__tunables_init)
rtld_hidden_proto (__tunables_print)
+rtld_hidden_proto (__tunable_is_initialized)
rtld_hidden_proto (__tunable_get_val)
rtld_hidden_proto (__tunable_set_val)
+rtld_hidden_proto (__tunable_get_default)
/* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and
TUNABLE_NAMESPACE are defined. This is useful shorthand to get and set
tunables within a module. */
#if defined TOP_NAMESPACE && defined TUNABLE_NAMESPACE
+# define TUNABLE_IS_INITIALIZED(__id) \
+ TUNABLE_IS_INITIALIZED_FULL(TOP_NAMESPACE, TUNABLE_NAMESPACE, __id)
+# define TUNABLE_GET_DEFAULT(__id, __type) \
+ TUNABLE_GET_DEFAULT_FULL(TOP_NAMESPACE, TUNABLE_NAMESPACE,__id, __type)
# define TUNABLE_GET(__id, __type, __cb) \
TUNABLE_GET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __cb)
# define TUNABLE_SET(__id, __val) \
@@ -73,6 +81,10 @@ rtld_hidden_proto (__tunable_set_val)
TUNABLE_SET_WITH_BOUNDS_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, \
__val, __min, __max)
#else
+# define TUNABLE_IS_INITIALIZED(__top, __ns, __id) \
+ TUNABLE_IS_INITIALIZED_FULL(__top, __ns, __id)
+# define TUNABLE_GET_DEFAULT(__top, __ns, __type) \
+ TUNABLE_GET_DEFAULT_FULL(__top, __ns, __id, __type)
# define TUNABLE_GET(__top, __ns, __id, __type, __cb) \
TUNABLE_GET_FULL (__top, __ns, __id, __type, __cb)
# define TUNABLE_SET(__top, __ns, __id, __val) \
@@ -81,6 +93,22 @@ rtld_hidden_proto (__tunable_set_val)
TUNABLE_SET_WITH_BOUNDS_FULL (__top, __ns, __id, __val, __min, __max)
#endif
+/* Return whether the tunable was initialized by the environment variable. */
+#define TUNABLE_IS_INITIALIZED_FULL(__top, __ns, __id) \
+({ \
+ tunable_id_t id = TUNABLE_ENUM_NAME (__top, __ns, __id); \
+ __tunable_is_initialized (id); \
+})
+
+/* Return the default value of the tunable. */
+#define TUNABLE_GET_DEFAULT_FULL(__top, __ns, __id, __type) \
+({ \
+ tunable_id_t id = TUNABLE_ENUM_NAME (__top, __ns, __id); \
+ __type __ret; \
+ __tunable_get_default (id, &__ret); \
+ __ret; \
+})
+
/* Get and return a tunable value. If the tunable was set externally and __CB
is defined then call __CB before returning the value. */
# define TUNABLE_GET_FULL(__top, __ns, __id, __type, __cb) \
diff -rup a/elf/dl-tunables.list b/elf/dl-tunables.list
--- a/elf/dl-tunables.list 2024-03-26 18:21:09.664666196 -0400
+++ b/elf/dl-tunables.list 2024-03-26 18:23:22.220505142 -0400
@@ -20,6 +20,7 @@
# type: Defaults to STRING
# minval: Optional minimum acceptable value
# maxval: Optional maximum acceptable value
+# default: Optional default value (if not specified it will be 0 or "")
# env_alias: An alias environment variable
# security_level: Specify security level of the tunable for AT_SECURE binaries.
# Valid values are:
diff -rup a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk
--- a/scripts/gen-tunables.awk 2024-03-26 18:21:09.523661049 -0400
+++ b/scripts/gen-tunables.awk 2024-03-26 18:34:45.385462341 -0400
@@ -236,8 +236,8 @@ END {
n = indices[2];
m = indices[3];
printf (" {TUNABLE_NAME_S(%s, %s, %s)", t, n, m)
- printf (", {TUNABLE_TYPE_%s, %s, %s}, {%s}, NULL, TUNABLE_SECLEVEL_%s, %s},\n",
- types[t,n,m], minvals[t,n,m], maxvals[t,n,m],
+ printf (", {TUNABLE_TYPE_%s, %s, %s}, {%s}, {%s}, NULL, TUNABLE_SECLEVEL_%s, %s},\n",
+ types[t,n,m], minvals[t,n,m], maxvals[t,n,m],default_val[t,n,m],
default_val[t,n,m], security_level[t,n,m], env_alias[t,n,m]);
}
print "};"

@ -1,27 +1,33 @@
commit aa4249266e9906c4bc833e4847f4d8feef59504f From 0c0d39fe4aeb0f69b26e76337c5dfd5530d5d44e Mon Sep 17 00:00:00 2001
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org> From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Feb 8 10:08:38 2024 -0300 Date: Thu, 8 Feb 2024 10:08:38 -0300
Subject: [PATCH] x86: Fix Zen3/Zen4 ERMS selection (BZ 30994)
x86: Fix Zen3/Zen4 ERMS selection (BZ 30994) Content-type: text/plain; charset=UTF-8
The REP MOVSB usage on memcpy/memmove does not show much performance The REP MOVSB usage on memcpy/memmove does not show much performance
improvement on Zen3/Zen4 cores compared to the vectorized loops. Also, improvement on Zen3/Zen4 cores compared to the vectorized loops. Also,
as from BZ 30994, if the source is aligned and the destination is not as from BZ 30994, if the source is aligned and the destination is not
the performance can be 20x slower. the performance can be 20x slower.
The performance difference is noticeable with small buffer sizes, closer The performance difference is noticeable with small buffer sizes, closer
to the lower bounds limits when memcpy/memmove starts to use ERMS. The to the lower bounds limits when memcpy/memmove starts to use ERMS. The
performance of REP MOVSB is similar to vectorized instruction on the performance of REP MOVSB is similar to vectorized instruction on the
size limit (the L2 cache). Also, there is no drawback to multiple cores size limit (the L2 cache). Also, there is no drawback to multiple cores
sharing the cache. sharing the cache.
Checked on x86_64-linux-gnu on Zen3. Checked on x86_64-linux-gnu on Zen3.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com> Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 0c0d39fe4aeb0f69b26e76337c5dfd5530d5d44e) Conflicts:
sysdeps/x86/dl-cacheinfo.h
(tweaked for changed context)
---
sysdeps/x86/dl-cacheinfo.h | 38 ++++++++++++++++++--------------------
1 file changed, 18 insertions(+), 20 deletions(-)
diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
index d5101615e348e5c2..f34d12846caf9422 100644 index d5101615e3..f34d12846c 100644
--- a/sysdeps/x86/dl-cacheinfo.h --- a/sysdeps/x86/dl-cacheinfo.h
+++ b/sysdeps/x86/dl-cacheinfo.h +++ b/sysdeps/x86/dl-cacheinfo.h
@@ -791,7 +791,6 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) @@ -791,7 +791,6 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
@ -125,8 +131,8 @@ index d5101615e348e5c2..f34d12846caf9422 100644
/* The default threshold to use Enhanced REP STOSB. */ /* The default threshold to use Enhanced REP STOSB. */
unsigned long int rep_stosb_threshold = 2048; unsigned long int rep_stosb_threshold = 2048;
@@ -1028,16 +1033,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) @@ -1028,15 +1033,8 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
SIZE_MAX); #endif
unsigned long int rep_movsb_stop_threshold; unsigned long int rep_movsb_stop_threshold;
- /* ERMS feature is implemented from AMD Zen3 architecture and it is - /* ERMS feature is implemented from AMD Zen3 architecture and it is
@ -144,3 +150,6 @@ index d5101615e348e5c2..f34d12846caf9422 100644
cpu_features->data_cache_size = data; cpu_features->data_cache_size = data;
cpu_features->shared_cache_size = shared; cpu_features->shared_cache_size = shared;
--
2.39.3

@ -1,19 +1,20 @@
commit 6484a92698039c4a7a510f0214e22d067b0d78b3 From 272708884cb750f12f5c74a00e6620c19dc6d567 Mon Sep 17 00:00:00 2001
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org> From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Feb 8 10:08:39 2024 -0300 Date: Thu, 8 Feb 2024 10:08:39 -0300
Subject: [PATCH] x86: Do not prefer ERMS for memset on Zen3+
Content-type: text/plain; charset=UTF-8
x86: Do not prefer ERMS for memset on Zen3+ For AMD Zen3+ architecture, the performance of the vectorized loop is
slightly better than ERMS.
For AMD Zen3+ architecture, the performance of the vectorized loop is Checked on x86_64-linux-gnu on Zen3.
slightly better than ERMS. Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
---
Checked on x86_64-linux-gnu on Zen3. sysdeps/x86/dl-cacheinfo.h | 5 +++++
Reviewed-by: H.J. Lu <hjl.tools@gmail.com> 1 file changed, 5 insertions(+)
(cherry picked from commit 272708884cb750f12f5c74a00e6620c19dc6d567)
diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
index f34d12846caf9422..5a98f70364220da4 100644 index f34d12846c..5a98f70364 100644
--- a/sysdeps/x86/dl-cacheinfo.h --- a/sysdeps/x86/dl-cacheinfo.h
+++ b/sysdeps/x86/dl-cacheinfo.h +++ b/sysdeps/x86/dl-cacheinfo.h
@@ -1021,6 +1021,11 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) @@ -1021,6 +1021,11 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
@ -28,3 +29,6 @@ index f34d12846caf9422..5a98f70364220da4 100644
TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX); TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX);
TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX); TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX);
--
2.39.3

@ -1,14 +1,16 @@
commit 5d070d12b3a52bc44dd1b71743abc4b6243862ae From 491e55beab7457ed310a4a47496f4a333c5d1032 Mon Sep 17 00:00:00 2001
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org> From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Feb 8 10:08:40 2024 -0300 Date: Thu, 8 Feb 2024 10:08:40 -0300
Subject: [PATCH] x86: Expand the comment on when REP STOSB is used on memset
Content-type: text/plain; charset=UTF-8
x86: Expand the comment on when REP STOSB is used on memset Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
---
Reviewed-by: H.J. Lu <hjl.tools@gmail.com> sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S | 4 +++-
(cherry picked from commit 491e55beab7457ed310a4a47496f4a333c5d1032) 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
index 9984c3ca0fafab6a..97839a22483b0613 100644 index 9984c3ca0f..97839a2248 100644
--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S --- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
+++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
@@ -21,7 +21,9 @@ @@ -21,7 +21,9 @@
@ -22,3 +24,6 @@ index 9984c3ca0fafab6a..97839a22483b0613 100644
4 VEC stores and store 4 * VEC at a time until done. */ 4 VEC stores and store 4 * VEC at a time until done. */
#include <sysdep.h> #include <sysdep.h>
--
2.39.3

@ -0,0 +1,164 @@
This patch was developed under embargo and cannot reference an upstream
commit. To find the associated commit please review the upstream git
log for CVE-2023-4911 to identify the relevant commits.
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
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 <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
---
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;
}
}

@ -0,0 +1,205 @@
From dce754b1553b86fc6352636f1fa490a85b7cf0ff Mon Sep 17 00:00:00 2001
From: DJ Delorie <dj@redhat.com>
Date: Fri, 10 May 2024 14:52:09 -0400
Subject: Update mmap() flags and errors lists
Extend the list of MAP_* macros to include all macros available
to the average program (gcc -E -dM | grep MAP_*)
Extend the list of errno codes.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/manual/llio.texi b/manual/llio.texi
index fe1807a849..78c7c79913 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -1573,10 +1573,15 @@ permitted. They include @code{PROT_READ}, @code{PROT_WRITE}, and
of address space for future use. The @code{mprotect} function can be
used to change the protection flags. @xref{Memory Protection}.
-@var{flags} contains flags that control the nature of the map.
-One of @code{MAP_SHARED} or @code{MAP_PRIVATE} must be specified.
+The @var{flags} parameter contains flags that control the nature of
+the map. One of @code{MAP_SHARED}, @code{MAP_SHARED_VALIDATE}, or
+@code{MAP_PRIVATE} must be specified. Additional flags may be bitwise
+OR'd to further define the mapping.
-They include:
+Note that, aside from @code{MAP_PRIVATE} and @code{MAP_SHARED}, not
+all flags are supported on all versions of all operating systems.
+Consult the kernel-specific documentation for details. The flags
+include:
@vtable @code
@item MAP_PRIVATE
@@ -1598,9 +1603,19 @@ Note that actual writing may take place at any time. You need to use
@code{msync}, described below, if it is important that other processes
using conventional I/O get a consistent view of the file.
+@item MAP_SHARED_VALIDATE
+Similar to @code{MAP_SHARED} except that additional flags will be
+validated by the kernel, and the call will fail if an unrecognized
+flag is provided. With @code{MAP_SHARED} using a flag on a kernel
+that doesn't support it causes the flag to be ignored.
+@code{MAP_SHARED_VALIDATE} should be used when the behavior of all
+flags is required.
+
@item MAP_FIXED
This forces the system to use the exact mapping address specified in
-@var{address} and fail if it can't.
+@var{address} and fail if it can't. Note that if the new mapping
+would overlap an existing mapping, the overlapping portion of the
+existing map is unmapped.
@c One of these is official - the other is obviously an obsolete synonym
@c Which is which?
@@ -1641,10 +1656,73 @@ The @code{MAP_HUGETLB} flag is specific to Linux.
@c There is a mechanism to select different hugepage sizes; see
@c include/uapi/asm-generic/hugetlb_encode.h in the kernel sources.
-@c Linux has some other MAP_ options, which I have not discussed here.
-@c MAP_DENYWRITE, MAP_EXECUTABLE and MAP_GROWSDOWN don't seem applicable to
-@c user programs (and I don't understand the last two). MAP_LOCKED does
-@c not appear to be implemented.
+@item MAP_32BIT
+Require addresses that can be accessed with a signed 32 bit pointer,
+i.e., within the first 2 GiB. Ignored if MAP_FIXED is specified.
+
+@item MAP_DENYWRITE
+@itemx MAP_EXECUTABLE
+@itemx MAP_FILE
+
+Provided for compatibility. Ignored by the Linux kernel.
+
+@item MAP_FIXED_NOREPLACE
+Similar to @code{MAP_FIXED} except the call will fail with
+@code{EEXIST} if the new mapping would overwrite an existing mapping.
+To test for support for this flag, specify MAP_FIXED_NOREPLACE without
+MAP_FIXED, and (if the call was successful) check the actual address
+returned. If it does not match the address passed, then this flag is
+not supported.
+
+@item MAP_GROWSDOWN
+This flag is used to make stacks, and is typically only needed inside
+the program loader to set up the main stack for the running process.
+The mapping is created according to the other flags, except an
+additional page just prior to the mapping is marked as a ``guard
+page''. If a write is attempted inside this guard page, that page is
+mapped, the mapping is extended, and a new guard page is created.
+Thus, the mapping continues to grow towards lower addresses until it
+encounters some other mapping.
+
+Note that accessing memory beyond the guard page will not trigger this
+feature. In gcc, use @code{-fstack-clash-protection} to ensure the
+guard page is always touched.
+
+@item MAP_LOCKED
+A hint that requests that mapped pages are locked in memory (i.e. not
+paged out). Note that this is a request and not a requirement; use
+@code{mlock} if locking is required.
+
+@item MAP_POPULATE
+@itemx MAP_NONBLOCK
+@code{MAP_POPULATE} is a hint that requests that the kernel read-ahead
+a file-backed mapping, causing pages to be mapped before they're
+needed. @code{MAP_NONBLOCK} is a hint that requests that the kernel
+@emph{not} attempt such except for pages are already in memory. Note
+that neither of these hints affects future paging activity, use
+@code{mlock} if such needs to be controlled.
+
+@item MAP_NORESERVE
+Asks the kernel to not reserve physical backing (i.e. space in a swap
+device) for a mapping. This would be useful for, for example, a very
+large but sparsely used mapping which need not be limited in total
+length by available RAM, but with very few mapped pages. Note that
+writes to such a mapping may cause a @code{SIGSEGV} if the system is
+unable to map a page due to lack of resources.
+
+On Linux, this flag's behavior may be overwridden by
+@file{/proc/sys/vm/overcommit_memory} as documented in the proc(5) man
+page.
+
+@item MAP_STACK
+Ensures that the resulting mapping is suitable for use as a program
+stack. For example, the use of huge pages might be precluded.
+
+@item MAP_SYNC
+This is a special flag for DAX devices, which tells the kernel to
+write dirty metadata out whenever dirty data is written out. Unlike
+most other flags, this one will fail unless @code{MAP_SHARED_VALIDATE}
+is also given.
@end vtable
@@ -1655,6 +1733,24 @@ Possible errors include:
@table @code
+@item EACCES
+
+@var{filedes} was not open for the type of access specified in @var{protect}.
+
+@item EAGAIN
+
+The system has temporarily run out of resources.
+
+@item EBADF
+
+The @var{fd} passed is invalid, and a valid file descriptor is
+required (i.e. MAP_ANONYMOUS was not specified).
+
+@item EEXIST
+
+@code{MAP_FIXED_NOREPLACE} was specified and an existing mapping was
+found overlapping the requested address range.
+
@item EINVAL
Either @var{address} was unusable (because it is not a multiple of the
@@ -1663,23 +1759,37 @@ applicable page size), or inconsistent @var{flags} were given.
If @code{MAP_HUGETLB} was specified, the file or system does not support
large page sizes.
-@item EACCES
+@item ENODEV
-@var{filedes} was not open for the type of access specified in @var{protect}.
+This file is of a type that doesn't support mapping, the process has
+exceeded its data space limit, or the map request would exceed the
+process's virtual address space.
@item ENOMEM
-Either there is not enough memory for the operation, or the process is
-out of address space.
-
-@item ENODEV
-
-This file is of a type that doesn't support mapping.
+There is not enough memory for the operation, the process is out of
+address space, or there are too many mappings. On Linux, the maximum
+number of mappings can be controlled via
+@file{/proc/sys/vm/max_map_count} or, if your OS supports it, via
+the @code{vm.max_map_count} @code{sysctl} setting.
@item ENOEXEC
The file is on a filesystem that doesn't support mapping.
+@item EPERM
+
+@code{PROT_EXEC} was requested but the file is on a filesystem that
+was mounted with execution denied, a file seal prevented the mapping,
+or the caller set MAP_HUDETLB but does not have the required
+priviledges.
+
+@item EOVERFLOW
+
+Either the offset into the file plus the length of the mapping causes
+internal page counts to overflow, or the offset requested exceeds the
+length of the file.
+
@c On Linux, EAGAIN will appear if the file has a conflicting mandatory lock.
@c However mandatory locks are not discussed in this manual.
@c

@ -1,4 +1,3 @@
commit 31da30f23cddd36db29d5b6a1c7619361b271fb4
Author: Charles Fol <folcharles@gmail.com> Author: Charles Fol <folcharles@gmail.com>
Date: Thu Mar 28 12:25:38 2024 -0300 Date: Thu Mar 28 12:25:38 2024 -0300
@ -16,23 +15,24 @@ Date: Thu Mar 28 12:25:38 2024 -0300
Reviewed-by: Carlos O'Donell <carlos@redhat.com> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com> Tested-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit f9dc609e06b1136bb0408be9605ce7973a767ada) Conflicts:
iconvdata/Makefile
(usual tests conflict)
diff --git a/iconvdata/Makefile b/iconvdata/Makefile diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index ea019ce5c0e67e98..7196a8744bb66e8c 100644 index d5507a048c6a6508..25bd004e7f92a994 100644
--- a/iconvdata/Makefile --- a/iconvdata/Makefile
+++ b/iconvdata/Makefile +++ b/iconvdata/Makefile
@@ -75,7 +75,8 @@ ifeq (yes,$(build-shared)) @@ -75,7 +75,7 @@ ifeq (yes,$(build-shared))
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \ bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
- bug-iconv13 bug-iconv14 bug-iconv15 - bug-iconv13 bug-iconv14 bug-iconv15
+ bug-iconv13 bug-iconv14 bug-iconv15 \ + bug-iconv13 bug-iconv14 bug-iconv15 tst-iconv-iso-2022-cn-ext
+ tst-iconv-iso-2022-cn-ext
ifeq ($(have-thread-library),yes) ifeq ($(have-thread-library),yes)
tests += bug-iconv3 tests += bug-iconv3
endif endif
@@ -330,6 +331,8 @@ $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \ @@ -330,6 +330,8 @@ $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so)) $(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \ $(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so)) $(addprefix $(objpfx),$(modules.so))
@ -42,10 +42,10 @@ index ea019ce5c0e67e98..7196a8744bb66e8c 100644
$(objpfx)iconv-test.out: run-iconv-test.sh \ $(objpfx)iconv-test.out: run-iconv-test.sh \
$(addprefix $(objpfx), $(gconv-modules)) \ $(addprefix $(objpfx), $(gconv-modules)) \
diff --git a/iconvdata/iso-2022-cn-ext.c b/iconvdata/iso-2022-cn-ext.c diff --git a/iconvdata/iso-2022-cn-ext.c b/iconvdata/iso-2022-cn-ext.c
index b34c8a36f4564c11..cce29b19692263d6 100644 index 2aca91c021f21ba0..c1339fe933d9d1c4 100644
--- a/iconvdata/iso-2022-cn-ext.c --- a/iconvdata/iso-2022-cn-ext.c
+++ b/iconvdata/iso-2022-cn-ext.c +++ b/iconvdata/iso-2022-cn-ext.c
@@ -574,6 +574,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); @@ -575,6 +575,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
{ \ { \
const char *escseq; \ const char *escseq; \
\ \
@ -58,7 +58,7 @@ index b34c8a36f4564c11..cce29b19692263d6 100644
assert (used == CNS11643_2_set); /* XXX */ \ assert (used == CNS11643_2_set); /* XXX */ \
escseq = "*H"; \ escseq = "*H"; \
*outptr++ = ESC; \ *outptr++ = ESC; \
@@ -587,6 +593,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); @@ -588,6 +594,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
{ \ { \
const char *escseq; \ const char *escseq; \
\ \

@ -1,4 +1,4 @@
commit 32969a2b36b8cc74343182b768b3babe6f81c3aa commit 3a83f79024cc023a74c3892a1673542e8e972485
Author: Sergey Kolosov <skolosov@redhat.com> Author: Sergey Kolosov <skolosov@redhat.com>
Date: Wed Apr 10 17:58:05 2024 +0200 Date: Wed Apr 10 17:58:05 2024 +0200
@ -8,25 +8,24 @@ Date: Wed Apr 10 17:58:05 2024 +0200
connection to a local process via the loopback interface. connection to a local process via the loopback interface.
Reviewed-by: Arjun Shankar <arjun@redhat.com> Reviewed-by: Arjun Shankar <arjun@redhat.com>
(cherry picked from commit 3a83f79024cc023a74c3892a1673542e8e972485)
diff --git a/socket/Makefile b/socket/Makefile diff -Nrup a/socket/Makefile b/socket/Makefile
index 74ca5b8452cd15d3..fc1bd0a2608f04bc 100644 --- a/socket/Makefile 2024-05-19 21:52:59.775055152 -0400
--- a/socket/Makefile +++ b/socket/Makefile 2024-05-19 22:05:27.717703460 -0400
+++ b/socket/Makefile @@ -33,8 +33,9 @@ routines := accept bind connect getpeern
@@ -70,6 +70,7 @@ tests := \
tests := \
tst-accept4 \ tst-accept4 \
tst-cmsg_cloexec \ - tst-sockopt \
tst-cmsghdr \ tst-cmsghdr \
+ tst-connect \ + tst-connect \
tst-sockopt \ + tst-sockopt \
# tests # tests
diff --git a/socket/tst-connect.c b/socket/tst-connect.c tests-internal := \
new file mode 100644 diff -Nrup a/socket/tst-connect.c b/socket/tst-connect.c
index 0000000000000000..ec2fdd92c0a6f1be --- a/socket/tst-connect.c 1969-12-31 19:00:00.000000000 -0500
--- /dev/null +++ b/socket/tst-connect.c 2024-05-19 21:58:22.069058144 -0400
+++ b/socket/tst-connect.c
@@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
+/* Test the connect function. +/* Test the connect function.
+ Copyright (C) 2024 Free Software Foundation, Inc. + Copyright (C) 2024 Free Software Foundation, Inc.

@ -1,4 +1,4 @@
commit 2db79c96baa1256b8fc2656596143da92fabd074 commit 6687a6e3f962759536a8019d31c68c1009ccd6eb
Author: Sergey Kolosov <skolosov@redhat.com> Author: Sergey Kolosov <skolosov@redhat.com>
Date: Wed Apr 10 17:58:04 2024 +0200 Date: Wed Apr 10 17:58:04 2024 +0200
@ -7,25 +7,21 @@ Date: Wed Apr 10 17:58:04 2024 +0200
The patch adds redirections for getpeername. The patch adds redirections for getpeername.
Reviewed-by: Arjun Shankar <arjun@redhat.com> Reviewed-by: Arjun Shankar <arjun@redhat.com>
(cherry picked from commit 6687a6e3f962759536a8019d31c68c1009ccd6eb)
diff --git a/support/Makefile b/support/Makefile diff -Nrup a/support/Makefile b/support/Makefile
index 362a51f882787f2b..aa57207bdccc852d 100644 --- a/support/Makefile 2024-05-19 23:27:12.379362736 -0400
--- a/support/Makefile +++ b/support/Makefile 2024-05-19 23:29:28.668182089 -0400
+++ b/support/Makefile @@ -126,6 +126,7 @@ libsupport-routines = \
@@ -131,6 +131,7 @@ libsupport-routines = \ xfork \
xfreopen \
xftruncate \ xftruncate \
xgetline \ xgetline \
+ xgetpeername \ + xgetpeername \
xgetsockname \ xgetsockname \
xlisten \ xlisten \
xlseek \ xlseek \
diff --git a/support/xgetpeername.c b/support/xgetpeername.c diff -Nrup a/support/xgetpeername.c b/support/xgetpeername.c
new file mode 100644 --- a/support/xgetpeername.c 1969-12-31 19:00:00.000000000 -0500
index 0000000000000000..6f448e456a1d9e1e +++ b/support/xgetpeername.c 2024-05-19 23:30:31.852561947 -0400
--- /dev/null
+++ b/support/xgetpeername.c
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
+/* getpeername with error checking. +/* getpeername with error checking.
+ Copyright (C) 2024 Free Software Foundation, Inc. + Copyright (C) 2024 Free Software Foundation, Inc.
@ -57,10 +53,9 @@ index 0000000000000000..6f448e456a1d9e1e
+ if (getpeername (fd, sa, plen) != 0) + if (getpeername (fd, sa, plen) != 0)
+ FAIL_EXIT1 ("getpeername (%d): %m", fd); + FAIL_EXIT1 ("getpeername (%d): %m", fd);
+} +}
diff --git a/support/xsocket.h b/support/xsocket.h diff -Nrup a/support/xsocket.h b/support/xsocket.h
index 3e4410354676cb2a..4ac0e1f5ffe35dc2 100644 --- a/support/xsocket.h 2021-08-01 21:33:43.000000000 -0400
--- a/support/xsocket.h +++ b/support/xsocket.h 2024-05-19 23:31:24.541878715 -0400
+++ b/support/xsocket.h
@@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
int xsocket (int, int, int); int xsocket (int, int, int);
void xsetsockopt (int, int, int, const void *, socklen_t); void xsetsockopt (int, int, int, const void *, socklen_t);

@ -0,0 +1,83 @@
commit c00b984fcd53f679ca2dafcd1aee2c89836e6e73
Author: Florian Weimer <fweimer@redhat.com>
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 <dj@redhat.com>
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;
}

@ -1,4 +1,4 @@
commit 1263d583d2e28afb8be53f8d6922f0842036f35d commit 87801a8fd06db1d654eea3e4f7626ff476a9bdaa
Author: Florian Weimer <fweimer@redhat.com> Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Apr 25 15:00:45 2024 +0200 Date: Thu Apr 25 15:00:45 2024 +0200
@ -8,10 +8,9 @@ Date: Thu Apr 25 15:00:45 2024 +0200
bounded by MAXKEYLEN. bounded by MAXKEYLEN.
Reviewed-by: Carlos O'Donell <carlos@redhat.com> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 87801a8fd06db1d654eea3e4f7626ff476a9bdaa)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index 0c6e46f15c5d7139..f227dc7fa2856e38 100644 index 0c6e46f15c..f227dc7fa2 100644
--- a/nscd/netgroupcache.c --- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c
@@ -502,12 +502,13 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, @@ -502,12 +502,13 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,

@ -1,4 +1,4 @@
commit c99f886de54446cd4447db6b44be93dabbdc2f8b commit b048a482f088e53144d26a61c390bed0210f49f2
Author: Florian Weimer <fweimer@redhat.com> Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Apr 25 15:01:07 2024 +0200 Date: Thu Apr 25 15:01:07 2024 +0200
@ -16,10 +16,9 @@ Date: Thu Apr 25 15:01:07 2024 +0200
it from there in the future, instead of going through the socket. it from there in the future, instead of going through the socket.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org> Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit b048a482f088e53144d26a61c390bed0210f49f2)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index c18fe111f37496d7..e22ffa5884e36260 100644 index c18fe111f3..e22ffa5884 100644
--- a/nscd/netgroupcache.c --- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c
@@ -511,14 +511,15 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, @@ -511,14 +511,15 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,

@ -1,4 +1,4 @@
commit 5a508e0b508c8ad53bd0d2fb48fd71b242626341 commit 7835b00dbce53c3c87bbbb1754a95fb5e58187aa
Author: Florian Weimer <fweimer@redhat.com> Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Apr 25 15:01:07 2024 +0200 Date: Thu Apr 25 15:01:07 2024 +0200
@ -8,10 +8,9 @@ Date: Thu Apr 25 15:01:07 2024 +0200
point can be null, resulting in a null pointer dereference. point can be null, resulting in a null pointer dereference.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org> Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 7835b00dbce53c3c87bbbb1754a95fb5e58187aa)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index f227dc7fa2856e38..c18fe111f37496d7 100644 index f227dc7fa2..c18fe111f3 100644
--- a/nscd/netgroupcache.c --- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c
@@ -147,7 +147,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -147,7 +147,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,

@ -1,4 +1,4 @@
commit a9a8d3eebb145779a18d90e3966009a1daa63cd8 commit c04a21e050d64a1193a6daab872bca2528bda44b
Author: Florian Weimer <fweimer@redhat.com> Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Apr 25 15:01:07 2024 +0200 Date: Thu Apr 25 15:01:07 2024 +0200
@ -16,21 +16,19 @@ Date: Thu Apr 25 15:01:07 2024 +0200
This fixes bug 31679. This fixes bug 31679.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org> Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit c04a21e050d64a1193a6daab872bca2528bda44b)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c diff -Nrup glibc-2.34/nscd/netgroupcache.c b/nscd/netgroupcache.c
index e22ffa5884e36260..e8fe041846b75cb9 100644 --- glibc-2.34/nscd/netgroupcache.c 2024-06-13 13:55:16.406511485 -0400
--- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c 2024-06-13 13:34:45.523345077 -0400
+++ b/nscd/netgroupcache.c @@ -24,6 +24,7 @@
@@ -23,6 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
+#include <scratch_buffer.h> +#include <scratch_buffer.h>
#include "../nss/netgroup.h" #include "../inet/netgroup.h"
#include "nscd.h" #include "nscd.h"
@@ -65,6 +66,16 @@ struct dataset @@ -66,6 +67,16 @@ struct dataset
char strdata[0]; char strdata[0];
}; };
@ -47,7 +45,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
/* Sends a notfound message and prepares a notfound dataset to write to the /* Sends a notfound message and prepares a notfound dataset to write to the
cache. Returns true if there was enough memory to allocate the dataset and cache. Returns true if there was enough memory to allocate the dataset and
returns the dataset in DATASETP, total bytes to write in TOTALP and the returns the dataset in DATASETP, total bytes to write in TOTALP and the
@@ -83,8 +94,7 @@ do_notfound (struct database_dyn *db, int fd, request_header *req, @@ -84,8 +95,7 @@ do_notfound (struct database_dyn *db, in
total = sizeof (notfound); total = sizeof (notfound);
timeout = time (NULL) + db->negtimeout; timeout = time (NULL) + db->negtimeout;
@ -57,7 +55,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1); dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
/* If we cannot permanently store the result, so be it. */ /* If we cannot permanently store the result, so be it. */
@@ -109,11 +119,78 @@ do_notfound (struct database_dyn *db, int fd, request_header *req, @@ -110,11 +120,78 @@ do_notfound (struct database_dyn *db, in
return cacheable; return cacheable;
} }
@ -138,7 +136,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
{ {
if (__glibc_unlikely (debug_level > 0)) if (__glibc_unlikely (debug_level > 0))
{ {
@@ -132,14 +209,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -133,14 +210,10 @@ addgetnetgrentX (struct database_dyn *db
char *key_copy = NULL; char *key_copy = NULL;
struct __netgrent data; struct __netgrent data;
@ -153,7 +151,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
if (netgroup_database == NULL if (netgroup_database == NULL
&& !__nss_database_get (nss_database_netgroup, &netgroup_database)) && !__nss_database_get (nss_database_netgroup, &netgroup_database))
@@ -151,8 +224,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -152,8 +225,6 @@ addgetnetgrentX (struct database_dyn *db
} }
memset (&data, '\0', sizeof (data)); memset (&data, '\0', sizeof (data));
@ -162,7 +160,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
first_needed->next = first_needed; first_needed->next = first_needed;
memcpy (first_needed->name, key, group_len); memcpy (first_needed->name, key, group_len);
data.needed_groups = first_needed; data.needed_groups = first_needed;
@@ -195,8 +266,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -196,8 +267,8 @@ addgetnetgrentX (struct database_dyn *db
while (1) while (1)
{ {
int e; int e;
@ -173,7 +171,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
if (status == NSS_STATUS_SUCCESS) if (status == NSS_STATUS_SUCCESS)
{ {
if (data.type == triple_val) if (data.type == triple_val)
@@ -204,68 +275,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -205,68 +276,10 @@ addgetnetgrentX (struct database_dyn *db
const char *nhost = data.val.triple.host; const char *nhost = data.val.triple.host;
const char *nuser = data.val.triple.user; const char *nuser = data.val.triple.user;
const char *ndomain = data.val.triple.domain; const char *ndomain = data.val.triple.domain;
@ -246,7 +244,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
++nentries; ++nentries;
} }
else else
@@ -317,8 +330,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -318,8 +331,8 @@ addgetnetgrentX (struct database_dyn *db
} }
else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE) else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
{ {
@ -257,7 +255,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
} }
else if (status == NSS_STATUS_RETURN else if (status == NSS_STATUS_RETURN
|| status == NSS_STATUS_NOTFOUND || status == NSS_STATUS_NOTFOUND
@@ -351,10 +364,17 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -352,10 +365,17 @@ addgetnetgrentX (struct database_dyn *db
goto maybe_cache_add; goto maybe_cache_add;
} }
@ -277,7 +275,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
timeout = datahead_init_pos (&dataset->head, total + req->key_len, timeout = datahead_init_pos (&dataset->head, total + req->key_len,
total - offsetof (struct dataset, resp), total - offsetof (struct dataset, resp),
he == NULL ? 0 : dh->nreloads + 1, he == NULL ? 0 : dh->nreloads + 1,
@@ -363,11 +383,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -364,11 +384,7 @@ addgetnetgrentX (struct database_dyn *db
dataset->resp.version = NSCD_VERSION; dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1; dataset->resp.found = 1;
dataset->resp.nresults = nentries; dataset->resp.nresults = nentries;
@ -290,7 +288,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
/* Now we can determine whether on refill we have to create a new /* Now we can determine whether on refill we have to create a new
record or not. */ record or not. */
@@ -398,7 +414,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -399,7 +415,7 @@ addgetnetgrentX (struct database_dyn *db
if (__glibc_likely (newp != NULL)) if (__glibc_likely (newp != NULL))
{ {
/* Adjust pointer into the memory block. */ /* Adjust pointer into the memory block. */
@ -299,7 +297,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
dataset = memcpy (newp, dataset, total + req->key_len); dataset = memcpy (newp, dataset, total + req->key_len);
cacheable = true; cacheable = true;
@@ -439,7 +455,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, @@ -440,7 +456,7 @@ addgetnetgrentX (struct database_dyn *db
} }
out: out:
@ -308,9 +306,9 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
return timeout; return timeout;
} }
@@ -460,6 +476,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, @@ -461,6 +477,9 @@ addinnetgrX (struct database_dyn *db, in
if (user != NULL) if (user != NULL)
key = strchr (key, '\0') + 1; key = (char *) rawmemchr (key, '\0') + 1;
const char *domain = *key++ ? key : NULL; const char *domain = *key++ ? key : NULL;
+ struct addgetnetgrentX_scratch scratch; + struct addgetnetgrentX_scratch scratch;
+ +
@ -318,7 +316,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
if (__glibc_unlikely (debug_level > 0)) if (__glibc_unlikely (debug_level > 0))
{ {
@@ -475,12 +494,8 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, @@ -476,12 +495,8 @@ addinnetgrX (struct database_dyn *db, in
group, group_len, group, group_len,
db, uid); db, uid);
time_t timeout; time_t timeout;
@ -332,7 +330,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
else else
{ {
request_header req_get = request_header req_get =
@@ -489,7 +504,10 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, @@ -490,7 +505,10 @@ addinnetgrX (struct database_dyn *db, in
.key_len = group_len .key_len = group_len
}; };
timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL, timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
@ -344,7 +342,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
} }
struct indataset struct indataset
@@ -603,7 +621,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, @@ -604,7 +622,7 @@ addinnetgrX (struct database_dyn *db, in
} }
out: out:
@ -353,7 +351,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
return timeout; return timeout;
} }
@@ -613,11 +631,12 @@ addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req, @@ -614,11 +632,12 @@ addgetnetgrentX_ignore (struct database_
const char *key, uid_t uid, struct hashentry *he, const char *key, uid_t uid, struct hashentry *he,
struct datahead *dh) struct datahead *dh)
{ {
@ -371,7 +369,7 @@ index e22ffa5884e36260..e8fe041846b75cb9 100644
return timeout; return timeout;
} }
@@ -661,5 +680,9 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he, @@ -662,5 +681,9 @@ readdinnetgr (struct database_dyn *db, s
.key_len = he->len .key_len = he->len
}; };

@ -1,4 +1,4 @@
commit acc56074b0a5127631a64640aef1b7c5c103ebd8 commit 4bbca1a44691a6e9adcee5c6798a707b626bc331
Author: Florian Weimer <fweimer@redhat.com> Author: Florian Weimer <fweimer@redhat.com>
Date: Thu May 2 17:06:19 2024 +0200 Date: Thu May 2 17:06:19 2024 +0200
@ -12,10 +12,9 @@ Date: Thu May 2 17:06:19 2024 +0200
(bug 31680)"). (bug 31680)").
Reviewed-by: Carlos O'Donell <carlos@redhat.com> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 4bbca1a44691a6e9adcee5c6798a707b626bc331)
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index e8fe041846b75cb9..01d554af9c407739 100644 index 4b35498e3f..5fdcf4204e 100644
--- a/nscd/netgroupcache.c --- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c
@@ -680,8 +680,8 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he, @@ -680,8 +680,8 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he,

@ -0,0 +1,88 @@
commit fe06fb313bddf7e4530056897d4a706606e49377
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Aug 1 23:31:23 2024 +0200
elf: Clarify and invert second argument of _dl_allocate_tls_init
Also remove an outdated comment: _dl_allocate_tls_init is
called as part of pthread_create.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff -Nrup a/elf/dl-tls.c b/elf/dl-tls.c
--- a/elf/dl-tls.c 2024-08-27 22:51:44.720953314 -0400
+++ b/elf/dl-tls.c 2024-08-27 22:51:07.686759191 -0400
@@ -558,9 +558,14 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_m
/* Allocate initial TLS. RESULT should be a non-NULL pointer to storage
for the TLS space. The DTV may be resized, and so this function may
call malloc to allocate that space. The loader's GL(dl_load_tls_lock)
- is taken when manipulating global TLS-related data in the loader. */
+ is taken when manipulating global TLS-related data in the loader.
+
+ If MAIN_THREAD, this is the first call during process
+ initialization. In this case, TLS initialization for secondary
+ (audit) namespaces is skipped because that has already been handled
+ by dlopen. */
void *
-_dl_allocate_tls_init (void *result, bool init_tls)
+_dl_allocate_tls_init (void *result, bool main_thread)
{
if (result == NULL)
/* The memory allocation failed. */
@@ -639,7 +644,7 @@ _dl_allocate_tls_init (void *result, boo
because it would already be set by the audit setup. However,
subsequent thread creation would need to follow the default
behaviour. */
- if (map->l_ns != LM_ID_BASE && !init_tls)
+ if (map->l_ns != LM_ID_BASE && main_thread)
continue;
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',
@@ -667,7 +672,7 @@ _dl_allocate_tls (void *mem)
{
return _dl_allocate_tls_init (mem == NULL
? _dl_allocate_tls_storage ()
- : allocate_dtv (mem), true);
+ : allocate_dtv (mem), false);
}
rtld_hidden_def (_dl_allocate_tls)
diff -Nrup a/elf/rtld.c b/elf/rtld.c
--- a/elf/rtld.c 2024-08-27 22:51:44.720953314 -0400
+++ b/elf/rtld.c 2024-08-27 22:54:51.136930475 -0400
@@ -2485,7 +2485,7 @@ dl_main (const ElfW(Phdr) *phdr,
into the main thread's TLS area, which we allocated above.
Note: thread-local variables must only be accessed after completing
the next step. */
- _dl_allocate_tls_init (tcbp, false);
+ _dl_allocate_tls_init (tcbp, true);
/* And finally install it for the main thread. */
if (! tls_init_tp_called)
diff -Nrup a/nptl/allocatestack.c b/nptl/allocatestack.c
--- a/nptl/allocatestack.c 2024-08-27 22:51:43.922949131 -0400
+++ b/nptl/allocatestack.c 2024-08-27 22:51:07.687759197 -0400
@@ -137,7 +137,7 @@ get_cached_stack (size_t *sizep, void **
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
/* Re-initialize the TLS. */
- _dl_allocate_tls_init (TLS_TPADJ (result), true);
+ _dl_allocate_tls_init (TLS_TPADJ (result), false);
return result;
}
diff -Nrup a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
--- a/sysdeps/generic/ldsodefs.h 2024-08-27 22:51:44.720953314 -0400
+++ b/sysdeps/generic/ldsodefs.h 2024-08-27 22:56:44.425524320 -0400
@@ -1258,10 +1258,8 @@ extern void _dl_get_tls_static_info (siz
extern void _dl_allocate_static_tls (struct link_map *map) attribute_hidden;
-/* These are internal entry points to the two halves of _dl_allocate_tls,
- only used within rtld.c itself at startup time. */
extern void *_dl_allocate_tls_storage (void) attribute_hidden;
-extern void *_dl_allocate_tls_init (void *, bool);
+extern void *_dl_allocate_tls_init (void *result, bool main_thread);
rtld_hidden_proto (_dl_allocate_tls_init)
/* Deallocate memory allocated with _dl_allocate_tls. */

@ -0,0 +1,520 @@
commit 5097cd344fd243fb8deb6dec96e8073753f962f9
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Aug 1 23:31:30 2024 +0200
elf: Avoid re-initializing already allocated TLS in dlopen (bug 31717)
The old code used l_init_called as an indicator for whether TLS
initialization was complete. However, it is possible that
TLS for an object is initialized, written to, and then dlopen
for this object is called again, and l_init_called is not true at
this point. Previously, this resulted in TLS being initialized
twice, discarding any interim writes (technically introducing a
use-after-free bug even).
This commit introduces an explicit per-object flag, l_tls_in_slotinfo.
It indicates whether _dl_add_to_slotinfo has been called for this
object. This flag is used to avoid double-initialization of TLS.
In update_tls_slotinfo, the first_static_tls micro-optimization
is removed because preserving the initalization flag for subsequent
use by the second loop for static TLS is a bit complicated, and
another per-object flag does not seem to be worth it. Furthermore,
the l_init_called flag is dropped from the second loop (for static
TLS initialization) because l_need_tls_init on its own prevents
double-initialization.
The remaining l_init_called usage in resize_scopes and update_scopes
is just an optimization due to the use of scope_has_map, so it is
not changed in this commit.
The isupper check ensures that libc.so.6 is TLS is not reverted.
Such a revert happens if l_need_tls_init is not cleared in
_dl_allocate_tls_init for the main_thread case, now that
l_init_called is not checked anymore in update_tls_slotinfo
in elf/dl-open.c.
Reported-by: Jonathon Anderson <janderson@rice.edu>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff -Nrup a/elf/Makefile b/elf/Makefile
--- a/elf/Makefile 2024-08-27 23:25:59.327755050 -0400
+++ b/elf/Makefile 2024-08-27 23:16:50.456864065 -0400
@@ -399,6 +399,10 @@ tests += \
tst-dlmopen-dlerror \
tst-dlmopen-gethostbyname \
tst-dlmopen-twice \
+ tst-dlopen-tlsreinit1 \
+ tst-dlopen-tlsreinit2 \
+ tst-dlopen-tlsreinit3 \
+ tst-dlopen-tlsreinit4 \
tst-dlopenfail \
tst-dlopenfail-2 \
tst-dlopenrpath \
@@ -753,6 +757,9 @@ modules-names = \
tst-dlmopen-gethostbyname-mod \
tst-dlmopen-twice-mod1 \
tst-dlmopen-twice-mod2 \
+ tst-dlopen-tlsreinitmod1 \
+ tst-dlopen-tlsreinitmod2 \
+ tst-dlopen-tlsreinitmod3 \
tst-dlopenfaillinkmod \
tst-dlopenfailmod1 \
tst-dlopenfailmod2 \
@@ -2751,3 +2758,26 @@ $(objpfx)tst-recursive-tls.out: \
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
$(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
$(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
+
+# Order matters here. The test needs the constructor for
+# tst-dlopen-tlsreinitmod2.so to be called first.
+LDFLAGS-tst-dlopen-tlsreinitmod1.so = -Wl,--no-as-needed
+$(objpfx)tst-dlopen-tlsreinitmod1.so: \
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
+LDFLAGS-tst-dlopen-tlsreinit2 = -Wl,--no-as-needed
+$(objpfx)tst-dlopen-tlsreinit2: \
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
+LDFLAGS-tst-dlopen-tlsreinit4 = -Wl,--no-as-needed
+$(objpfx)tst-dlopen-tlsreinit4: \
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
+# tst-dlopen-tlsreinitmod2.so is underlinked and refers to
+# tst-dlopen-tlsreinitmod3.so. The dependency is provided via
+# $(objpfx)tst-dlopen-tlsreinitmod1.so.
+tst-dlopen-tlsreinitmod2.so-no-z-defs = yes
+$(objpfx)tst-dlopen-tlsreinit.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
+ $(objpfx)tst-dlopen-tlsreinitmod2.so $(objpfx)tst-dlopen-tlsreinitmod3.so
+# Reuse an audit module which provides ample debug logging.
+$(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so
+tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
+tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
diff -Nrup a/elf/dl-open.c b/elf/dl-open.c
--- a/elf/dl-open.c 2024-08-27 23:25:59.237754576 -0400
+++ b/elf/dl-open.c 2024-08-27 23:10:52.497978645 -0400
@@ -362,17 +362,8 @@ resize_tls_slotinfo (struct link_map *ne
{
bool any_tls = false;
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
- {
- struct link_map *imap = new->l_searchlist.r_list[i];
-
- /* Only add TLS memory if this object is loaded now and
- therefore is not yet initialized. */
- if (! imap->l_init_called && imap->l_tls_blocksize > 0)
- {
- _dl_add_to_slotinfo (imap, false);
- any_tls = true;
- }
- }
+ if (_dl_add_to_slotinfo (new->l_searchlist.r_list[i], false))
+ any_tls = true;
return any_tls;
}
@@ -382,22 +373,8 @@ resize_tls_slotinfo (struct link_map *ne
static void
update_tls_slotinfo (struct link_map *new)
{
- unsigned int first_static_tls = new->l_searchlist.r_nlist;
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
- {
- struct link_map *imap = new->l_searchlist.r_list[i];
-
- /* Only add TLS memory if this object is loaded now and
- therefore is not yet initialized. */
- if (! imap->l_init_called && imap->l_tls_blocksize > 0)
- {
- _dl_add_to_slotinfo (imap, true);
-
- if (imap->l_need_tls_init
- && first_static_tls == new->l_searchlist.r_nlist)
- first_static_tls = i;
- }
- }
+ _dl_add_to_slotinfo (new->l_searchlist.r_list[i], true);
size_t newgen = GL(dl_tls_generation) + 1;
if (__glibc_unlikely (newgen == 0))
@@ -409,13 +386,11 @@ TLS generation counter wrapped! Please
/* We need a second pass for static tls data, because
_dl_update_slotinfo must not be run while calls to
_dl_add_to_slotinfo are still pending. */
- for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
{
struct link_map *imap = new->l_searchlist.r_list[i];
- if (imap->l_need_tls_init
- && ! imap->l_init_called
- && imap->l_tls_blocksize > 0)
+ if (imap->l_need_tls_init && imap->l_tls_blocksize > 0)
{
/* For static TLS we have to allocate the memory here and
now, but we can delay updating the DTV. */
diff -Nrup a/elf/dl-tls.c b/elf/dl-tls.c
--- a/elf/dl-tls.c 2024-08-27 23:25:59.358755213 -0400
+++ b/elf/dl-tls.c 2024-08-27 23:21:04.960204566 -0400
@@ -638,17 +638,21 @@ _dl_allocate_tls_init (void *result, boo
some platforms use in static programs requires it. */
dtv[map->l_tls_modid].pointer.val = dest;
- /* Copy the initialization image and clear the BSS part. For
- audit modules or dependencies with initial-exec TLS, we can not
- set the initial TLS image on default loader initialization
- because it would already be set by the audit setup. However,
- subsequent thread creation would need to follow the default
- behaviour. */
+ /* Copy the initialization image and clear the BSS part.
+ For audit modules or dependencies with initial-exec TLS,
+ we can not set the initial TLS image on default loader
+ initialization because it would already be set by the
+ audit setup, which uses the dlopen code and already
+ clears l_need_tls_init. Calls with !main_thread from
+ pthread_create need to initialze TLS for the current
+ thread regardless of namespace. */
if (map->l_ns != LM_ID_BASE && main_thread)
continue;
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',
map->l_tls_blocksize - map->l_tls_initimage_size);
+ if (main_thread)
+ map->l_need_tls_init = 0;
}
total += cnt;
@@ -1105,9 +1109,32 @@ _dl_tls_initial_modid_limit_setup (void)
}
-void
+/* Add module to slot information data. If DO_ADD is false, only the
+ required memory is allocated. Must be called with
+ GL (dl_load_tls_lock) acquired. If the function has already been
+ called for the link map L with !DO_ADD, then this function will not
+ raise an exception, otherwise it is possible that it encounters a
+ memory allocation failure.
+
+ Return false if L has already been added to the slotinfo data, or
+ if L has no TLS data. If the returned value is true, L has been
+ added with this call (DO_ADD), or has been added in a previous call
+ (!DO_ADD).
+
+ The expected usage is as follows: Call _dl_add_to_slotinfo for
+ several link maps with DO_ADD set to false, and record if any calls
+ result in a true result. If there was a true result, call
+ _dl_add_to_slotinfo again, this time with DO_ADD set to true. (For
+ simplicity, it's possible to call the function for link maps where
+ the previous result was false.) The return value from the second
+ round of calls can be ignored. If there was true result initially,
+ call _dl_update_slotinfo to update the TLS generation counter. */
+bool
_dl_add_to_slotinfo (struct link_map *l, bool do_add)
{
+ if (l->l_tls_blocksize == 0 || l->l_tls_in_slotinfo)
+ return false;
+
/* Now that we know the object is loaded successfully add
modules containing TLS data to the dtv info table. We
might have to increase its size. */
@@ -1163,7 +1190,10 @@ cannot create TLS data structures"));
atomic_store_relaxed (&listp->slotinfo[idx].map, l);
atomic_store_relaxed (&listp->slotinfo[idx].gen,
GL(dl_tls_generation) + 1);
+ l->l_tls_in_slotinfo = true;
}
+
+ return true;
}
#if THREAD_GSCOPE_IN_TCB
diff -Nrup a/elf/tst-dlopen-tlsreinit1.c b/elf/tst-dlopen-tlsreinit1.c
--- a/elf/tst-dlopen-tlsreinit1.c 1969-12-31 19:00:00.000000000 -0500
+++ b/elf/tst-dlopen-tlsreinit1.c 2024-08-27 23:10:52.497978645 -0400
@@ -0,0 +1,40 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717).
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdbool.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <ctype.h>
+
+static int
+do_test (void)
+{
+ void *handle = xdlopen ("tst-dlopen-tlsreinitmod1.so", RTLD_NOW);
+
+ bool *tlsreinitmod3_tested = xdlsym (handle, "tlsreinitmod3_tested");
+ TEST_VERIFY (*tlsreinitmod3_tested);
+
+ xdlclose (handle);
+
+ /* This crashes if the libc.so.6 TLS image has been reverted. */
+ TEST_VERIFY (!isupper ('@'));
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff -Nrup a/elf/tst-dlopen-tlsreinit2.c b/elf/tst-dlopen-tlsreinit2.c
--- a/elf/tst-dlopen-tlsreinit2.c 1969-12-31 19:00:00.000000000 -0500
+++ b/elf/tst-dlopen-tlsreinit2.c 2024-08-27 23:10:52.497978645 -0400
@@ -0,0 +1,39 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717).
+ Variant with initially-linked modules.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+
+static int
+do_test (void)
+{
+ /* Defined in tst-dlopen-tlsreinitmod3.so. */
+ extern bool tlsreinitmod3_tested;
+ TEST_VERIFY (tlsreinitmod3_tested);
+
+ /* This crashes if the libc.so.6 TLS image has been reverted. */
+ TEST_VERIFY (!isupper ('@'));
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff -Nrup a/elf/tst-dlopen-tlsreinit3.c b/elf/tst-dlopen-tlsreinit3.c
--- a/elf/tst-dlopen-tlsreinit3.c 1969-12-31 19:00:00.000000000 -0500
+++ b/elf/tst-dlopen-tlsreinit3.c 2024-08-27 23:10:52.497978645 -0400
@@ -0,0 +1,2 @@
+/* Same code, but run with LD_AUDIT=tst-auditmod1.so. */
+#include "tst-dlopen-tlsreinit1.c"
diff -Nrup a/elf/tst-dlopen-tlsreinit4.c b/elf/tst-dlopen-tlsreinit4.c
--- a/elf/tst-dlopen-tlsreinit4.c 1969-12-31 19:00:00.000000000 -0500
+++ b/elf/tst-dlopen-tlsreinit4.c 2024-08-27 23:10:52.497978645 -0400
@@ -0,0 +1,2 @@
+/* Same code, but run with LD_AUDIT=tst-auditmod1.so. */
+#include "tst-dlopen-tlsreinit2.c"
diff -Nrup a/elf/tst-dlopen-tlsreinitmod1.c b/elf/tst-dlopen-tlsreinitmod1.c
--- a/elf/tst-dlopen-tlsreinitmod1.c 1969-12-31 19:00:00.000000000 -0500
+++ b/elf/tst-dlopen-tlsreinitmod1.c 2024-08-27 23:10:52.497978645 -0400
@@ -0,0 +1,20 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 1.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* This module triggers loading of tst-dlopen-tlsreinitmod2.so and
+ tst-dlopen-tlsreinitmod3.so. */
diff -Nrup a/elf/tst-dlopen-tlsreinitmod2.c b/elf/tst-dlopen-tlsreinitmod2.c
--- a/elf/tst-dlopen-tlsreinitmod2.c 1969-12-31 19:00:00.000000000 -0500
+++ b/elf/tst-dlopen-tlsreinitmod2.c 2024-08-27 23:10:52.497978645 -0400
@@ -0,0 +1,30 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 2.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+/* Defined in tst-dlopen-tlsreinitmod3.so. This an underlinked symbol
+ dependency. */
+extern void call_tlsreinitmod3 (void);
+
+static void __attribute__ ((constructor))
+tlsreinitmod2_init (void)
+{
+ puts ("info: constructor of tst-dlopen-tlsreinitmod2.so invoked");
+ call_tlsreinitmod3 ();
+}
diff -Nrup a/elf/tst-dlopen-tlsreinitmod3.c b/elf/tst-dlopen-tlsreinitmod3.c
--- a/elf/tst-dlopen-tlsreinitmod3.c 1969-12-31 19:00:00.000000000 -0500
+++ b/elf/tst-dlopen-tlsreinitmod3.c 2024-08-27 23:10:52.498978651 -0400
@@ -0,0 +1,102 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 3.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* Used to verify from the main program that the test ran. */
+bool tlsreinitmod3_tested;
+
+/* This TLS variable must not revert back to the initial state after
+ dlopen. */
+static __thread int tlsreinitmod3_state = 1;
+
+/* Set from the ELF constructor during dlopen. */
+static bool tlsreinitmod3_constructed;
+
+/* Second half of test, behind a compiler barrier. The compiler
+ barrier is necessary to prevent carrying over TLS address
+ information from call_tlsreinitmod3 to call_tlsreinitmod3_tail. */
+void call_tlsreinitmod3_tail (void *self) __attribute__ ((weak));
+
+/* Called from tst-dlopen-tlsreinitmod2.so. */
+void
+call_tlsreinitmod3 (void)
+{
+ printf ("info: call_tlsreinitmod3 invoked (state=%d)\n",
+ tlsreinitmod3_state);
+
+ if (tlsreinitmod3_constructed)
+ {
+ puts ("error: call_tlsreinitmod3 called after ELF constructor");
+ fflush (stdout);
+ /* Cannot rely on test harness due to dynamic linking. */
+ _exit (1);
+ }
+
+ tlsreinitmod3_state = 2;
+
+ /* Self-dlopen. This will run the ELF constructor. */
+ void *self = dlopen ("tst-dlopen-tlsreinitmod3.so", RTLD_NOW);
+ if (self == NULL)
+ {
+ printf ("error: dlopen: %s\n", dlerror ());
+ fflush (stdout);
+ /* Cannot rely on test harness due to dynamic linking. */
+ _exit (1);
+ }
+
+ call_tlsreinitmod3_tail (self);
+}
+
+void
+call_tlsreinitmod3_tail (void *self)
+{
+ printf ("info: dlopen returned in tlsreinitmod3 (state=%d)\n",
+ tlsreinitmod3_state);
+
+ if (!tlsreinitmod3_constructed)
+ {
+ puts ("error: dlopen did not call tlsreinitmod3 ELF constructor");
+ fflush (stdout);
+ /* Cannot rely on test harness due to dynamic linking. */
+ _exit (1);
+ }
+
+ if (tlsreinitmod3_state != 2)
+ {
+ puts ("error: TLS state reverted in tlsreinitmod3");
+ fflush (stdout);
+ /* Cannot rely on test harness due to dynamic linking. */
+ _exit (1);
+ }
+
+ dlclose (self);
+
+ /* Signal test completion to the main program. */
+ tlsreinitmod3_tested = true;
+}
+
+static void __attribute__ ((constructor))
+tlsreinitmod3_init (void)
+{
+ puts ("info: constructor of tst-dlopen-tlsreinitmod3.so invoked");
+ tlsreinitmod3_constructed = true;
+}
diff -Nrup a/include/link.h b/include/link.h
--- a/include/link.h 2024-08-27 23:25:58.503750710 -0400
+++ b/include/link.h 2024-08-27 23:23:42.209032820 -0400
@@ -211,6 +211,7 @@ struct link_map
freed, ie. not allocated with
the dummy malloc in ld.so. */
unsigned int l_ld_readonly:1; /* Nonzero if dynamic section is readonly. */
+ unsigned int l_tls_in_slotinfo:1; /* TLS slotinfo updated in dlopen. */
/* NODELETE status of the map. Only valid for maps of type
lt_loaded. Lazy binding sets l_nodelete_active directly,
diff -Nrup a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
--- a/sysdeps/generic/ldsodefs.h 2024-08-27 23:25:59.359755218 -0400
+++ b/sysdeps/generic/ldsodefs.h 2024-08-27 23:10:52.498978651 -0400
@@ -1291,13 +1291,7 @@ extern void *_dl_open (const char *name,
extern int _dl_scope_free (void *) attribute_hidden;
-/* Add module to slot information data. If DO_ADD is false, only the
- required memory is allocated. Must be called with GL
- (dl_load_tls_lock) acquired. If the function has already been called
- for the link map L with !do_add, then this function will not raise
- an exception, otherwise it is possible that it encounters a memory
- allocation failure. */
-extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add)
+extern bool _dl_add_to_slotinfo (struct link_map *l, bool do_add)
attribute_hidden;
/* Update slot information data for at least the generation of the

@ -0,0 +1,16 @@
Author: Patsy Griffin <patsy@redhat.com>
Fix a typo in naming tst-dlopen-tlsreinit1.out
diff -Nrup a/elf/Makefile b/elf/Makefile
--- a/elf/Makefile 2024-08-16 13:27:00.700921146 -0400
+++ b/elf/Makefile 2024-08-16 13:29:12.951628406 -0400
@@ -2802,7 +2802,7 @@ $(objpfx)tst-dlopen-tlsreinit4: \
# tst-dlopen-tlsreinitmod3.so. The dependency is provided via
# $(objpfx)tst-dlopen-tlsreinitmod1.so.
tst-dlopen-tlsreinitmod2.so-no-z-defs = yes
-$(objpfx)tst-dlopen-tlsreinit.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
+$(objpfx)tst-dlopen-tlsreinit1.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
$(objpfx)tst-dlopen-tlsreinitmod2.so $(objpfx)tst-dlopen-tlsreinitmod3.so
# Reuse an audit module which provides ample debug logging.
$(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so

@ -0,0 +1,593 @@
commit df11c05be91fda5ef490c76fd0d4a53821750116
Author: Joseph Myers <josmyers@redhat.com>
Date: Wed Jan 17 15:38:54 2024 +0000
Update syscall lists for Linux 6.7
Linux 6.7 adds the futex_requeue, futex_wait and futex_wake syscalls,
and enables map_shadow_stack for architectures previously missing it.
Update syscall-names.list and regenerate the arch-syscall.h headers
with build-many-glibcs.py update-syscalls.
Tested with build-many-glibcs.py.
Modified for RHEL by: Patsy Griffin <patsy@redhat.com>
diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
index 746991aa2f..1713897f85 100644
--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
@@ -64,7 +64,10 @@
#define __NR_fsync 82
#define __NR_ftruncate 46
#define __NR_futex 98
+#define __NR_futex_requeue 456
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_get_mempolicy 236
#define __NR_get_robust_list 100
#define __NR_getcpu 168
@@ -126,6 +129,7 @@
#define __NR_lseek 62
#define __NR_lsetxattr 6
#define __NR_madvise 233
+#define __NR_map_shadow_stack 453
#define __NR_mbind 235
#define __NR_membarrier 283
#define __NR_memfd_create 279
diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
index 32efe51267..5457d2d8ae 100644
--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
@@ -80,7 +80,10 @@
#define __NR_fsync 95
#define __NR_ftruncate 130
#define __NR_futex 394
+#define __NR_futex_requeue 566
+#define __NR_futex_wait 565
#define __NR_futex_waitv 559
+#define __NR_futex_wake 564
#define __NR_futimesat 454
#define __NR_get_kernel_syms 309
#define __NR_get_mempolicy 430
@@ -156,6 +159,7 @@
#define __NR_lstat 68
#define __NR_lstat64 426
#define __NR_madvise 75
+#define __NR_map_shadow_stack 563
#define __NR_mbind 429
#define __NR_membarrier 517
#define __NR_memfd_create 512
diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
index 1d2879e877..a66471c83a 100644
--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
@@ -66,8 +66,11 @@
#define __NR_fstatfs64 44
#define __NR_fsync 82
#define __NR_ftruncate64 46
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_get_mempolicy 236
#define __NR_get_robust_list 100
#define __NR_getcpu 168
@@ -130,6 +133,7 @@
#define __NR_lremovexattr 15
#define __NR_lsetxattr 6
#define __NR_madvise 233
+#define __NR_map_shadow_stack 453
#define __NR_mbind 235
#define __NR_membarrier 283
#define __NR_memfd_create 279
diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
index 6711981e78..74a57f4520 100644
--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
@@ -91,8 +91,11 @@
#define __NR_ftruncate 93
#define __NR_ftruncate64 194
#define __NR_futex 240
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 326
#define __NR_get_mempolicy 320
#define __NR_get_robust_list 339
@@ -170,6 +173,7 @@
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 220
+#define __NR_map_shadow_stack 453
#define __NR_mbind 319
#define __NR_membarrier 389
#define __NR_memfd_create 385
diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
index 92d9a703ea..ba7632e018 100644
--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
@@ -71,8 +71,11 @@
#define __NR_fsync 82
#define __NR_ftruncate64 46
#define __NR_futex 98
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_get_mempolicy 236
#define __NR_get_robust_list 100
#define __NR_getcpu 168
@@ -135,6 +138,7 @@
#define __NR_lremovexattr 15
#define __NR_lsetxattr 6
#define __NR_madvise 233
+#define __NR_map_shadow_stack 453
#define __NR_mbind 235
#define __NR_membarrier 283
#define __NR_memfd_create 279
diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
index fbac124b70..483706de9b 100644
--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
@@ -89,8 +89,11 @@
#define __NR_ftruncate 93
#define __NR_ftruncate64 200
#define __NR_futex 210
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 279
#define __NR_get_mempolicy 261
#define __NR_get_robust_list 290
@@ -161,6 +164,7 @@
#define __NR_lstat 84
#define __NR_lstat64 198
#define __NR_madvise 119
+#define __NR_map_shadow_stack 453
#define __NR_mbind 260
#define __NR_membarrier 343
#define __NR_memfd_create 340
diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
index 8961788a96..21c1308bb3 100644
--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
@@ -95,8 +95,11 @@
#define __NR_ftruncate 93
#define __NR_ftruncate64 194
#define __NR_futex 240
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 299
#define __NR_get_kernel_syms 130
#define __NR_get_mempolicy 275
@@ -183,6 +186,7 @@
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 219
+#define __NR_map_shadow_stack 453
#define __NR_mbind 274
#define __NR_membarrier 375
#define __NR_memfd_create 356
diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
index 2053d5d392..6d788e3440 100644
--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
@@ -94,8 +94,11 @@
#define __NR_ftruncate 93
#define __NR_ftruncate64 194
#define __NR_futex 235
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 292
#define __NR_get_kernel_syms 130
#define __NR_get_mempolicy 269
@@ -177,6 +180,7 @@
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 238
+#define __NR_map_shadow_stack 453
#define __NR_mbind 268
#define __NR_membarrier 374
#define __NR_memfd_create 353
diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
index 6865b1693c..91e1630f7b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
@@ -95,8 +95,11 @@
#define __NR_ftruncate 93
#define __NR_ftruncate64 194
#define __NR_futex 240
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 299
#define __NR_get_kernel_syms 130
#define __NR_get_mempolicy 275
@@ -183,6 +186,7 @@
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 219
+#define __NR_map_shadow_stack 453
#define __NR_mbind 274
#define __NR_membarrier 390
#define __NR_memfd_create 386
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
index b13ace8e1c..d75af97467 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
@@ -94,8 +94,11 @@
#define __NR_ftruncate 4093
#define __NR_ftruncate64 4212
#define __NR_futex 4238
+#define __NR_futex_requeue 4456
#define __NR_futex_time64 4422
+#define __NR_futex_wait 4455
#define __NR_futex_waitv 4449
+#define __NR_futex_wake 4454
#define __NR_futimesat 4292
#define __NR_get_kernel_syms 4130
#define __NR_get_mempolicy 4269
@@ -173,6 +176,7 @@
#define __NR_lstat 4107
#define __NR_lstat64 4214
#define __NR_madvise 4218
+#define __NR_map_shadow_stack 4453
#define __NR_mbind 4268
#define __NR_membarrier 4358
#define __NR_memfd_create 4354
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 b7a7c0dfa7..05bf7d251d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
@@ -87,8 +87,11 @@
#define __NR_fsync 6072
#define __NR_ftruncate 6075
#define __NR_futex 6194
+#define __NR_futex_requeue 6456
#define __NR_futex_time64 6422
+#define __NR_futex_wait 6455
#define __NR_futex_waitv 6449
+#define __NR_futex_wake 6454
#define __NR_futimesat 6255
#define __NR_get_kernel_syms 6170
#define __NR_get_mempolicy 6232
@@ -159,6 +162,7 @@
#define __NR_lsetxattr 6181
#define __NR_lstat 6006
#define __NR_madvise 6027
+#define __NR_map_shadow_stack 6453
#define __NR_mbind 6231
#define __NR_membarrier 6322
#define __NR_memfd_create 6318
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 e5d7f91f48..41ffaf3255 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
@@ -80,7 +80,10 @@
#define __NR_fsync 5072
#define __NR_ftruncate 5075
#define __NR_futex 5194
+#define __NR_futex_requeue 5456
+#define __NR_futex_wait 5455
#define __NR_futex_waitv 5449
+#define __NR_futex_wake 5454
#define __NR_futimesat 5251
#define __NR_get_kernel_syms 5170
#define __NR_get_mempolicy 5228
@@ -150,6 +153,7 @@
#define __NR_lsetxattr 5181
#define __NR_lstat 5006
#define __NR_madvise 5027
+#define __NR_map_shadow_stack 5453
#define __NR_mbind 5227
#define __NR_membarrier 5318
#define __NR_memfd_create 5314
diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
index 89950cc33a..d94e7e9ee9 100644
--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
@@ -70,8 +70,11 @@
#define __NR_fsync 82
#define __NR_ftruncate64 46
#define __NR_futex 98
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_get_mempolicy 236
#define __NR_get_robust_list 100
#define __NR_getcpu 168
@@ -134,6 +137,7 @@
#define __NR_lremovexattr 15
#define __NR_lsetxattr 6
#define __NR_madvise 233
+#define __NR_map_shadow_stack 453
#define __NR_mbind 235
#define __NR_membarrier 283
#define __NR_memfd_create 279
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
index 64683bcb76..b5522e8889 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
@@ -93,8 +93,11 @@
#define __NR_ftruncate 93
#define __NR_ftruncate64 194
#define __NR_futex 221
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 290
#define __NR_get_kernel_syms 130
#define __NR_get_mempolicy 260
@@ -173,6 +176,7 @@
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 205
+#define __NR_map_shadow_stack 453
#define __NR_mbind 259
#define __NR_membarrier 365
#define __NR_memfd_create 360
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
index af1bbf32e8..162d782ae6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
@@ -83,7 +83,10 @@
#define __NR_ftime 35
#define __NR_ftruncate 93
#define __NR_futex 221
+#define __NR_futex_requeue 456
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 290
#define __NR_get_kernel_syms 130
#define __NR_get_mempolicy 260
@@ -160,6 +163,7 @@
#define __NR_lsetxattr 210
#define __NR_lstat 107
#define __NR_madvise 205
+#define __NR_map_shadow_stack 453
#define __NR_mbind 259
#define __NR_membarrier 365
#define __NR_memfd_create 360
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
index 56e3088cbf..013222e5de 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
@@ -61,8 +61,11 @@
#define __NR_fstatfs64 44
#define __NR_fsync 82
#define __NR_ftruncate64 46
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_get_mempolicy 236
#define __NR_get_robust_list 100
#define __NR_getcpu 168
@@ -121,6 +124,7 @@
#define __NR_lremovexattr 15
#define __NR_lsetxattr 6
#define __NR_madvise 233
+#define __NR_map_shadow_stack 453
#define __NR_mbind 235
#define __NR_membarrier 283
#define __NR_memfd_create 279
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
index 508161b47a..d03dad8200 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
@@ -64,7 +64,10 @@
#define __NR_fsync 82
#define __NR_ftruncate 46
#define __NR_futex 98
+#define __NR_futex_requeue 456
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_get_mempolicy 236
#define __NR_get_robust_list 100
#define __NR_getcpu 168
@@ -126,6 +129,7 @@
#define __NR_lseek 62
#define __NR_lsetxattr 6
#define __NR_madvise 233
+#define __NR_map_shadow_stack 453
#define __NR_mbind 235
#define __NR_membarrier 283
#define __NR_memfd_create 279
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 1498ebf42e..98e6b68b31 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
@@ -92,8 +92,11 @@
#define __NR_ftruncate 93
#define __NR_ftruncate64 194
#define __NR_futex 238
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 292
#define __NR_get_kernel_syms 130
#define __NR_get_mempolicy 269
@@ -177,6 +180,7 @@
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 219
+#define __NR_map_shadow_stack 453
#define __NR_mbind 268
#define __NR_membarrier 356
#define __NR_memfd_create 350
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 624d71b56d..951fbd7c97 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
@@ -78,7 +78,10 @@
#define __NR_fsync 118
#define __NR_ftruncate 93
#define __NR_futex 238
+#define __NR_futex_requeue 456
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 292
#define __NR_get_kernel_syms 130
#define __NR_get_mempolicy 269
@@ -151,6 +154,7 @@
#define __NR_lsetxattr 225
#define __NR_lstat 107
#define __NR_madvise 219
+#define __NR_map_shadow_stack 453
#define __NR_mbind 268
#define __NR_membarrier 356
#define __NR_memfd_create 350
diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
index 37211f5f8c..6b4418bcae 100644
--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
@@ -91,8 +91,11 @@
#define __NR_ftruncate 93
#define __NR_ftruncate64 194
#define __NR_futex 240
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 299
#define __NR_get_mempolicy 275
#define __NR_get_robust_list 312
@@ -170,6 +173,7 @@
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 219
+#define __NR_map_shadow_stack 453
#define __NR_mbind 274
#define __NR_membarrier 378
#define __NR_memfd_create 374
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
index 8093abcc9c..4f9460b1a3 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
@@ -93,8 +93,11 @@
#define __NR_ftruncate 130
#define __NR_ftruncate64 84
#define __NR_futex 142
+#define __NR_futex_requeue 456
#define __NR_futex_time64 422
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 288
#define __NR_get_kernel_syms 223
#define __NR_get_mempolicy 304
@@ -175,6 +178,7 @@
#define __NR_lstat 40
#define __NR_lstat64 132
#define __NR_madvise 75
+#define __NR_map_shadow_stack 453
#define __NR_mbind 303
#define __NR_membarrier 351
#define __NR_memfd_create 348
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
index d25ccfb571..129ce50646 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
@@ -84,7 +84,10 @@
#define __NR_fsync 95
#define __NR_ftruncate 130
#define __NR_futex 142
+#define __NR_futex_requeue 456
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 288
#define __NR_get_kernel_syms 223
#define __NR_get_mempolicy 304
@@ -158,6 +161,7 @@
#define __NR_lstat 40
#define __NR_lstat64 132
#define __NR_madvise 75
+#define __NR_map_shadow_stack 453
#define __NR_mbind 303
#define __NR_membarrier 351
#define __NR_memfd_create 348
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
index c039d5c37f..aac065e7b3 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.6.
-kernel 6.6
+# The list of system calls is current as of Linux 6.7.
+kernel 6.7
FAST_atomic_update
FAST_cmpxchg
@@ -147,8 +147,11 @@ ftime
ftruncate
ftruncate64
futex
+futex_requeue
futex_time64
+futex_wait
futex_waitv
+futex_wake
futimesat
get_kernel_syms
get_mempolicy
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 5e4c9e901c..4fa5b942c5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
@@ -80,7 +80,10 @@
#define __NR_fsync 74
#define __NR_ftruncate 77
#define __NR_futex 202
+#define __NR_futex_requeue 456
+#define __NR_futex_wait 455
#define __NR_futex_waitv 449
+#define __NR_futex_wake 454
#define __NR_futimesat 261
#define __NR_get_kernel_syms 177
#define __NR_get_mempolicy 239
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 dd5e196272..b9db8bc5be 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
@@ -76,7 +76,10 @@
#define __NR_fsync 1073741898
#define __NR_ftruncate 1073741901
#define __NR_futex 1073742026
+#define __NR_futex_requeue 1073742280
+#define __NR_futex_wait 1073742279
#define __NR_futex_waitv 1073742273
+#define __NR_futex_wake 1073742278
#define __NR_futimesat 1073742085
#define __NR_get_mempolicy 1073742063
#define __NR_get_robust_list 1073742355

@ -0,0 +1,756 @@
commit 3de2f8755c6c036dcd0b1f4acd6bcdefe0e775c0
Author: Joseph Myers <josmyers@redhat.com>
Date: Wed Mar 13 13:57:56 2024 +0000
Update syscall lists for Linux 6.8
Linux 6.8 adds five new syscalls. Update syscall-names.list and
regenerate the arch-syscall.h headers with build-many-glibcs.py
update-syscalls.
Tested with build-many-glibcs.py.
Modified for RHEL by: Patsy Griffin <patsy@redhat.com>
diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
index 1713897f85..7ee8a2167a 100644
--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
@@ -122,12 +122,16 @@
#define __NR_lgetxattr 9
#define __NR_linkat 37
#define __NR_listen 201
+#define __NR_listmount 458
#define __NR_listxattr 11
#define __NR_llistxattr 12
#define __NR_lookup_dcookie 18
#define __NR_lremovexattr 15
#define __NR_lseek 62
#define __NR_lsetxattr 6
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_madvise 233
#define __NR_map_shadow_stack 453
#define __NR_mbind 235
@@ -276,6 +280,7 @@
#define __NR_socketpair 199
#define __NR_splice 76
#define __NR_statfs 43
+#define __NR_statmount 457
#define __NR_statx 291
#define __NR_swapoff 225
#define __NR_swapon 224
diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
index 5457d2d8ae..0f4ea7670b 100644
--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
@@ -150,12 +150,16 @@
#define __NR_link 9
#define __NR_linkat 458
#define __NR_listen 106
+#define __NR_listmount 568
#define __NR_listxattr 388
#define __NR_llistxattr 389
#define __NR_lookup_dcookie 406
#define __NR_lremovexattr 392
#define __NR_lseek 19
#define __NR_lsetxattr 383
+#define __NR_lsm_get_self_attr 569
+#define __NR_lsm_list_modules 571
+#define __NR_lsm_set_self_attr 570
#define __NR_lstat 68
#define __NR_lstat64 426
#define __NR_madvise 75
@@ -441,6 +445,7 @@
#define __NR_stat64 425
#define __NR_statfs 328
#define __NR_statfs64 528
+#define __NR_statmount 567
#define __NR_statx 522
#define __NR_swapoff 304
#define __NR_swapon 322
diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
index a66471c83a..90359482a8 100644
--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
@@ -126,12 +126,16 @@
#define __NR_lgetxattr 9
#define __NR_linkat 37
#define __NR_listen 201
+#define __NR_listmount 458
#define __NR_listxattr 11
#define __NR_llistxattr 12
#define __NR_llseek 62
#define __NR_lookup_dcookie 18
#define __NR_lremovexattr 15
#define __NR_lsetxattr 6
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_madvise 233
#define __NR_map_shadow_stack 453
#define __NR_mbind 235
@@ -278,6 +282,7 @@
#define __NR_socketpair 199
#define __NR_splice 76
#define __NR_statfs64 43
+#define __NR_statmount 457
#define __NR_statx 291
#define __NR_swapoff 225
#define __NR_swapon 224
diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
index 74a57f4520..4930167a03 100644
--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
@@ -164,12 +164,16 @@
#define __NR_link 9
#define __NR_linkat 330
#define __NR_listen 284
+#define __NR_listmount 458
#define __NR_listxattr 232
#define __NR_llistxattr 233
#define __NR_lookup_dcookie 249
#define __NR_lremovexattr 236
#define __NR_lseek 19
#define __NR_lsetxattr 227
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 220
@@ -361,6 +365,7 @@
#define __NR_stat64 195
#define __NR_statfs 99
#define __NR_statfs64 266
+#define __NR_statmount 457
#define __NR_statx 397
#define __NR_swapoff 115
#define __NR_swapon 87
diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
index ba7632e018..3f16a29f57 100644
--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
@@ -131,12 +131,16 @@
#define __NR_lgetxattr 9
#define __NR_linkat 37
#define __NR_listen 201
+#define __NR_listmount 458
#define __NR_listxattr 11
#define __NR_llistxattr 12
#define __NR_llseek 62
#define __NR_lookup_dcookie 18
#define __NR_lremovexattr 15
#define __NR_lsetxattr 6
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_madvise 233
#define __NR_map_shadow_stack 453
#define __NR_mbind 235
@@ -291,6 +295,7 @@
#define __NR_socketpair 199
#define __NR_splice 76
#define __NR_statfs64 43
+#define __NR_statmount 457
#define __NR_statx 291
#define __NR_swapoff 225
#define __NR_swapon 224
diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
index 483706de9b..a1b2c819d6 100644
--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
@@ -155,12 +155,16 @@
#define __NR_link 9
#define __NR_linkat 283
#define __NR_listen 32
+#define __NR_listmount 458
#define __NR_listxattr 244
#define __NR_llistxattr 245
#define __NR_lookup_dcookie 223
#define __NR_lremovexattr 248
#define __NR_lseek 19
#define __NR_lsetxattr 239
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 84
#define __NR_lstat64 198
#define __NR_madvise 119
@@ -339,6 +343,7 @@
#define __NR_stat64 101
#define __NR_statfs 99
#define __NR_statfs64 298
+#define __NR_statmount 457
#define __NR_statx 349
#define __NR_stime 25
#define __NR_swapoff 115
diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
index 21c1308bb3..cc775432d6 100644
--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
@@ -176,6 +176,7 @@
#define __NR_link 9
#define __NR_linkat 303
#define __NR_listen 363
+#define __NR_listmount 458
#define __NR_listxattr 232
#define __NR_llistxattr 233
#define __NR_lock 53
@@ -183,6 +184,9 @@
#define __NR_lremovexattr 236
#define __NR_lseek 19
#define __NR_lsetxattr 227
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 219
@@ -386,6 +390,7 @@
#define __NR_stat64 195
#define __NR_statfs 99
#define __NR_statfs64 268
+#define __NR_statmount 457
#define __NR_statx 383
#define __NR_stime 25
#define __NR_stty 31
diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
index 6d788e3440..79f277dd5b 100644
--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
@@ -171,12 +171,16 @@
#define __NR_link 9
#define __NR_linkat 296
#define __NR_listen 360
+#define __NR_listmount 458
#define __NR_listxattr 229
#define __NR_llistxattr 230
#define __NR_lookup_dcookie 248
#define __NR_lremovexattr 233
#define __NR_lseek 19
#define __NR_lsetxattr 224
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 238
@@ -373,6 +377,7 @@
#define __NR_stat64 195
#define __NR_statfs 99
#define __NR_statfs64 263
+#define __NR_statmount 457
#define __NR_statx 379
#define __NR_stime 25
#define __NR_swapoff 115
diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
index 91e1630f7b..779d5d5d70 100644
--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
@@ -176,6 +176,7 @@
#define __NR_link 9
#define __NR_linkat 303
#define __NR_listen 348
+#define __NR_listmount 458
#define __NR_listxattr 232
#define __NR_llistxattr 233
#define __NR_lock 53
@@ -183,6 +184,9 @@
#define __NR_lremovexattr 236
#define __NR_lseek 19
#define __NR_lsetxattr 227
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 219
@@ -389,6 +393,7 @@
#define __NR_stat64 195
#define __NR_statfs 99
#define __NR_statfs64 268
+#define __NR_statmount 457
#define __NR_statx 398
#define __NR_stime 25
#define __NR_stty 31
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
index d75af97467..86ffd5ce84 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
@@ -166,6 +166,7 @@
#define __NR_link 4009
#define __NR_linkat 4296
#define __NR_listen 4174
+#define __NR_listmount 4458
#define __NR_listxattr 4230
#define __NR_llistxattr 4231
#define __NR_lock 4053
@@ -173,6 +174,9 @@
#define __NR_lremovexattr 4234
#define __NR_lseek 4019
#define __NR_lsetxattr 4225
+#define __NR_lsm_get_self_attr 4459
+#define __NR_lsm_list_modules 4461
+#define __NR_lsm_set_self_attr 4460
#define __NR_lstat 4107
#define __NR_lstat64 4214
#define __NR_madvise 4218
@@ -362,6 +366,7 @@
#define __NR_stat64 4213
#define __NR_statfs 4099
#define __NR_statfs64 4255
+#define __NR_statmount 4457
#define __NR_statx 4366
#define __NR_stime 4025
#define __NR_stty 4031
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 05bf7d251d..5d37a686e5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
@@ -154,12 +154,16 @@
#define __NR_link 6084
#define __NR_linkat 6259
#define __NR_listen 6049
+#define __NR_listmount 6458
#define __NR_listxattr 6186
#define __NR_llistxattr 6187
#define __NR_lookup_dcookie 6206
#define __NR_lremovexattr 6190
#define __NR_lseek 6008
#define __NR_lsetxattr 6181
+#define __NR_lsm_get_self_attr 6459
+#define __NR_lsm_list_modules 6461
+#define __NR_lsm_set_self_attr 6460
#define __NR_lstat 6006
#define __NR_madvise 6027
#define __NR_map_shadow_stack 6453
@@ -332,6 +336,7 @@
#define __NR_stat 6004
#define __NR_statfs 6134
#define __NR_statfs64 6217
+#define __NR_statmount 6457
#define __NR_statx 6330
#define __NR_swapoff 6163
#define __NR_swapon 6162
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 41ffaf3255..9b1e846e76 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
@@ -145,12 +145,16 @@
#define __NR_link 5084
#define __NR_linkat 5255
#define __NR_listen 5049
+#define __NR_listmount 5458
#define __NR_listxattr 5186
#define __NR_llistxattr 5187
#define __NR_lookup_dcookie 5206
#define __NR_lremovexattr 5190
#define __NR_lseek 5008
#define __NR_lsetxattr 5181
+#define __NR_lsm_get_self_attr 5459
+#define __NR_lsm_list_modules 5461
+#define __NR_lsm_set_self_attr 5460
#define __NR_lstat 5006
#define __NR_madvise 5027
#define __NR_map_shadow_stack 5453
@@ -313,6 +317,7 @@
#define __NR_splice 5263
#define __NR_stat 5004
#define __NR_statfs 5134
+#define __NR_statmount 5457
#define __NR_statx 5326
#define __NR_swapoff 5163
#define __NR_swapon 5162
diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
index d94e7e9ee9..abbc9ab6b0 100644
--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
@@ -130,12 +130,16 @@
#define __NR_lgetxattr 9
#define __NR_linkat 37
#define __NR_listen 201
+#define __NR_listmount 458
#define __NR_listxattr 11
#define __NR_llistxattr 12
#define __NR_llseek 62
#define __NR_lookup_dcookie 18
#define __NR_lremovexattr 15
#define __NR_lsetxattr 6
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_madvise 233
#define __NR_map_shadow_stack 453
#define __NR_mbind 235
@@ -290,6 +294,7 @@
#define __NR_socketpair 199
#define __NR_splice 76
#define __NR_statfs64 43
+#define __NR_statmount 457
#define __NR_statx 291
#define __NR_swapoff 225
#define __NR_swapon 224
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
index b5522e8889..af0d2b121e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
@@ -166,6 +166,7 @@
#define __NR_link 9
#define __NR_linkat 294
#define __NR_listen 329
+#define __NR_listmount 458
#define __NR_listxattr 215
#define __NR_llistxattr 216
#define __NR_lock 53
@@ -173,6 +174,9 @@
#define __NR_lremovexattr 219
#define __NR_lseek 19
#define __NR_lsetxattr 210
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 205
@@ -374,6 +378,7 @@
#define __NR_stat64 195
#define __NR_statfs 99
#define __NR_statfs64 252
+#define __NR_statmount 457
#define __NR_statx 383
#define __NR_stime 25
#define __NR_stty 31
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
index 162d782ae6..a4c70aa7fe 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
@@ -154,6 +154,7 @@
#define __NR_link 9
#define __NR_linkat 294
#define __NR_listen 329
+#define __NR_listmount 458
#define __NR_listxattr 215
#define __NR_llistxattr 216
#define __NR_lock 53
@@ -161,6 +162,9 @@
#define __NR_lremovexattr 219
#define __NR_lseek 19
#define __NR_lsetxattr 210
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_madvise 205
#define __NR_map_shadow_stack 453
@@ -352,6 +356,7 @@
#define __NR_stat 106
#define __NR_statfs 99
#define __NR_statfs64 252
+#define __NR_statmount 457
#define __NR_statx 383
#define __NR_stime 25
#define __NR_stty 31
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
index 013222e5de..7315d164d6 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
@@ -117,12 +117,16 @@
#define __NR_lgetxattr 9
#define __NR_linkat 37
#define __NR_listen 201
+#define __NR_listmount 458
#define __NR_listxattr 11
#define __NR_llistxattr 12
#define __NR_llseek 62
#define __NR_lookup_dcookie 18
#define __NR_lremovexattr 15
#define __NR_lsetxattr 6
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_madvise 233
#define __NR_map_shadow_stack 453
#define __NR_mbind 235
@@ -268,6 +272,7 @@
#define __NR_socketpair 199
#define __NR_splice 76
#define __NR_statfs64 43
+#define __NR_statmount 457
#define __NR_statx 291
#define __NR_swapoff 225
#define __NR_swapon 224
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
index d03dad8200..31a1130db9 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
@@ -122,12 +122,16 @@
#define __NR_lgetxattr 9
#define __NR_linkat 37
#define __NR_listen 201
+#define __NR_listmount 458
#define __NR_listxattr 11
#define __NR_llistxattr 12
#define __NR_lookup_dcookie 18
#define __NR_lremovexattr 15
#define __NR_lseek 62
#define __NR_lsetxattr 6
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_madvise 233
#define __NR_map_shadow_stack 453
#define __NR_mbind 235
@@ -277,6 +281,7 @@
#define __NR_socketpair 199
#define __NR_splice 76
#define __NR_statfs 43
+#define __NR_statmount 457
#define __NR_statx 291
#define __NR_swapoff 225
#define __NR_swapon 224
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 98e6b68b31..cf8569304d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
@@ -171,12 +171,16 @@
#define __NR_link 9
#define __NR_linkat 296
#define __NR_listen 363
+#define __NR_listmount 458
#define __NR_listxattr 230
#define __NR_llistxattr 231
#define __NR_lookup_dcookie 110
#define __NR_lremovexattr 234
#define __NR_lseek 19
#define __NR_lsetxattr 225
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 219
@@ -372,6 +376,7 @@
#define __NR_stat64 195
#define __NR_statfs 99
#define __NR_statfs64 265
+#define __NR_statmount 457
#define __NR_statx 379
#define __NR_stime 25
#define __NR_swapoff 115
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 951fbd7c97..f3536ed03f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
@@ -146,12 +146,16 @@
#define __NR_link 9
#define __NR_linkat 296
#define __NR_listen 363
+#define __NR_listmount 458
#define __NR_listxattr 230
#define __NR_llistxattr 231
#define __NR_lookup_dcookie 110
#define __NR_lremovexattr 234
#define __NR_lseek 19
#define __NR_lsetxattr 225
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_madvise 219
#define __NR_map_shadow_stack 453
@@ -329,6 +333,7 @@
#define __NR_stat 106
#define __NR_statfs 99
#define __NR_statfs64 265
+#define __NR_statmount 457
#define __NR_statx 379
#define __NR_swapoff 115
#define __NR_swapon 87
diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
index 6b4418bcae..0c88bf10c7 100644
--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
@@ -164,12 +164,16 @@
#define __NR_link 9
#define __NR_linkat 303
#define __NR_listen 343
+#define __NR_listmount 458
#define __NR_listxattr 232
#define __NR_llistxattr 233
#define __NR_lookup_dcookie 253
#define __NR_lremovexattr 236
#define __NR_lseek 19
#define __NR_lsetxattr 227
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 107
#define __NR_lstat64 196
#define __NR_madvise 219
@@ -365,6 +369,7 @@
#define __NR_stat64 195
#define __NR_statfs 99
#define __NR_statfs64 268
+#define __NR_statmount 457
#define __NR_statx 383
#define __NR_stime 25
#define __NR_swapoff 115
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
index 4f9460b1a3..19fa614624 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
@@ -169,12 +169,16 @@
#define __NR_link 9
#define __NR_linkat 292
#define __NR_listen 354
+#define __NR_listmount 458
#define __NR_listxattr 178
#define __NR_llistxattr 179
#define __NR_lookup_dcookie 208
#define __NR_lremovexattr 182
#define __NR_lseek 19
#define __NR_lsetxattr 170
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 40
#define __NR_lstat64 132
#define __NR_madvise 75
@@ -370,6 +374,7 @@
#define __NR_stat64 139
#define __NR_statfs 157
#define __NR_statfs64 234
+#define __NR_statmount 457
#define __NR_statx 360
#define __NR_stime 233
#define __NR_swapoff 213
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
index 129ce50646..18516f20cb 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
@@ -152,12 +152,16 @@
#define __NR_link 9
#define __NR_linkat 292
#define __NR_listen 354
+#define __NR_listmount 458
#define __NR_listxattr 178
#define __NR_llistxattr 179
#define __NR_lookup_dcookie 208
#define __NR_lremovexattr 182
#define __NR_lseek 19
#define __NR_lsetxattr 170
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 40
#define __NR_lstat64 132
#define __NR_madvise 75
@@ -339,6 +343,7 @@
#define __NR_stat64 139
#define __NR_statfs 157
#define __NR_statfs64 234
+#define __NR_statmount 457
#define __NR_statx 360
#define __NR_stime 233
#define __NR_swapoff 213
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
index aac065e7b3..6557bcfde4 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.7.
-kernel 6.7
+# The list of system calls is current as of Linux 6.8.
+kernel 6.8
FAST_atomic_update
FAST_cmpxchg
@@ -239,6 +239,7 @@ lgetxattr
link
linkat
listen
+listmount
listxattr
llistxattr
llseek
@@ -247,6 +248,9 @@ lookup_dcookie
lremovexattr
lseek
lsetxattr
+lsm_get_self_attr
+lsm_list_modules
+lsm_set_self_attr
lstat
lstat64
madvise
@@ -593,6 +597,7 @@ stat
stat64
statfs
statfs64
+statmount
statx
stime
stty
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 4fa5b942c5..b122216013 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
@@ -149,12 +149,16 @@
#define __NR_link 86
#define __NR_linkat 265
#define __NR_listen 50
+#define __NR_listmount 458
#define __NR_listxattr 194
#define __NR_llistxattr 195
#define __NR_lookup_dcookie 212
#define __NR_lremovexattr 198
#define __NR_lseek 8
#define __NR_lsetxattr 189
+#define __NR_lsm_get_self_attr 459
+#define __NR_lsm_list_modules 461
+#define __NR_lsm_set_self_attr 460
#define __NR_lstat 6
#define __NR_madvise 28
#define __NR_map_shadow_stack 453
@@ -321,6 +325,7 @@
#define __NR_splice 275
#define __NR_stat 4
#define __NR_statfs 137
+#define __NR_statmount 457
#define __NR_statx 332
#define __NR_swapoff 168
#define __NR_swapon 167
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 b9db8bc5be..3040a47d72 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
@@ -143,12 +143,16 @@
#define __NR_link 1073741910
#define __NR_linkat 1073742089
#define __NR_listen 1073741874
+#define __NR_listmount 1073742282
#define __NR_listxattr 1073742018
#define __NR_llistxattr 1073742019
#define __NR_lookup_dcookie 1073742036
#define __NR_lremovexattr 1073742022
#define __NR_lseek 1073741832
#define __NR_lsetxattr 1073742013
+#define __NR_lsm_get_self_attr 1073742283
+#define __NR_lsm_list_modules 1073742285
+#define __NR_lsm_set_self_attr 1073742284
#define __NR_lstat 1073741830
#define __NR_madvise 1073741852
#define __NR_mbind 1073742061
@@ -312,6 +316,7 @@
#define __NR_splice 1073742099
#define __NR_stat 1073741828
#define __NR_statfs 1073741961
+#define __NR_statmount 1073742281
#define __NR_statx 1073742156
#define __NR_swapoff 1073741992
#define __NR_swapon 1073741991

@ -0,0 +1,28 @@
commit cf0ca8d52e1653d4aa4311a4649af8dc541ce6b4
Author: Joseph Myers <josmyers@redhat.com>
Date: Mon May 20 13:10:31 2024 +0000
Update syscall lists for Linux 6.9
Linux 6.9 has no new syscalls. Update the version number in
syscall-names.list to reflect that it is still current for 6.9.
Tested with build-many-glibcs.py.
Modified for RHEL by: Patsy Griffin <patsy@redhat.com>
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
index 6557bcfde4..672d39eaad 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.8.
-kernel 6.8
+# The list of system calls is current as of Linux 6.9.
+kernel 6.9
FAST_atomic_update
FAST_cmpxchg

@ -0,0 +1,26 @@
From cb8c78b2ffa0b77ae453b2d328d7e2fe5186ef2a Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Tue, 31 Oct 2023 13:32:35 -0300
Subject: linux: Add MMAP_ABOVE4G from Linux 6.6 to sys/mman.h
x86 added the flag (29f890d1050fc099f) for CET enabled.
Also update tst-mman-consts.py test.
Conflicts:
sysdeps/unix/sysv/linux/tst-mman-consts.py
(removed patch to keep alerting about kernel differences)
sysdeps/unix/sysv/linux/x86/bits/mman.h
(adapted to missing __USE_MISC conditional upstream)
diff -rup a/sysdeps/unix/sysv/linux/x86/bits/mman.h b/sysdeps/unix/sysv/linux/x86/bits/mman.h
--- a/sysdeps/unix/sysv/linux/x86/bits/mman.h 2021-08-01 21:33:43.000000000 -0400
+++ b/sysdeps/unix/sysv/linux/x86/bits/mman.h 2024-05-29 14:03:12.426182715 -0400
@@ -26,6 +26,7 @@
/* Other flags. */
#ifdef __USE_MISC
# define MAP_32BIT 0x40 /* Only give out 32-bit addresses. */
+# define MAP_ABOVE4G 0x80 /* Only map above 4GB. */
#endif
#include <bits/mman-map-flags-generic.h>

@ -1,4 +1,4 @@
commit 6ade91c21140d8c803c289932dbfc74537f65a1f commit afe42e935b3ee97bac9a7064157587777259c60e
Author: Florian Weimer <fweimer@redhat.com> Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 3 10:49:40 2024 +0200 Date: Mon Jun 3 10:49:40 2024 +0200
@ -20,10 +20,9 @@ Date: Mon Jun 3 10:49:40 2024 +0200
tls access after dlopen [BZ #19924]"). tls access after dlopen [BZ #19924]").
Reviewed-by: Carlos O'Donell <carlos@redhat.com> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit afe42e935b3ee97bac9a7064157587777259c60e)
diff --git a/elf/dl-tls.c b/elf/dl-tls.c diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 7b3dd9ab60e89ae9..670dbc42fc2e3334 100644 index 7b3dd9ab60..670dbc42fc 100644
--- a/elf/dl-tls.c --- a/elf/dl-tls.c
+++ b/elf/dl-tls.c +++ b/elf/dl-tls.c
@@ -819,7 +819,14 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen) @@ -819,7 +819,14 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)

@ -0,0 +1,499 @@
commit 018f0fc3b818d4d1460a4e2384c24802504b1d20
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jul 1 17:42:04 2024 +0200
elf: Support recursive use of dynamic TLS in interposed malloc
It turns out that quite a few applications use bundled mallocs that
have been built to use global-dynamic TLS (instead of the recommended
initial-exec TLS). The previous workaround from
commit afe42e935b3ee97bac9a7064157587777259c60e ("elf: Avoid some
free (NULL) calls in _dl_update_slotinfo") does not fix all
encountered cases unfortunatelly.
This change avoids the TLS generation update for recursive use
of TLS from a malloc that was called during a TLS update. This
is possible because an interposed malloc has a fixed module ID and
TLS slot. (It cannot be unloaded.) If an initially-loaded module ID
is encountered in __tls_get_addr and the dynamic linker is already
in the middle of a TLS update, use the outdated DTV, thus avoiding
another call into malloc. It's still necessary to update the
DTV to the most recent generation, to get out of the slow path,
which is why the check for recursion is needed.
The bookkeeping is done using a global counter instead of per-thread
flag because TLS access in the dynamic linker is tricky.
All this will go away once the dynamic linker stops using malloc
for TLS, likely as part of a change that pre-allocates all TLS
during pthread_create/dlopen.
Fixes commit d2123d68275acc0f061e73d5f86ca504e0d5a344 ("elf: Fix slow
tls access after dlopen [BZ #19924]").
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
Reworked for RHEL by: Patsy Griffin <patsy@redhat.com>
diff -Nrup a/elf/Makefile b/elf/Makefile
--- a/elf/Makefile 2024-07-09 22:06:30.237752048 -0400
+++ b/elf/Makefile 2024-07-10 14:09:02.996759220 -0400
@@ -423,6 +423,7 @@ tests += \
tst-nodeps2 \
tst-noload \
tst-null-argv \
+ tst-recursive-tls \
tst-relsort1 \
tst-ro-dynamic \
tst-rtld-run-static \
@@ -783,6 +784,23 @@ modules-names = \
tst-nodeps1-mod \
tst-nodeps2-mod \
tst-null-argv-lib \
+ tst-recursive-tlsmallocmod \
+ tst-recursive-tlsmod0 \
+ tst-recursive-tlsmod1 \
+ tst-recursive-tlsmod2 \
+ tst-recursive-tlsmod3 \
+ tst-recursive-tlsmod4 \
+ tst-recursive-tlsmod5 \
+ tst-recursive-tlsmod6 \
+ tst-recursive-tlsmod7 \
+ tst-recursive-tlsmod8 \
+ tst-recursive-tlsmod9 \
+ tst-recursive-tlsmod10 \
+ tst-recursive-tlsmod11 \
+ tst-recursive-tlsmod12 \
+ tst-recursive-tlsmod13 \
+ tst-recursive-tlsmod14 \
+ tst-recursive-tlsmod15 \
tst-relsort1mod1 \
tst-relsort1mod2 \
tst-ro-dynamic-mod \
@@ -2725,3 +2743,11 @@ CFLAGS-tst-tlsgap-mod0.c += -mtls-dialec
CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=gnu2
CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=gnu2
endif
+
+$(objpfx)tst-recursive-tls: $(objpfx)tst-recursive-tlsmallocmod.so
+# More objects than DTV_SURPLUS, to trigger DTV reallocation.
+$(objpfx)tst-recursive-tls.out: \
+ $(patsubst %,$(objpfx)tst-recursive-tlsmod%.so, \
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
+$(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
+ $(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 670dbc42fc..3d221273f1 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -75,6 +75,31 @@
/* Default for dl_tls_static_optional. */
#define OPTIONAL_TLS 512
+/* Used to count the number of threads currently executing dynamic TLS
+ updates. Used to avoid recursive malloc calls in __tls_get_addr
+ for an interposed malloc that uses global-dynamic TLS (which is not
+ recommended); see _dl_tls_allocate_active checks. This could be a
+ per-thread flag, but would need TLS access in the dynamic linker. */
+unsigned int _dl_tls_threads_in_update;
+
+static inline void
+_dl_tls_allocate_begin (void)
+{
+ atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, 1);
+}
+
+static inline void
+_dl_tls_allocate_end (void)
+{
+ atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, -1);
+}
+
+static inline bool
+_dl_tls_allocate_active (void)
+{
+ return atomic_load_relaxed (&_dl_tls_threads_in_update) > 0;
+}
+
/* Compute the static TLS surplus based on the namespace count and the
TLS space that can be used for optimizations. */
static inline int
@@ -425,12 +450,18 @@ _dl_allocate_tls_storage (void)
size += TLS_PRE_TCB_SIZE;
#endif
- /* Perform the allocation. Reserve space for the required alignment
- and the pointer to the original allocation. */
+ /* Reserve space for the required alignment and the pointer to the
+ original allocation. */
size_t alignment = GLRO (dl_tls_static_align);
+
+ /* Perform the allocation. */
+ _dl_tls_allocate_begin ();
void *allocated = malloc (size + alignment + sizeof (void *));
if (__glibc_unlikely (allocated == NULL))
- return NULL;
+ {
+ _dl_tls_allocate_end ();
+ return NULL;
+ }
/* Perform alignment and allocate the DTV. */
#if TLS_TCB_AT_TP
@@ -466,6 +497,8 @@ _dl_allocate_tls_storage (void)
result = allocate_dtv (result);
if (result == NULL)
free (allocated);
+
+ _dl_tls_allocate_end ();
return result;
}
@@ -483,6 +516,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
size_t newsize = max_modid + DTV_SURPLUS;
size_t oldsize = dtv[-1].counter;
+ _dl_tls_allocate_begin ();
if (dtv == GL(dl_initial_dtv))
{
/* This is the initial dtv that was either statically allocated in
@@ -502,6 +536,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
if (newp == NULL)
oom ();
}
+ _dl_tls_allocate_end ();
newp[0].counter = newsize;
@@ -676,7 +711,9 @@ allocate_dtv_entry (size_t alignment, size_t size)
if (powerof2 (alignment) && alignment <= _Alignof (max_align_t))
{
/* The alignment is supported by malloc. */
+ _dl_tls_allocate_begin ();
void *ptr = malloc (size);
+ _dl_tls_allocate_end ();
return (struct dtv_pointer) { ptr, ptr };
}
@@ -688,7 +725,10 @@ allocate_dtv_entry (size_t alignment, size_t size)
/* Perform the allocation. This is the pointer we need to free
later. */
+ _dl_tls_allocate_begin ();
void *start = malloc (alloc_size);
+ _dl_tls_allocate_end ();
+
if (start == NULL)
return (struct dtv_pointer) {};
@@ -826,7 +866,11 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)
free implementation. Checking here papers over at
least some dynamic TLS usage by interposed mallocs. */
if (dtv[modid].pointer.to_free != NULL)
- free (dtv[modid].pointer.to_free);
+ {
+ _dl_tls_allocate_begin ();
+ free (dtv[modid].pointer.to_free);
+ _dl_tls_allocate_end ();
+ }
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[modid].pointer.to_free = NULL;
@@ -956,10 +1000,22 @@ __tls_get_addr (GET_ADDR_ARGS)
size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
if (__glibc_unlikely (dtv[0].counter != gen))
{
- /* 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);
+ if (_dl_tls_allocate_active ()
+ && GET_ADDR_MODULE < _dl_tls_initial_modid_limit)
+ /* This is a reentrant __tls_get_addr call, but we can
+ satisfy it because it's an initially-loaded module ID.
+ These TLS slotinfo slots do not change, so the
+ out-of-date generation counter does not matter. However,
+ if not in a TLS update, still update_get_addr below, to
+ get off the slow path eventually. */
+ ;
+ else
+ {
+ /* 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;
@@ -969,7 +1025,7 @@ __tls_get_addr (GET_ADDR_ARGS)
return (char *) p + GET_ADDR_OFFSET;
}
-#endif
+#endif /* SHARED */
/* Look up the module's TLS block as for __tls_get_addr,
@@ -1018,6 +1074,25 @@ _dl_tls_get_addr_soft (struct link_map *l)
return data;
}
+size_t _dl_tls_initial_modid_limit;
+
+void
+_dl_tls_initial_modid_limit_setup (void)
+{
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+ size_t idx;
+ for (idx = 0; idx < listp->len; ++idx)
+ {
+ struct link_map *l = listp->slotinfo[idx].map;
+ if (l == NULL
+ /* The object can be unloaded, so its modid can be
+ reassociated. */
+ || !(l->l_type == lt_executable || l->l_type == lt_library))
+ break;
+ }
+ _dl_tls_initial_modid_limit = idx;
+}
+
void
_dl_add_to_slotinfo (struct link_map *l, bool do_add)
@@ -1050,9 +1125,11 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
the first slot. */
assert (idx == 0);
+ _dl_tls_allocate_begin ();
listp = (struct dtv_slotinfo_list *)
malloc (sizeof (struct dtv_slotinfo_list)
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+ _dl_tls_allocate_end ();
if (listp == NULL)
{
/* We ran out of memory while resizing the dtv slotinfo list. */
diff --git a/elf/rtld.c b/elf/rtld.c
index e9525ea987..6352ba76c5 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -788,6 +788,8 @@ init_tls (size_t naudit)
_dl_fatal_printf ("\
cannot allocate TLS data structures for initial thread\n");
+ _dl_tls_initial_modid_limit_setup ();
+
/* Store for detection of the special case by __tls_get_addr
so it knows not to pass this dtv to the normal realloc. */
GL(dl_initial_dtv) = GET_DTV (tcbp);
diff --git a/elf/tst-recursive-tls.c b/elf/tst-recursive-tls.c
new file mode 100644
index 0000000000..716d1f783a
--- /dev/null
+++ b/elf/tst-recursive-tls.c
@@ -0,0 +1,60 @@
+/* Test with interposed malloc with dynamic TLS.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+/* Defined in tst-recursive-tlsmallocmod.so. */
+extern __thread unsigned int malloc_subsytem_counter;
+
+static int
+do_test (void)
+{
+ /* 16 is large enough to exercise the DTV resizing case. */
+ void *handles[16];
+
+ for (unsigned int i = 0; i < array_length (handles); ++i)
+ {
+ /* Re-use the TLS slot for module 0. */
+ if (i > 0)
+ xdlclose (handles[0]);
+
+ char soname[30];
+ snprintf (soname, sizeof (soname), "tst-recursive-tlsmod%u.so", i);
+ handles[i] = xdlopen (soname, RTLD_NOW);
+
+ if (i > 0)
+ {
+ handles[0] = xdlopen ("tst-recursive-tlsmod0.so", RTLD_NOW);
+ int (*fptr) (void) = xdlsym (handles[0], "get_threadvar_0");
+ /* May trigger TLS storage allocation using malloc. */
+ TEST_COMPARE (fptr (), 0);
+ }
+ }
+
+ for (unsigned int i = 0; i < array_length (handles); ++i)
+ xdlclose (handles[i]);
+
+ printf ("info: malloc subsystem calls: %u\n", malloc_subsytem_counter);
+ TEST_VERIFY (malloc_subsytem_counter > 0);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-recursive-tlsmallocmod.c b/elf/tst-recursive-tlsmallocmod.c
new file mode 100644
index 0000000000..c24e9945d1
--- /dev/null
+++ b/elf/tst-recursive-tlsmallocmod.c
@@ -0,0 +1,64 @@
+/* Interposed malloc with dynamic TLS.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <dlfcn.h>
+
+__thread unsigned int malloc_subsytem_counter;
+
+static __typeof (malloc) *malloc_fptr;
+static __typeof (free) *free_fptr;
+static __typeof (calloc) *calloc_fptr;
+static __typeof (realloc) *realloc_fptr;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ malloc_fptr = dlsym (RTLD_NEXT, "malloc");
+ free_fptr = dlsym (RTLD_NEXT, "free");
+ calloc_fptr = dlsym (RTLD_NEXT, "calloc");
+ realloc_fptr = dlsym (RTLD_NEXT, "realloc");
+}
+
+void *
+malloc (size_t size)
+{
+ ++malloc_subsytem_counter;
+ return malloc_fptr (size);
+}
+
+void
+free (void *ptr)
+{
+ ++malloc_subsytem_counter;
+ return free_fptr (ptr);
+}
+
+void *
+calloc (size_t a, size_t b)
+{
+ ++malloc_subsytem_counter;
+ return calloc_fptr (a, b);
+}
+
+void *
+realloc (void *ptr, size_t size)
+{
+ ++malloc_subsytem_counter;
+ return realloc_fptr (ptr, size);
+}
diff --git a/elf/tst-recursive-tlsmodN.c b/elf/tst-recursive-tlsmodN.c
new file mode 100644
index 0000000000..bb7592aee6
--- /dev/null
+++ b/elf/tst-recursive-tlsmodN.c
@@ -0,0 +1,28 @@
+/* Test module with global-dynamic TLS. Used to trigger DTV reallocation.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* Compiled with VAR and FUNC set via -D. FUNC requires some
+ relocation against TLS variable VAR. */
+
+__thread int VAR;
+
+int
+FUNC (void)
+{
+ return VAR;
+}
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 50f58a60e3..656e8a3fa0 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1256,6 +1256,20 @@ extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid,
size_t gen)
attribute_hidden;
+/* The last TLS module ID that is initially loaded, plus 1. TLS
+ addresses for modules with IDs lower than that can be obtained from
+ the DTV even if its generation is outdated. */
+extern size_t _dl_tls_initial_modid_limit attribute_hidden attribute_relro;
+
+/* Compute _dl_tls_initial_modid_limit. To be called after initial
+ relocation. */
+void _dl_tls_initial_modid_limit_setup (void) attribute_hidden;
+
+/* Number of threads currently in a TLS update. This is used to
+ detect reentrant __tls_get_addr calls without a per-thread
+ flag. */
+extern unsigned int _dl_tls_threads_in_update attribute_hidden;
+
/* Look up the module's TLS block as for __tls_get_addr,
but never touch anything. Return null if it's not allocated yet. */
extern void *_dl_tls_get_addr_soft (struct link_map *l) attribute_hidden;
diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
index 869023bbba..b3c1e4fcd7 100644
--- a/sysdeps/x86_64/dl-tls.c
+++ b/sysdeps/x86_64/dl-tls.c
@@ -41,7 +41,10 @@ __tls_get_addr_slow (GET_ADDR_ARGS)
dtv_t *dtv = THREAD_DTV ();
size_t gen = atomic_load_acquire (&GL(dl_tls_generation));
- if (__glibc_unlikely (dtv[0].counter != gen))
+ if (__glibc_unlikely (dtv[0].counter != gen)
+ /* See comment in __tls_get_addr in elf/dl-tls.c. */
+ && !(_dl_tls_allocate_active ()
+ && GET_ADDR_MODULE < _dl_tls_initial_modid_limit))
return update_get_addr (GET_ADDR_PARAM, gen);
return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);

@ -0,0 +1,44 @@
commit 0e16db440cc73d2cdd94e439c0efa1ec43d92b2a
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Aug 13 15:52:34 2024 +0200
manual: Document generic printf error codes
Describe EOVERFLOW, ENOMEN, EILSEQ.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/manual/stdio.texi b/manual/stdio.texi
index 567f6780011f9db1..41298b87a4a6c7d9 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -2318,6 +2318,29 @@ the easiest way to make sure you have all the right prototypes is to
just include @file{stdio.h}.
@pindex stdio.h
+The @code{printf} family shares the error codes listed below.
+Individual functions may report additional @code{errno} values if they
+fail.
+
+@table @code
+@item EOVERFLOW
+The number of written bytes would have exceeded @code{INT_MAX}, and thus
+could not be represented in the return type @code{int}.
+
+@item ENOMEM
+The function could not allocate memory during processing. Long argument
+lists and certain floating point conversions may require memory
+allocation, as does initialization of an output stream upon first use.
+
+@item EILSEQ
+POSIX specifies this error code should be used if a wide character is
+encountered that does not have a matching valid character. @Theglibc{}
+always performs transliteration, using a replacement character if
+necessary, so this error condition cannot occur on output. However,
+@theglibc{} uses @code{EILSEQ} to indicate that an input character
+sequence (wide or multi-byte) could not be converted successfully.
+@end table
+
@deftypefun int printf (const char *@var{template}, @dots{})
@standards{ISO, stdio.h}
@safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{}}@acunsafe{@acsmem{} @aculock{} @acucorrupt{}}}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save