From c3fda489cfdb2260f9fec706e6fd7259858c4467 Mon Sep 17 00:00:00 2001 From: Tom Honermann Date: Sun, 24 Jul 2022 01:11:43 -0400 Subject: stdlib: Suppress gcc diagnostic that char8_t is a keyword in C++20 in uchar.h. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc 13 issues the following diagnostic for the uchar.h header when the -Wc++20-compat option is enabled in C++ modes that do not enable char8_t as a builtin type (C++17 and earlier by default; subject to _GNU_SOURCE and the gcc -f[no-]char8_t option). warning: identifier ‘char8_t’ is a keyword in C++20 [-Wc++20-compat] This change modifies the uchar.h header to suppress the diagnostic through the use of '#pragma GCC diagnostic' directives for gcc 10 and later (the -Wc++20-compat option was added in gcc version 10). Unfortunately, a bug in gcc currently prevents those directives from having the intended effect as reported at https://gcc.gnu.org/PR106423. A patch for that issue has been submitted and is available in the email thread archive linked below. https://gcc.gnu.org/pipermail/gcc-patches/2022-July/598736.html (cherry picked from commit 825f84f133bd840347dc49229b6d831f07d04775) --- wcsmbs/uchar.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h index c37e8619a0..5f7139f279 100644 --- a/wcsmbs/uchar.h +++ b/wcsmbs/uchar.h @@ -34,8 +34,16 @@ /* Declare the C2x char8_t typedef in C2x modes, but only if the C++ __cpp_char8_t feature test macro is not defined. */ #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t +#if __GNUC_PREREQ (10, 0) && defined __cplusplus +/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wc++20-compat" +#endif /* Define the 8-bit character type. */ typedef unsigned char char8_t; +#if __GNUC_PREREQ (10, 0) && defined __cplusplus +# pragma GCC diagnostic pop +#endif #endif #ifndef __USE_ISOCXX11 -- cgit 1.4.1 From 33f1b4c1452b33991e670f636ebe98b90a405e10 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 29 Jul 2022 10:50:56 -0700 Subject: wcsmbs: Add missing test-c8rtomb/test-mbrtoc8 dependency Make test-c8rtomb.out and test-mbrtoc8.out depend on $(gen-locales) for xsetlocale (LC_ALL, "de_DE.UTF-8"); xsetlocale (LC_ALL, "zh_HK.BIG5-HKSCS"); Reviewed-by: Sunil K Pandey Reviewed-by: Carlos O'Donell (cherry picked from commit e03f5ccd6cc8f829416156eac75acee501626c1f) --- wcsmbs/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile index e6b9e8743a..3d19d5556f 100644 --- a/wcsmbs/Makefile +++ b/wcsmbs/Makefile @@ -73,6 +73,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales) $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales) $(objpfx)tst-c16-surrogate.out: $(gen-locales) $(objpfx)tst-c32-state.out: $(gen-locales) +$(objpfx)test-c8rtomb.out: $(gen-locales) +$(objpfx)test-mbrtoc8.out: $(gen-locales) endif $(objpfx)tst-wcstod-round: $(libm) -- cgit 1.4.1 From c74bb93cfdb04d49155b0e30983a3c866167bbca Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 4 Aug 2022 17:54:48 +0200 Subject: dlfcn: Pass caller pointer to static dlopen implementation (bug 29446) Fixes commit 0c1c3a771eceec46e66ce1183cf988e2303bd373 ("dlfcn: Move dlopen into libc"). (cherry picked from commit ed0185e4129130cbe081c221efb758fb400623ce) --- NEWS | 7 +++++++ dlfcn/dlopen.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index f61e521fc8..15f3dd2cdb 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,13 @@ See the end for copying conditions. Please send GNU C library bug reports via using `glibc' in the "product" field. + +Version 2.36.1 + +The following bugs are resolved with this release: + + [29446] _dlopen now ignores dl_caller argument in static mode + Version 2.36 diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c index 2696dde4b1..9b07b4e132 100644 --- a/dlfcn/dlopen.c +++ b/dlfcn/dlopen.c @@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1); void * __dlopen (const char *file, int mode, void *dl_caller) { - return dlopen_implementation (file, mode, RETURN_ADDRESS (0)); + return dlopen_implementation (file, mode, dl_caller); } void * -- cgit 1.4.1 From ac47d8f6cf9744139adb12f540fb9cc610cac579 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Tue, 2 Aug 2022 21:05:07 +0000 Subject: Update syscall lists for Linux 5.19 Linux 5.19 has no new syscalls, but enables memfd_secret in the uapi headers for RISC-V. Update the version number in syscall-names.list to reflect that it is still current for 5.19 and regenerate the arch-syscall.h headers with build-many-glibcs.py update-syscalls. Tested with build-many-glibcs.py. (cherry picked from commit fccadcdf5bed7ee67a6cef4714e0b477d6c8472c) --- sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h | 1 + sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h | 1 + sysdeps/unix/sysv/linux/syscall-names.list | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h index bf4be80f8d..202520ee25 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h @@ -122,6 +122,7 @@ #define __NR_mbind 235 #define __NR_membarrier 283 #define __NR_memfd_create 279 +#define __NR_memfd_secret 447 #define __NR_migrate_pages 238 #define __NR_mincore 232 #define __NR_mkdirat 34 diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h index d656aedcc2..4e65f337d4 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h @@ -127,6 +127,7 @@ #define __NR_mbind 235 #define __NR_membarrier 283 #define __NR_memfd_create 279 +#define __NR_memfd_secret 447 #define __NR_migrate_pages 238 #define __NR_mincore 232 #define __NR_mkdirat 34 diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list index 6c7b2f7011..028ad3107a 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.18. -kernel 5.18 +# The list of system calls is current as of Linux 5.19. +kernel 5.19 FAST_atomic_update FAST_cmpxchg -- cgit 1.4.1 From 302bc33bc53c787da6e74162a7092e9c0fb964a8 Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Mon, 8 Aug 2022 11:26:22 +0800 Subject: elf: Replace `strcpy` call with `memcpy` [BZ #29454] GCC normally does this optimization for us in strlen_pass::handle_builtin_strcpy but only for optimized build. To avoid needing to include strcpy.S in the rtld build to support the debug build, just do the optimization by hand. (cherry picked from commit 483cfe1a6a33d6335b1901581b41040d2d412511) --- elf/dl-cache.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/elf/dl-cache.c b/elf/dl-cache.c index 8bbf110d02..b97c17b3a9 100644 --- a/elf/dl-cache.c +++ b/elf/dl-cache.c @@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name) we are accessing. Therefore we must make the copy of the mapping data without using malloc. */ char *temp; - temp = alloca (strlen (best) + 1); - strcpy (temp, best); + size_t best_len = strlen (best) + 1; + temp = alloca (best_len); + memcpy (temp, best, best_len); return __strdup (temp); } -- cgit 1.4.1 From e982657073c4db21459ffd9e17bc505b1d64b876 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 15 Aug 2022 16:43:59 +0200 Subject: Linux: Terminate subprocess on late failure in tst-pidfd (bug 29485) Reviewed-by: Carlos O'Donell (cherry picked from commit f82e05ebb295cadd35f7372f652c72264da810ad) --- NEWS | 1 + sysdeps/unix/sysv/linux/tst-pidfd.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 15f3dd2cdb..f8fb8db510 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ Version 2.36.1 The following bugs are resolved with this release: [29446] _dlopen now ignores dl_caller argument in static mode + [29485] Linux: Terminate subprocess on late failure in tst-pidfd Version 2.36 diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c index 037af22290..5711d1c312 100644 --- a/sysdeps/unix/sysv/linux/tst-pidfd.c +++ b/sysdeps/unix/sysv/linux/tst-pidfd.c @@ -147,8 +147,11 @@ do_test (void) may be denied if the process doesn't have CAP_SYS_PTRACE or if a LSM security_ptrace_access_check denies access. */ if (fd == -1 && errno == EPERM) - FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, " - "skipping test"); + { + TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0); + FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, " + "skipping test"); + } TEST_VERIFY (fd > 0); char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd); -- cgit 1.4.1 From 8b139cd4f1074ae0d95d9bff60db283a1ed72734 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 22 Aug 2022 11:04:47 +0200 Subject: alpha: Fix generic brk system call emulation in __brk_call (bug 29490) The kernel special-cases the zero argument for alpha brk, and we can use that to restore the generic Linux error handling behavior. Fixes commit b57ab258c1140bc45464b4b9908713e3e0ee35aa ("Linux: Introduce __brk_call for invoking the brk system call"). (cherry picked from commit e7ad26ee3cb74e61d0637c888f24dd478d77af58) --- NEWS | 1 + sysdeps/unix/sysv/linux/alpha/brk_call.h | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index f8fb8db510..becab3ade9 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ The following bugs are resolved with this release: [29446] _dlopen now ignores dl_caller argument in static mode [29485] Linux: Terminate subprocess on late failure in tst-pidfd + [29490] alpha: New __brk_call implementation is broken Version 2.36 diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h index b8088cf13f..0b851b6c86 100644 --- a/sysdeps/unix/sysv/linux/alpha/brk_call.h +++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h @@ -21,8 +21,7 @@ __brk_call (void *addr) { unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr); if (result == -ENOMEM) - /* Mimic the default error reporting behavior. */ - return addr; - else - return (void *) result; + /* Mimic the generic error reporting behavior. */ + result = INTERNAL_SYSCALL_CALL (brk, 0); + return (void *) result; } -- cgit 1.4.1 From d13a7a6f100576b1e30dc044b2e0c4cbcb6196f6 Mon Sep 17 00:00:00 2001 From: Arjun Shankar Date: Tue, 2 Aug 2022 11:10:25 +0200 Subject: socket: Check lengths before advancing pointer in CMSG_NXTHDR The inline and library functions that the CMSG_NXTHDR macro may expand to increment the pointer to the header before checking the stride of the increment against available space. Since C only allows incrementing pointers to one past the end of an array, the increment must be done after a length check. This commit fixes that and includes a regression test for CMSG_FIRSTHDR and CMSG_NXTHDR. The Linux, Hurd, and generic headers are all changed. Tested on Linux on armv7hl, i686, x86_64, aarch64, ppc64le, and s390x. [BZ #28846] Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 9c443ac4559a47ed99859bd80d14dc4b6dd220a1) --- bits/socket.h | 40 ++++++++++++--- socket/Makefile | 1 + socket/tst-cmsghdr-skeleton.c | 92 +++++++++++++++++++++++++++++++++++ socket/tst-cmsghdr.c | 56 +++++++++++++++++++++ sysdeps/mach/hurd/bits/socket.h | 40 ++++++++++++--- sysdeps/unix/sysv/linux/bits/socket.h | 40 ++++++++++++--- sysdeps/unix/sysv/linux/cmsg_nxthdr.c | 36 +++++++++++--- 7 files changed, 276 insertions(+), 29 deletions(-) create mode 100644 socket/tst-cmsghdr-skeleton.c create mode 100644 socket/tst-cmsghdr.c diff --git a/bits/socket.h b/bits/socket.h index 2b99dea33b..aac8c49b00 100644 --- a/bits/socket.h +++ b/bits/socket.h @@ -245,6 +245,12 @@ struct cmsghdr + CMSG_ALIGN (sizeof (struct cmsghdr))) #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +/* Given a length, return the additional padding necessary such that + len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ +#define __CMSG_PADDING(len) ((sizeof (size_t) \ + - ((len) & (sizeof (size_t) - 1))) \ + & (sizeof (size_t) - 1)) + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg) __THROW; #ifdef __USE_EXTERN_INLINES @@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, _EXTERN_INLINE struct cmsghdr * __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) { + /* We may safely assume that __cmsg lies between __mhdr->msg_control and + __mhdr->msg_controllen because the user is required to obtain the first + cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs + via CMSG_NXTHDR, setting lengths along the way. However, we don't yet + trust the value of __cmsg->cmsg_len and therefore do not use it in any + pointer arithmetic until we check its value. */ + + unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; + unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; + + size_t __size_needed = sizeof (struct cmsghdr) + + __CMSG_PADDING (__cmsg->cmsg_len); + + /* The current header is malformed, too small to be a full header. */ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) - /* The kernel header does this so there may be a reason. */ return (struct cmsghdr *) 0; + /* There isn't enough space between __cmsg and the end of the buffer to + hold the current cmsg *and* the next one. */ + if (((size_t) + (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) + < __size_needed) + || ((size_t) + (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr + - __size_needed) + < __cmsg->cmsg_len)) + + return (struct cmsghdr *) 0; + + /* Now, we trust cmsg_len and can use it to find the next header. */ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)); - if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control - + __mhdr->msg_controllen) - || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) - > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) - /* No more entries. */ - return (struct cmsghdr *) 0; return __cmsg; } #endif /* Use `extern inline'. */ diff --git a/socket/Makefile b/socket/Makefile index 156eec6c85..2bde78387f 100644 --- a/socket/Makefile +++ b/socket/Makefile @@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \ tests := \ tst-accept4 \ tst-sockopt \ + tst-cmsghdr \ # tests tests-internal := \ diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c new file mode 100644 index 0000000000..4c6898569b --- /dev/null +++ b/socket/tst-cmsghdr-skeleton.c @@ -0,0 +1,92 @@ +/* Test ancillary data header creation. + Copyright (C) 2022 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 + . */ + +/* We use the preprocessor to generate the function/macro tests instead of + using indirection because having all the macro expansions alongside + each other lets the compiler warn us about suspicious pointer + arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */ + +#include + +#define RUN_TEST_CONCAT(suffix) run_test_##suffix +#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix) + +static void +RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void) +{ + struct msghdr m = {0}; + struct cmsghdr *cmsg; + char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0}; + + m.msg_control = cmsgbuf; + m.msg_controllen = sizeof (cmsgbuf); + + /* First header should point to the start of the buffer. */ + cmsg = CMSG_FIRSTHDR (&m); + TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); + + /* If the first header length consumes the entire buffer, there is no + space remaining for additional headers. */ + cmsg->cmsg_len = sizeof (cmsgbuf); + cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); + TEST_VERIFY_EXIT (cmsg == NULL); + + /* The first header length is so big, using it would cause an overflow. */ + cmsg = CMSG_FIRSTHDR (&m); + TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); + cmsg->cmsg_len = SIZE_MAX; + cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); + TEST_VERIFY_EXIT (cmsg == NULL); + + /* The first header leaves just enough space to hold another header. */ + cmsg = CMSG_FIRSTHDR (&m); + TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); + cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr); + cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); + TEST_VERIFY_EXIT (cmsg != NULL); + + /* The first header leaves space but not enough for another header. */ + cmsg = CMSG_FIRSTHDR (&m); + TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); + cmsg->cmsg_len ++; + cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); + TEST_VERIFY_EXIT (cmsg == NULL); + + /* The second header leaves just enough space to hold another header. */ + cmsg = CMSG_FIRSTHDR (&m); + TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); + cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD)); + cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); + TEST_VERIFY_EXIT (cmsg != NULL); + cmsg->cmsg_len = sizeof (cmsgbuf) + - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */ + - sizeof (struct cmsghdr); + cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); + TEST_VERIFY_EXIT (cmsg != NULL); + + /* The second header leaves space but not enough for another header. */ + cmsg = CMSG_FIRSTHDR (&m); + TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); + cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); + TEST_VERIFY_EXIT (cmsg != NULL); + cmsg->cmsg_len ++; + cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); + TEST_VERIFY_EXIT (cmsg == NULL); + + return; +} diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c new file mode 100644 index 0000000000..68c96d3c9d --- /dev/null +++ b/socket/tst-cmsghdr.c @@ -0,0 +1,56 @@ +/* Test ancillary data header creation. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +#define PAYLOAD "Hello, World!" + +/* CMSG_NXTHDR is a macro that calls an inline function defined in + bits/socket.h. In case the function cannot be inlined, libc.so carries + a copy. Both versions need to be tested. */ + +#define CMSG_NXTHDR_IMPL CMSG_NXTHDR +#include "tst-cmsghdr-skeleton.c" +#undef CMSG_NXTHDR_IMPL + +static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *); + +#define CMSG_NXTHDR_IMPL cmsg_nxthdr +#include "tst-cmsghdr-skeleton.c" +#undef CMSG_NXTHDR_IMPL + +static int +do_test (void) +{ + static void *handle; + + run_test_CMSG_NXTHDR (); + + handle = xdlopen (LIBC_SO, RTLD_LAZY); + cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *)) + xdlsym (handle, "__cmsg_nxthdr"); + + run_test_cmsg_nxthdr (); + + return 0; +} + +#include diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h index 5b35ea81ec..70fce4fb27 100644 --- a/sysdeps/mach/hurd/bits/socket.h +++ b/sysdeps/mach/hurd/bits/socket.h @@ -249,6 +249,12 @@ struct cmsghdr + CMSG_ALIGN (sizeof (struct cmsghdr))) #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +/* Given a length, return the additional padding necessary such that + len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ +#define __CMSG_PADDING(len) ((sizeof (size_t) \ + - ((len) & (sizeof (size_t) - 1))) \ + & (sizeof (size_t) - 1)) + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg) __THROW; #ifdef __USE_EXTERN_INLINES @@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, _EXTERN_INLINE struct cmsghdr * __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) { + /* We may safely assume that __cmsg lies between __mhdr->msg_control and + __mhdr->msg_controllen because the user is required to obtain the first + cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs + via CMSG_NXTHDR, setting lengths along the way. However, we don't yet + trust the value of __cmsg->cmsg_len and therefore do not use it in any + pointer arithmetic until we check its value. */ + + unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; + unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; + + size_t __size_needed = sizeof (struct cmsghdr) + + __CMSG_PADDING (__cmsg->cmsg_len); + + /* The current header is malformed, too small to be a full header. */ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) - /* The kernel header does this so there may be a reason. */ return (struct cmsghdr *) 0; + /* There isn't enough space between __cmsg and the end of the buffer to + hold the current cmsg *and* the next one. */ + if (((size_t) + (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) + < __size_needed) + || ((size_t) + (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr + - __size_needed) + < __cmsg->cmsg_len)) + + return (struct cmsghdr *) 0; + + /* Now, we trust cmsg_len and can use it to find the next header. */ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)); - if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control - + __mhdr->msg_controllen) - || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) - > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) - /* No more entries. */ - return (struct cmsghdr *) 0; return __cmsg; } #endif /* Use `extern inline'. */ diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h index 4f1f810ea1..539b8d7716 100644 --- a/sysdeps/unix/sysv/linux/bits/socket.h +++ b/sysdeps/unix/sysv/linux/bits/socket.h @@ -307,6 +307,12 @@ struct cmsghdr + CMSG_ALIGN (sizeof (struct cmsghdr))) #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +/* Given a length, return the additional padding necessary such that + len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ +#define __CMSG_PADDING(len) ((sizeof (size_t) \ + - ((len) & (sizeof (size_t) - 1))) \ + & (sizeof (size_t) - 1)) + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg) __THROW; #ifdef __USE_EXTERN_INLINES @@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, _EXTERN_INLINE struct cmsghdr * __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) { + /* We may safely assume that __cmsg lies between __mhdr->msg_control and + __mhdr->msg_controllen because the user is required to obtain the first + cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs + via CMSG_NXTHDR, setting lengths along the way. However, we don't yet + trust the value of __cmsg->cmsg_len and therefore do not use it in any + pointer arithmetic until we check its value. */ + + unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; + unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; + + size_t __size_needed = sizeof (struct cmsghdr) + + __CMSG_PADDING (__cmsg->cmsg_len); + + /* The current header is malformed, too small to be a full header. */ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) - /* The kernel header does this so there may be a reason. */ return (struct cmsghdr *) 0; + /* There isn't enough space between __cmsg and the end of the buffer to + hold the current cmsg *and* the next one. */ + if (((size_t) + (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) + < __size_needed) + || ((size_t) + (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr + - __size_needed) + < __cmsg->cmsg_len)) + + return (struct cmsghdr *) 0; + + /* Now, we trust cmsg_len and can use it to find the next header. */ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)); - if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control - + __mhdr->msg_controllen) - || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) - > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) - /* No more entries. */ - return (struct cmsghdr *) 0; return __cmsg; } #endif /* Use `extern inline'. */ diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c index 15b7a3a925..24f72b797a 100644 --- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c +++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c @@ -23,18 +23,38 @@ struct cmsghdr * __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg) { + /* We may safely assume that cmsg lies between mhdr->msg_control and + mhdr->msg_controllen because the user is required to obtain the first + cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs + via CMSG_NXTHDR, setting lengths along the way. However, we don't yet + trust the value of cmsg->cmsg_len and therefore do not use it in any + pointer arithmetic until we check its value. */ + + unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control; + unsigned char * cmsg_ptr = (unsigned char *) cmsg; + + size_t size_needed = sizeof (struct cmsghdr) + + __CMSG_PADDING (cmsg->cmsg_len); + + /* The current header is malformed, too small to be a full header. */ if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr)) - /* The kernel header does this so there may be a reason. */ - return NULL; + return (struct cmsghdr *) 0; + + /* There isn't enough space between cmsg and the end of the buffer to + hold the current cmsg *and* the next one. */ + if (((size_t) + (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr) + < size_needed) + || ((size_t) + (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr + - size_needed) + < cmsg->cmsg_len)) + + return (struct cmsghdr *) 0; + /* Now, we trust cmsg_len and can use it to find the next header. */ cmsg = (struct cmsghdr *) ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)); - if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control - + mhdr->msg_controllen) - || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len) - > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen))) - /* No more entries. */ - return NULL; return cmsg; } libc_hidden_def (__cmsg_nxthdr) -- cgit 1.4.1 From 5c62874f423af93e97b51bc9a57af228a546156f Mon Sep 17 00:00:00 2001 From: Arjun Shankar Date: Mon, 22 Aug 2022 18:21:14 +0200 Subject: NEWS: Add entry for bug 28846 --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index becab3ade9..ae30900bbc 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ Version 2.36.1 The following bugs are resolved with this release: + [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning [29446] _dlopen now ignores dl_caller argument in static mode [29485] Linux: Terminate subprocess on late failure in tst-pidfd [29490] alpha: New __brk_call implementation is broken -- cgit 1.4.1 From 0062e7dd1c3674ece2daca53a898badd28b60421 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 10 Aug 2022 16:24:06 -0300 Subject: glibcextract.py: Add compile_c_snippet It might be used on tests to check if a snippet build with the provided compiler and flags. Reviewed-by: Florian Weimer (cherry picked from commit 841afa116e32b3c7195475769c26bf46fd870d32) --- scripts/glibcextract.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py index 43ab58ffe2..36d204c9b0 100644 --- a/scripts/glibcextract.py +++ b/scripts/glibcextract.py @@ -17,6 +17,7 @@ # License along with the GNU C Library; if not, see # . +import collections import os.path import re import subprocess @@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None, if not allow_extra_2: ret = 1 return ret + +CompileResult = collections.namedtuple("CompileResult", "returncode output") + +def compile_c_snippet(snippet, cc, extra_cc_args=''): + """Compile and return whether the SNIPPET can be build with CC along + EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE + being 0 for success, or the failure value and the compiler output. + """ + with tempfile.TemporaryDirectory() as temp_dir: + c_file_name = os.path.join(temp_dir, 'test.c') + obj_file_name = os.path.join(temp_dir, 'test.o') + with open(c_file_name, 'w') as c_file: + c_file.write(snippet + '\n') + cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name, + c_file_name] + r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + return CompileResult(r.returncode, r.stdout) -- cgit 1.4.1 From 1cc5513114e76083669cba1b11252aad35525e69 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 10 Aug 2022 14:24:44 -0300 Subject: linux: Use compile_c_snippet to check linux/pidfd.h availability Instead of tying to a specific kernel version. Checked on x86_64-linux-gnu. Reviewed-by: Florian Weimer (cherry picked from commit 1542019b69b7ec7b2cd34357af035e406d153631) --- sysdeps/unix/sysv/linux/tst-pidfd-consts.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py index 90cbb9be64..d732173abd 100644 --- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py @@ -33,11 +33,13 @@ def main(): help='C compiler (including options) to use') args = parser.parse_args() - linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) - # Linux started to provide pidfd.h with 5.10. - if linux_version_headers < (5, 10): + if glibcextract.compile_c_snippet( + '#include ', + args.cc).returncode != 0: sys.exit (77) - linux_version_glibc = (5, 18) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) + linux_version_glibc = (5, 19) sys.exit(glibcextract.compare_macro_consts( '#include \n', '#include \n' -- cgit 1.4.1 From 4dad97e2a2e510c6b53a0add29a2188714fcf4ab Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 10 Aug 2022 14:24:45 -0300 Subject: linux: Mimic kernel defition for BLOCK_SIZE To avoid possible warnings if the kernel header is included before sys/mount.h. Reviewed-by: Florian Weimer (cherry picked from commit c68b6044bc7945716431f1adc091b17c39b80a06) --- sysdeps/unix/sysv/linux/sys/mount.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h index f965986ba8..df6b0dbb42 100644 --- a/sysdeps/unix/sysv/linux/sys/mount.h +++ b/sysdeps/unix/sysv/linux/sys/mount.h @@ -27,8 +27,8 @@ #include #include -#define BLOCK_SIZE 1024 #define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE (1< Date: Wed, 10 Aug 2022 14:24:46 -0300 Subject: linux: Use compile_c_snippet to check linux/mount.h availability Checked on x86_64-linux-gnu. Reviewed-by: Florian Weimer (cherry picked from commit e1226cdc6b209539a92d32d5b620ba53fd35abf3) --- sysdeps/unix/sysv/linux/tst-mount-consts.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py index a62f803123..be2ef2daf1 100755 --- a/sysdeps/unix/sysv/linux/tst-mount-consts.py +++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py @@ -33,6 +33,11 @@ def main(): help='C compiler (including options) to use') args = parser.parse_args() + if glibcextract.compile_c_snippet( + '#include ', + args.cc).returncode != 0: + sys.exit (77) + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) # Constants in glibc were updated to match Linux v5.16. When glibc # constants are updated this value should be updated to match the -- cgit 1.4.1 From bb1e8b0ca99b5cbedfae3e6245528a87d95ff3e2 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 10 Aug 2022 14:24:47 -0300 Subject: linux: Fix sys/mount.h usage with kernel headers Now that kernel exports linux/mount.h and includes it on linux/fs.h, its definitions might clash with glibc exports sys/mount.h. To avoid the need to rearrange the Linux header to be always after glibc one, the glibc sys/mount.h is changed to: 1. Undefine the macros also used as enum constants. This covers prior inclusion of (for instance MS_RDONLY). 2. Include based on the usual __has_include check (needs to use __has_include ("linux/mount.h") to paper over GCC bugs. 3. Define enum fsconfig_command only if FSOPEN_CLOEXEC is not defined. (FSOPEN_CLOEXEC should be a very close proxy.) 4. Define struct mount_attr if MOUNT_ATTR_SIZE_VER0 is not defined. (Added in the same commit on the Linux side.) This patch also adds some tests to check if including linux/fs.h and linux/mount.h after and before sys/mount.h does work. Checked on x86_64-linux-gnu. Reviewed-by: Florian Weimer (cherry picked from commit 774058d72942249f71d74e7f2b639f77184160a6) --- sysdeps/unix/sysv/linux/Makefile | 8 ++++ sysdeps/unix/sysv/linux/sys/mount.h | 71 ++++++++++++++++++++++++---- sysdeps/unix/sysv/linux/tst-mount-compile.py | 66 ++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 8 deletions(-) create mode 100755 sysdeps/unix/sysv/linux/tst-mount-compile.py diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index a139a16532..3ceda9fdbf 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py < /dev/null > $@ 2>&1; $(evaluate-test) $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps) +tests-special += $(objpfx)tst-mount-compile.out +$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py + $(sysdeps-linux-python) \ + ../sysdeps/unix/sysv/linux/tst-mount-compile.py \ + $(sysdeps-linux-python-cc) \ + < /dev/null > $@ 2>&1; $(evaluate-test) +$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps) + tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0 endif # $(subdir) == misc diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h index df6b0dbb42..2e3fd6a7fe 100644 --- a/sysdeps/unix/sysv/linux/sys/mount.h +++ b/sysdeps/unix/sysv/linux/sys/mount.h @@ -27,6 +27,13 @@ #include #include +#ifdef __has_include +# if __has_include ("linux/mount.h") +# include "linux/mount.h" +# endif +#endif + + #define BLOCK_SIZE_BITS 10 #define BLOCK_SIZE (1<. + +import argparse +import sys + +import glibcextract + + +def main(): + """The main entry point.""" + parser = argparse.ArgumentParser( + description='Check if glibc provided sys/mount.h can be ' + ' used along related kernel headers.') + parser.add_argument('--cc', metavar='CC', + help='C compiler (including options) to use') + args = parser.parse_args() + + if glibcextract.compile_c_snippet( + '#include ', + args.cc).returncode != 0: + sys.exit (77) + + def check(testname, snippet): + # Add -Werror to catch macro redefinitions and _ISOMAC to avoid + # internal glibc definitions. + r = glibcextract.compile_c_snippet(snippet, args.cc, + '-Werror -D_ISOMAC') + if r.returncode != 0: + print('error: test {}:\n{}'.format(testname, r.output.decode())) + return r.returncode + + status = max( + check("sys/mount.h + linux/mount.h", + "#include \n" + "#include "), + check("sys/mount.h + linux/fs.h", + "#include \n" + "#include "), + check("linux/mount.h + sys/mount.h", + "#include \n" + "#include "), + check("linux/fs.h + sys/mount.h", + "#include \n" + "#include ")) + sys.exit(status) + +if __name__ == '__main__': + main() -- cgit 1.4.1 From 3bd3c612e98a53ce60ed972f5cd2b90628b3cba5 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 16 Aug 2022 09:25:23 +0200 Subject: Linux: Fix enum fsconfig_command detection in The #ifdef FSOPEN_CLOEXEC check did not work because the macro was always defined in this header prior to the check, so that the contents did not matter. Fixes commit 774058d72942249f71d74e7f2b639f77184160a6 ("linux: Fix sys/mount.h usage with kernel headers"). (cherry picked from commit 2955ef4b7c9b56fcd7abfeddef7ee83c60abff98) --- sysdeps/unix/sysv/linux/sys/mount.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h index 2e3fd6a7fe..19841d0738 100644 --- a/sysdeps/unix/sysv/linux/sys/mount.h +++ b/sysdeps/unix/sysv/linux/sys/mount.h @@ -188,9 +188,6 @@ enum }; -/* fsopen flags. */ -#define FSOPEN_CLOEXEC 0x00000001 - /* fsmount flags. */ #define FSMOUNT_CLOEXEC 0x00000001 @@ -261,6 +258,9 @@ enum fsconfig_command }; #endif +/* fsopen flags. */ +#define FSOPEN_CLOEXEC 0x00000001 + /* open_tree flags. */ #define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ #define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ -- cgit 1.4.1 From b0e7888d1fa2dbd2d9e1645ec8c796abf78880b9 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Sun, 28 Aug 2022 16:52:53 -0300 Subject: syslog: Fix large messages (BZ#29536) The a583b6add407c17cd change did not handle large messages that would require a heap allocation correctly, where the message itself is not take in consideration. This patch fixes it and extend the tst-syslog to check for large messages as well. Checked on x86_64-linux-gnu. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 52a5be0df411ef3ff45c10c7c308cb92993d15b1) --- misc/syslog.c | 18 ++++--- misc/tst-syslog.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 142 insertions(+), 28 deletions(-) diff --git a/misc/syslog.c b/misc/syslog.c index 554089bfc4..b88f66c835 100644 --- a/misc/syslog.c +++ b/misc/syslog.c @@ -193,28 +193,32 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc, mode_flags); if (0 <= vl && vl < sizeof bufs - l) - { - buf = bufs; - bufsize = l + vl; - } + buf = bufs; + bufsize = l + vl; va_end (apc); } if (buf == NULL) { - buf = malloc (l * sizeof (char)); + buf = malloc ((bufsize + 1) * sizeof (char)); if (buf != NULL) { /* Tell the cancellation handler to free this buffer. */ clarg.buf = buf; if (has_ts) - __snprintf (bufs, sizeof bufs, + __snprintf (buf, l + 1, SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); else - __snprintf (bufs, sizeof bufs, + __snprintf (buf, l + 1, SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); + + va_list apc; + va_copy (apc, ap); + __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, + mode_flags); + va_end (apc); } else { diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c index e550d15796..1d332ece53 100644 --- a/misc/tst-syslog.c +++ b/misc/tst-syslog.c @@ -68,21 +68,19 @@ static const int priorities[] = LOG_DEBUG }; -enum - { - ident_length = 64, - msg_length = 64 - }; +#define IDENT_LENGTH 64 +#define MSG_LENGTH 1024 #define SYSLOG_MSG_BASE "syslog_message" #define OPENLOG_IDENT "openlog_ident" +static char large_message[MSG_LENGTH]; struct msg_t { int priority; int facility; - char ident[ident_length]; - char msg[msg_length]; + char ident[IDENT_LENGTH]; + char msg[MSG_LENGTH]; pid_t pid; }; @@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options, return true; } +static void +send_syslog_large (int options) +{ + int facility = LOG_USER; + int priority = LOG_INFO; + + syslog (facility | priority, "%s %d %d", large_message, facility, + priority); +} + +static void +send_vsyslog_large (int options) +{ + int facility = LOG_USER; + int priority = LOG_INFO; + + call_vsyslog (facility | priority, "%s %d %d", large_message, facility, + priority); +} + +static bool +check_syslog_message_large (const struct msg_t *msg, int msgnum, int options, + pid_t pid) +{ + TEST_COMPARE (msg->facility, LOG_USER); + TEST_COMPARE (msg->priority, LOG_INFO); + TEST_COMPARE_STRING (msg->msg, large_message); + + return false; +} + static void send_openlog (int options) { @@ -179,6 +208,17 @@ send_openlog (int options) closelog (); } +static void +send_openlog_large (int options) +{ + /* Define a non-default IDENT and a not default facility. */ + openlog (OPENLOG_IDENT, options, LOG_LOCAL0); + + syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO); + + closelog (); +} + static bool check_openlog_message (const struct msg_t *msg, int msgnum, int options, pid_t pid) @@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum, int expected_priority = priorities[msgnum % array_length (priorities)]; TEST_COMPARE (msg->priority, expected_priority); - char expected_ident[ident_length]; + char expected_ident[IDENT_LENGTH]; snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:", OPENLOG_IDENT, options & LOG_PID ? "[" : "", @@ -211,15 +251,38 @@ check_openlog_message (const struct msg_t *msg, int msgnum, return true; } +static bool +check_openlog_message_large (const struct msg_t *msg, int msgnum, + int options, pid_t pid) +{ + char expected_ident[IDENT_LENGTH]; + snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:", + OPENLOG_IDENT, + options & LOG_PID ? "[" : "", + options & LOG_PID ? pid : 0, + options & LOG_PID ? "]" : ""); + + TEST_COMPARE_STRING (msg->ident, expected_ident); + TEST_COMPARE_STRING (msg->msg, large_message); + TEST_COMPARE (msg->priority, LOG_INFO); + TEST_COMPARE (msg->facility, LOG_LOCAL0); + + return false; +} + static struct msg_t parse_syslog_msg (const char *msg) { struct msg_t r = { .pid = -1 }; int number; +#define STRINPUT(size) XSTRINPUT(size) +#define XSTRINPUT(size) "%" # size "s" + /* The message in the form: - <179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */ - int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d", + <179>Apr 8 14:51:19 tst-syslog: message 176 3 */ + int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d " STRINPUT(IDENT_LENGTH) + " " STRINPUT(MSG_LENGTH) " %*d %*d", &number, r.ident, r.msg); TEST_COMPARE (n, 3); @@ -246,7 +309,7 @@ parse_syslog_console (const char *msg) /* The message in the form: openlog_ident: syslog_message 128 0 */ - int n = sscanf (msg, "%32s %64s %d %d", + int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d", r.ident, r.msg, &facility, &priority); TEST_COMPARE (n, 4); @@ -281,7 +344,7 @@ check_syslog_udp (void (*syslog_send)(int), int options, int msgnum = 0; while (1) { - char buf[512]; + char buf[2048]; size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0, (struct sockaddr *) &addr, &addrlen); buf[l] = '\0'; @@ -325,7 +388,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options, int client_tcp = xaccept (server_tcp, NULL, NULL); - char buf[512], *rb = buf; + char buf[2048], *rb = buf; size_t rbl = sizeof (buf); size_t prl = 0; /* Track the size of the partial record. */ int msgnum = 0; @@ -393,20 +456,34 @@ check_syslog_console_read (FILE *fp) } static void -check_syslog_console (void) +check_syslog_console_read_large (FILE *fp) +{ + char buf[2048]; + TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL); + struct msg_t msg = parse_syslog_console (buf); + + TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":"); + TEST_COMPARE_STRING (msg.msg, large_message); + TEST_COMPARE (msg.priority, LOG_INFO); + TEST_COMPARE (msg.facility, LOG_LOCAL0); +} + +static void +check_syslog_console (void (*syslog_send)(int), + void (*syslog_check)(FILE *fp)) { xmkfifo (_PATH_CONSOLE, 0666); pid_t sender_pid = xfork (); if (sender_pid == 0) { - send_openlog (LOG_CONS); + syslog_send (LOG_CONS); _exit (0); } { FILE *fp = xfopen (_PATH_CONSOLE, "r+"); - check_syslog_console_read (fp); + syslog_check (fp); xfclose (fp); } @@ -425,16 +502,28 @@ send_openlog_callback (void *clousure) } static void -check_syslog_perror (void) +send_openlog_callback_large (void *clousure) +{ + int options = *(int *) clousure; + send_openlog_large (options); +} + +static void +check_syslog_perror (bool large) { struct support_capture_subprocess result; - result = support_capture_subprocess (send_openlog_callback, + result = support_capture_subprocess (large + ? send_openlog_callback_large + : send_openlog_callback, &(int){LOG_PERROR}); FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r"); if (mfp == NULL) FAIL_EXIT1 ("fmemopen: %m"); - check_syslog_console_read (mfp); + if (large) + check_syslog_console_read_large (mfp); + else + check_syslog_console_read (mfp); xfclose (mfp); support_capture_subprocess_check (&result, "tst-openlog-child", 0, @@ -462,10 +551,31 @@ do_test (void) check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message); /* Check the LOG_CONS option. */ - check_syslog_console (); + check_syslog_console (send_openlog, check_syslog_console_read); /* Check the LOG_PERROR option. */ - check_syslog_perror (); + check_syslog_perror (false); + + /* Similar tests as before, but with a large message to trigger the + syslog path that uses dynamically allocated memory. */ + memset (large_message, 'a', sizeof large_message - 1); + large_message[sizeof large_message - 1] = '\0'; + + check_syslog_udp (send_syslog_large, 0, check_syslog_message_large); + check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large); + + check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large); + check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large); + + check_syslog_udp (send_openlog_large, 0, check_openlog_message_large); + check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large); + + check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large); + check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large); + + check_syslog_console (send_openlog_large, check_syslog_console_read_large); + + check_syslog_perror (true); return 0; } -- cgit 1.4.1 From 924e4f3eaa502ce82fccf8537f021a796d158771 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 26 Aug 2022 21:15:43 +0200 Subject: elf: Call __libc_early_init for reused namespaces (bug 29528) libc_map is never reset to NULL, neither during dlclose nor on a dlopen call which reuses the namespace structure. As a result, if a namespace is reused, its libc is not initialized properly. The most visible result is a crash in the functions. To prevent similar bugs on namespace reuse from surfacing, unconditionally initialize the chosen namespace to zero using memset. (cherry picked from commit d0e357ff45a75553dee3b17ed7d303bfa544f6fe) --- NEWS | 1 + elf/Makefile | 25 ++++++++++++++++++++++ elf/dl-open.c | 13 +++++++----- elf/tst-dlmopen-twice-mod1.c | 37 ++++++++++++++++++++++++++++++++ elf/tst-dlmopen-twice-mod2.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ elf/tst-dlmopen-twice.c | 34 ++++++++++++++++++++++++++++++ 6 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 elf/tst-dlmopen-twice-mod1.c create mode 100644 elf/tst-dlmopen-twice-mod2.c create mode 100644 elf/tst-dlmopen-twice.c diff --git a/NEWS b/NEWS index ae30900bbc..6d31e5abba 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ The following bugs are resolved with this release: [29446] _dlopen now ignores dl_caller argument in static mode [29485] Linux: Terminate subprocess on late failure in tst-pidfd [29490] alpha: New __brk_call implementation is broken + [29528] elf: Call __libc_early_init for reused namespaces Version 2.36 diff --git a/elf/Makefile b/elf/Makefile index fd77d0c7c8..43353a4b08 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -408,6 +408,7 @@ tests += \ tst-dlmopen4 \ tst-dlmopen-dlerror \ tst-dlmopen-gethostbyname \ + tst-dlmopen-twice \ tst-dlopenfail \ tst-dlopenfail-2 \ tst-dlopenrpath \ @@ -834,6 +835,8 @@ modules-names += \ tst-dlmopen1mod \ tst-dlmopen-dlerror-mod \ tst-dlmopen-gethostbyname-mod \ + tst-dlmopen-twice-mod1 \ + tst-dlmopen-twice-mod2 \ tst-dlopenfaillinkmod \ tst-dlopenfailmod1 \ tst-dlopenfailmod2 \ @@ -2967,3 +2970,25 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \ grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \ && grep -q '^status: 127$$' $@; \ $(evaluate-test) + +$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ + $(objpfx)tst-audit-tlsdesc-mod2.so \ + $(shared-thread-library) +ifeq (yes,$(have-mtls-dialect-gnu2)) +# The test is valid for all TLS types, but we want to exercise GNU2 +# TLS if possible. +CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 +CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 +endif +$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) +$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \ + $(objpfx)tst-audit-tlsdesc-mod2.so +$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so +$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so +tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so +$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so +tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so + +$(objpfx)tst-dlmopen-twice.out: \ + $(objpfx)tst-dlmopen-twice-mod1.so \ + $(objpfx)tst-dlmopen-twice-mod2.so diff --git a/elf/dl-open.c b/elf/dl-open.c index a23e65926b..46e8066fd8 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -844,11 +844,14 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, _dl_signal_error (EINVAL, file, NULL, N_("\ no more namespaces available for dlmopen()")); } - else if (nsid == GL(dl_nns)) - { - __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); - ++GL(dl_nns); - } + + if (nsid == GL(dl_nns)) + ++GL(dl_nns); + + /* Initialize the new namespace. Most members are + zero-initialized, only the lock needs special treatment. */ + memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid])); + __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); _dl_debug_update (nsid)->r_state = RT_CONSISTENT; } diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c new file mode 100644 index 0000000000..0eaf04948c --- /dev/null +++ b/elf/tst-dlmopen-twice-mod1.c @@ -0,0 +1,37 @@ +/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +static void __attribute__ ((constructor)) +init (void) +{ + puts ("info: tst-dlmopen-twice-mod1.so loaded"); + fflush (stdout); +} + +static void __attribute__ ((destructor)) +fini (void) +{ + puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded"); + fflush (stdout); +} + +/* Large allocation. The second module does not have this, so it + should load libc at a different address. */ +char large_allocate[16 * 1024 * 1024]; diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c new file mode 100644 index 0000000000..40c6c01f96 --- /dev/null +++ b/elf/tst-dlmopen-twice-mod2.c @@ -0,0 +1,50 @@ +/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +static void __attribute__ ((constructor)) +init (void) +{ + puts ("info: tst-dlmopen-twice-mod2.so loaded"); + fflush (stdout); +} + +static void __attribute__ ((destructor)) +fini (void) +{ + puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded"); + fflush (stdout); +} + +int +run_check (void) +{ + puts ("info: about to call isalpha"); + fflush (stdout); + + volatile char ch = 'a'; + if (!isalpha (ch)) + { + puts ("error: isalpha ('a') is not true"); + fflush (stdout); + return 1; + } + return 0; +} diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c new file mode 100644 index 0000000000..449f3c8fa9 --- /dev/null +++ b/elf/tst-dlmopen-twice.c @@ -0,0 +1,34 @@ +/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +static int +do_test (void) +{ + void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW); + xdlclose (handle); + handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW); + int (*run_check) (void) = xdlsym (handle, "run_check"); + TEST_COMPARE (run_check (), 0); + xdlclose (handle); + return 0; +} + +#include -- cgit 1.4.1 From 3c791f2031ca8f6b99e96b774ed1c505ceb93595 Mon Sep 17 00:00:00 2001 From: Raphael Moreira Zinsly Date: Wed, 24 Aug 2022 11:43:37 -0300 Subject: Apply asm redirections in wchar.h before first use Similar to d0fa09a770, but for wchar.h. Fixes [BZ #27087] by applying all long double related asm redirections before using functions in bits/wchar2.h. Moves the function declarations from wcsmbs/bits/wchar2.h to a new file wcsmbs/bits/wchar2-decl.h that will be included first in wcsmbs/wchar.h. Tested with build-many-glibcs.py. Reviewed-by: Adhemerval Zanella (cherry picked from commit c7509d49c4e8fa494120c5ead21338559dad16f5) --- include/bits/wchar2-decl.h | 1 + wcsmbs/Makefile | 5 +- wcsmbs/bits/wchar2-decl.h | 124 +++++++++++++++++++++++++++++++++++++++++++++ wcsmbs/bits/wchar2.h | 72 -------------------------- wcsmbs/wchar.h | 11 +++- 5 files changed, 137 insertions(+), 76 deletions(-) create mode 100644 include/bits/wchar2-decl.h create mode 100644 wcsmbs/bits/wchar2-decl.h diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h new file mode 100644 index 0000000000..00b1b93342 --- /dev/null +++ b/include/bits/wchar2-decl.h @@ -0,0 +1 @@ +#include diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile index 3d19d5556f..4af102a3f6 100644 --- a/wcsmbs/Makefile +++ b/wcsmbs/Makefile @@ -22,8 +22,9 @@ subdir := wcsmbs include ../Makeconfig -headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \ - bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h +headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \ + bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \ + bits/types/mbstate_t.h bits/types/wint_t.h routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \ diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h new file mode 100644 index 0000000000..8e1735c33b --- /dev/null +++ b/wcsmbs/bits/wchar2-decl.h @@ -0,0 +1,124 @@ +/* Checking macros for wchar functions. Declarations only. + Copyright (C) 2004-2022 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 + . */ + +#ifndef _BITS_WCHAR2_DECL_H +#define _BITS_WCHAR2_DECL_H 1 + +#ifndef _WCHAR_H +# error "Never include directly; use instead." +#endif + + +extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, + const wchar_t *__restrict __s2, size_t __n, + size_t __ns1) __THROW; +extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, + size_t __n, size_t __ns1) __THROW; + + +#ifdef __USE_GNU + +extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, + const wchar_t *__restrict __s2, size_t __n, + size_t __ns1) __THROW; + +#endif + + +extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, + size_t __ns) __THROW; +extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, + size_t __n) __THROW; +extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, + size_t __destlen) __THROW; +extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, size_t __n, + size_t __destlen) __THROW; +extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, size_t __n, + size_t __destlen) __THROW; +extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, + size_t __destlen) __THROW; +extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, + size_t __n, size_t __destlen) __THROW; +extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, + int __flag, size_t __s_len, + const wchar_t *__restrict __format, ...) + __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; +extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, + int __flag, size_t __s_len, + const wchar_t *__restrict __format, + __gnuc_va_list __arg) + __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; + +#if __USE_FORTIFY_LEVEL > 1 + +extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, + const wchar_t *__restrict __format, ...); +extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, + ...); +extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, + const wchar_t *__restrict __format, + __gnuc_va_list __ap); +extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, + __gnuc_va_list __ap); + +#endif + +extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, + __FILE *__restrict __stream) __wur; + +#ifdef __USE_GNU + +extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, + int __n, __FILE *__restrict __stream) + __wur; + +#endif + +extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, + mbstate_t *__restrict __p, + size_t __buflen) __THROW __wur; +extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, + const char **__restrict __src, + size_t __len, mbstate_t *__restrict __ps, + size_t __dstlen) __THROW; +extern size_t __wcsrtombs_chk (char *__restrict __dst, + const wchar_t **__restrict __src, + size_t __len, mbstate_t *__restrict __ps, + size_t __dstlen) __THROW; + +#ifdef __USE_XOPEN2K8 + +extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, + const char **__restrict __src, size_t __nmc, + size_t __len, mbstate_t *__restrict __ps, + size_t __dstlen) __THROW; +extern size_t __wcsnrtombs_chk (char *__restrict __dst, + const wchar_t **__restrict __src, + size_t __nwc, size_t __len, + mbstate_t *__restrict __ps, size_t __dstlen) + __THROW; + +#endif + +#endif /* bits/wchar2-decl.h. */ diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h index 0e017f458b..3f110efe57 100644 --- a/wcsmbs/bits/wchar2.h +++ b/wcsmbs/bits/wchar2.h @@ -21,9 +21,6 @@ #endif -extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, - const wchar_t *__restrict __s2, size_t __n, - size_t __ns1) __THROW; extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias, (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, size_t __n), @@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, } -extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, - size_t __n, size_t __ns1) __THROW; extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1, const wchar_t *__s2, size_t __n), wmemmove); @@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n)) #ifdef __USE_GNU -extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, - const wchar_t *__restrict __s2, size_t __n, - size_t __ns1) __THROW; extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias, (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, @@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, #endif -extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, - size_t __ns) __THROW; extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c, size_t __n), wmemset); extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn, @@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n)) } -extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, - size_t __n) __THROW; extern wchar_t *__REDIRECT_NTH (__wcscpy_alias, (wchar_t *__restrict __dest, const wchar_t *__restrict __src), wcscpy); @@ -127,9 +114,6 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) } -extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, - size_t __destlen) __THROW; extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias, (wchar_t *__restrict __dest, const wchar_t *__restrict __src), wcpcpy); @@ -144,9 +128,6 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) } -extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, size_t __n, - size_t __destlen) __THROW; extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias, (wchar_t *__restrict __dest, const wchar_t *__restrict __src, @@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, } -extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, size_t __n, - size_t __destlen) __THROW; extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias, (wchar_t *__restrict __dest, const wchar_t *__restrict __src, @@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, } -extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, - size_t __destlen) __THROW; extern wchar_t *__REDIRECT_NTH (__wcscat_alias, (wchar_t *__restrict __dest, const wchar_t *__restrict __src), wcscat); @@ -209,9 +184,6 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) } -extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, - size_t __n, size_t __destlen) __THROW; extern wchar_t *__REDIRECT_NTH (__wcsncat_alias, (wchar_t *__restrict __dest, const wchar_t *__restrict __src, @@ -228,10 +200,6 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src, } -extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, - int __flag, size_t __s_len, - const wchar_t *__restrict __format, ...) - __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; extern int __REDIRECT_NTH_LDBL (__swprintf_alias, (wchar_t *__restrict __s, size_t __n, @@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n, : swprintf (s, n, __VA_ARGS__)) #endif -extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, - int __flag, size_t __s_len, - const wchar_t *__restrict __format, - __gnuc_va_list __arg) - __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; extern int __REDIRECT_NTH_LDBL (__vswprintf_alias, (wchar_t *__restrict __s, size_t __n, @@ -283,16 +246,6 @@ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n, #if __USE_FORTIFY_LEVEL > 1 -extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, - const wchar_t *__restrict __format, ...); -extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, - ...); -extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, - const wchar_t *__restrict __format, - __gnuc_va_list __ap); -extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, - __gnuc_va_list __ap); - # ifdef __va_arg_pack __fortify_function int wprintf (const wchar_t *__restrict __fmt, ...) @@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream, #endif -extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, - __FILE *__restrict __stream) __wur; extern wchar_t *__REDIRECT (__fgetws_alias, (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream), fgetws) __wur; @@ -351,9 +302,6 @@ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) } #ifdef __USE_GNU -extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, - int __n, __FILE *__restrict __stream) - __wur; extern wchar_t *__REDIRECT (__fgetws_unlocked_alias, (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream), fgetws_unlocked) @@ -379,9 +327,6 @@ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) #endif -extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, - mbstate_t *__restrict __p, - size_t __buflen) __THROW __wur; extern size_t __REDIRECT_NTH (__wcrtomb_alias, (char *__restrict __s, wchar_t __wchar, mbstate_t *__restrict __ps), wcrtomb) __wur; @@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar, } -extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, - const char **__restrict __src, - size_t __len, mbstate_t *__restrict __ps, - size_t __dstlen) __THROW; extern size_t __REDIRECT_NTH (__mbsrtowcs_alias, (wchar_t *__restrict __dst, const char **__restrict __src, @@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, } -extern size_t __wcsrtombs_chk (char *__restrict __dst, - const wchar_t **__restrict __src, - size_t __len, mbstate_t *__restrict __ps, - size_t __dstlen) __THROW; extern size_t __REDIRECT_NTH (__wcsrtombs_alias, (char *__restrict __dst, const wchar_t **__restrict __src, @@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, #ifdef __USE_XOPEN2K8 -extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, - const char **__restrict __src, size_t __nmc, - size_t __len, mbstate_t *__restrict __ps, - size_t __dstlen) __THROW; extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias, (wchar_t *__restrict __dst, const char **__restrict __src, size_t __nmc, @@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, } -extern size_t __wcsnrtombs_chk (char *__restrict __dst, - const wchar_t **__restrict __src, - size_t __nwc, size_t __len, - mbstate_t *__restrict __ps, size_t __dstlen) - __THROW; extern size_t __REDIRECT_NTH (__wcsnrtombs_alias, (char *__restrict __dst, const wchar_t **__restrict __src, diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h index 5d6a40853d..c1321c7518 100644 --- a/wcsmbs/wchar.h +++ b/wcsmbs/wchar.h @@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize, /* Define some macros helping to catch buffer overflows. */ #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function -# include +/* Declare all functions from bits/wchar2-decl.h first. */ +# include #endif -#include +/* The following headers provide asm redirections. These redirections must + appear before the first usage of these functions, e.g. in bits/wchar.h. */ #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 # include #endif +#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function +/* Now include the function definitions and redirects too. */ +# include +#endif + __END_DECLS #endif /* wchar.h */ -- cgit 1.4.1 From b3736d1a3c60a3ec9959bf3b38794958546bf6a2 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 30 Aug 2022 13:35:52 -0300 Subject: elf: Restore how vDSO dependency is printed with LD_TRACE_LOADED_OBJECTS (BZ #29539) The d7703d3176d225d5743b21811d888619eba39e82 changed how vDSO like dependencies are printed, instead of just the name and address it follows other libraries mode and prints 'name => path'. Unfortunately, this broke some ldd consumer that uses the output to filter out the program's dependencies. For instance CMake bundleutilities module [1], where GetPrequirite uses the regex to filter out 'name => path' [2]. This patch restore the previous way to print just the name and the mapping address. Checked on x86_64-linux-gnu. [1] https://github.com/Kitware/CMake/tree/master/Tests/BundleUtilities [2] https://github.com/Kitware/CMake/blob/master/Modules/GetPrerequisites.cmake#L733 Reviewed-by: Florian Weimer (cherry picked from commit 1e903124cec4492463d075c6c061a2a772db77bf) --- NEWS | 2 +- elf/rtld.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 6d31e5abba..757ded85e0 100644 --- a/NEWS +++ b/NEWS @@ -14,7 +14,7 @@ The following bugs are resolved with this release: [29485] Linux: Terminate subprocess on late failure in tst-pidfd [29490] alpha: New __brk_call implementation is broken [29528] elf: Call __libc_early_init for reused namespaces - + [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are Version 2.36 diff --git a/elf/rtld.c b/elf/rtld.c index cbbaf4a331..3e771a93d8 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -2122,6 +2122,12 @@ dl_main (const ElfW(Phdr) *phdr, if (l->l_faked) /* The library was not found. */ _dl_printf ("\t%s => not found\n", l->l_libname->name); + else if (strcmp (l->l_libname->name, l->l_name) == 0) + /* Print vDSO like libraries without duplicate name. Some + consumers depend of this format. */ + _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name, + (int) sizeof l->l_map_start * 2, + (size_t) l->l_map_start); else _dl_printf ("\t%s => %s (0x%0*Zx)\n", DSO_FILENAME (l->l_libname->name), -- cgit 1.4.1 From 645d94808aaa90fb1b20a25ff70bb50d9eb1d55b Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Mon, 5 Sep 2022 09:34:39 -0300 Subject: syslog: Remove extra whitespace between timestamp and message (BZ#29544) The rfc3164 clear states that a single space character must follow the timestamp field. Checked on x86_64-linux-gnu. --- misc/syslog.c | 2 +- misc/tst-syslog.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/misc/syslog.c b/misc/syslog.c index b88f66c835..f67d4b58a4 100644 --- a/misc/syslog.c +++ b/misc/syslog.c @@ -167,7 +167,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, _nl_C_locobj_ptr); #define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \ - "<%d>%s %n%s%s%.0d%s: ", \ + "<%d>%s%n%s%s%.0d%s: ", \ __pri, __timestamp, __msgoff, \ LogTag == NULL ? __progname : LogTag, \ "[" + (pid == 0), pid, "]" + (pid == 0) diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c index 1d332ece53..3560b518a2 100644 --- a/misc/tst-syslog.c +++ b/misc/tst-syslog.c @@ -275,16 +275,19 @@ parse_syslog_msg (const char *msg) { struct msg_t r = { .pid = -1 }; int number; + int wsb, wsa; #define STRINPUT(size) XSTRINPUT(size) #define XSTRINPUT(size) "%" # size "s" /* The message in the form: - <179>Apr 8 14:51:19 tst-syslog: message 176 3 */ - int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d " STRINPUT(IDENT_LENGTH) + <179>Apr 8 14:51:19 tst-syslog: message 176 3 */ + int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %*d %*d", - &number, r.ident, r.msg); + &number, &wsb, &wsa, r.ident, r.msg); TEST_COMPARE (n, 3); + /* It should only one space between timestamp and message. */ + TEST_COMPARE (wsa - wsb, 1); r.facility = number & LOG_FACMASK; r.priority = number & LOG_PRIMASK; -- cgit 1.4.1 From b46412fb17e8bfc6c9e1f144bbcf833320c80f8a Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Tue, 6 Sep 2022 09:31:50 -0400 Subject: Add NEWS entry for CVE-2022-39046 (cherry picked from commit 76fe56020e7ef354685b2284580ac1630c078a2b) --- NEWS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS b/NEWS index 757ded85e0..10a7613f09 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,13 @@ using `glibc' in the "product" field. Version 2.36.1 +Security related changes: + + CVE-2022-39046: When the syslog function is passed a crafted input + string larger than 1024 bytes, it reads uninitialized memory from the + heap and prints it to the target log file, potentially revealing a + portion of the contents of the heap. + The following bugs are resolved with this release: [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning -- cgit 1.4.1 From c399271c10bd00714504e8d4dfbec8aebf996dd4 Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Wed, 27 Jul 2022 11:44:07 +0200 Subject: nscd: Fix netlink cache invalidation if epoll is used [BZ #29415] Processes cache network interface information such as whether IPv4 or IPv6 are enabled. This is only checked again if the "netlink timestamp" provided by nscd changed, which is triggered by netlink socket activity. However, in the epoll handler for the netlink socket, it was missed to assign the new timestamp to the nscd database. The handler for plain poll did that properly, copy that over. This bug caused that e.g. processes which started before network configuration got unusuable addresses from getaddrinfo, like IPv6 only even though only IPv4 is available: https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1041 It's a bit hard to reproduce, so I verified this by checking the timestamp on calls to __check_pf manually. Without this patch it's stuck at 1, now it's increasing on network changes as expected. Signed-off-by: Fabian Vogt (cherry picked from commit 02ca25fef2785974011e9c5beecc99b900b69fd7) --- NEWS | 1 + nscd/connections.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 10a7613f09..9360596fcc 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ Security related changes: The following bugs are resolved with this release: [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning + [29415] nscd: Fix netlink cache invalidation if epoll is used [29446] _dlopen now ignores dl_caller argument in static mode [29485] Linux: Terminate subprocess on late failure in tst-pidfd [29490] alpha: New __brk_call implementation is broken diff --git a/nscd/connections.c b/nscd/connections.c index 61d1674eb4..531d2e83df 100644 --- a/nscd/connections.c +++ b/nscd/connections.c @@ -2284,7 +2284,8 @@ main_loop_epoll (int efd) sizeof (buf))) != -1) ; - __bump_nl_timestamp (); + dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP] + = __bump_nl_timestamp (); } # endif else -- cgit 1.4.1 From 9d7eebde8f134ea25bdb9ab61bc74d5e71e41288 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: resolv: Add tst-resolv-byaddr for testing reverse lookup Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 0b99828d54e5d1fc8f5ad3edf5ba262ad2e9c5b0) --- resolv/Makefile | 2 + resolv/tst-resolv-byaddr.c | 326 +++++++++++++++++++++++++++++++++++ resolv/tst-resolv-maybe_insert_sig.h | 32 ++++ 3 files changed, 360 insertions(+) create mode 100644 resolv/tst-resolv-byaddr.c create mode 100644 resolv/tst-resolv-maybe_insert_sig.h diff --git a/resolv/Makefile b/resolv/Makefile index 5b15321f9b..98b10d97a0 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -91,6 +91,7 @@ tests += \ tst-res_hnok \ tst-resolv-basic \ tst-resolv-binary \ + tst-resolv-byaddr \ tst-resolv-edns \ tst-resolv-network \ tst-resolv-noaaaa \ @@ -260,6 +261,7 @@ $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \ $(gen-locales) $(objpfx)tst-no-libidn2.so $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library) +$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c new file mode 100644 index 0000000000..6299e89837 --- /dev/null +++ b/resolv/tst-resolv-byaddr.c @@ -0,0 +1,326 @@ +/* Test reverse DNS lookup. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tst-resolv-maybe_insert_sig.h" + +/* QNAME format: + + ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa. + CNAMES|ADDRESSES.2.0.192.in-addr-arpa. + + For the IPv4 reverse lookup, the address count is in the lower + bits. + + CNAMES is the length of the CNAME chain, ADDRESSES is the number of + addresses in the response. The special value 15 means that there + are no addresses, and the RCODE is NXDOMAIN. */ +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + TEST_COMPARE (qclass, C_IN); + TEST_COMPARE (qtype, T_PTR); + + unsigned int addresses, cnames, bits; + char *tail; + if (strstr (qname, "ip6.arpa") != NULL + && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3) + TEST_COMPARE_STRING (tail, "\ +0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); + else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2) + { + TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa"); + addresses = bits & 0x0f; + cnames = bits >> 4; + } + else + FAIL_EXIT1 ("invalid QNAME: %s", qname); + free (tail); + + int rcode; + if (addresses == 15) + { + /* Special case: Use no addresses with NXDOMAIN response. */ + rcode = ns_r_nxdomain; + addresses = 0; + } + else + rcode = 0; + + struct resolv_response_flags flags = { .rcode = rcode }; + resolv_response_init (b, flags); + resolv_response_add_question (b, qname, qclass, qtype); + resolv_response_section (b, ns_s_an); + maybe_insert_sig (b, qname); + + /* Provide the requested number of CNAME records. */ + char *previous_name = (char *) qname; + for (int unique = 0; unique < cnames; ++unique) + { + resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); + char *new_name = xasprintf ("%d.alias.example", unique); + resolv_response_add_name (b, new_name); + resolv_response_close_record (b); + + maybe_insert_sig (b, qname); + + if (previous_name != qname) + free (previous_name); + previous_name = new_name; + } + + for (int unique = 0; unique < addresses; ++unique) + { + resolv_response_open_record (b, previous_name, qclass, T_PTR, 60); + char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example", + unique, cnames, addresses); + resolv_response_add_name (b, ptr); + free (ptr); + resolv_response_close_record (b); + } + + if (previous_name != qname) + free (previous_name); +} + +/* Used to check that gethostbyaddr_r does not write past the buffer + end. */ +static struct support_next_to_fault ntf; + +/* Perform a gethostbyaddr call and check the result. */ +static void +check_gethostbyaddr (const char *address, const char *expected) +{ + unsigned char bytes[16]; + unsigned int byteslen; + int family; + if (strchr (address, ':') != NULL) + { + family = AF_INET6; + byteslen = 16; + } + else + { + family = AF_INET; + byteslen = 4; + } + TEST_COMPARE (inet_pton (family, address, bytes), 1); + + struct hostent *e = gethostbyaddr (bytes, byteslen, family); + check_hostent (address, e, expected); + + if (e == NULL) + return; + + /* Try gethostbyaddr_r with increasing sizes until success. First + compute a reasonable minimum buffer size, to avoid many pointless + attempts. */ + size_t minimum_size = strlen (e->h_name); + for (int i = 0; e->h_addr_list[i] != NULL; ++i) + minimum_size += e->h_length + sizeof (char *); + for (int i = 0; e->h_aliases[i] != NULL; ++i) + minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *); + + /* Gradually increase the size until success. */ + for (size_t size = minimum_size; size < ntf.length; ++size) + { + struct hostent result; + int herrno; + int ret = gethostbyaddr_r (bytes, byteslen, family, &result, + ntf.buffer + ntf.length - size, size, + &e, &herrno); + if (ret == ERANGE) + /* Retry with larger size. */ + TEST_COMPARE (herrno, NETDB_INTERNAL); + else if (ret == 0) + { + TEST_VERIFY (size > minimum_size); + check_hostent (address, e, expected); + return; + } + else + FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret); + } + + FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address); +} + +/* Perform a getnameinfo call and check the result. */ +static void +check_getnameinfo (const char *address, const char *expected) +{ + struct sockaddr_in sin = { }; + struct sockaddr_in6 sin6 = { }; + void *sa; + socklen_t salen; + if (strchr (address, ':') != NULL) + { + sin6.sin6_family = AF_INET6; + TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1); + sin6.sin6_port = htons (80); + sa = &sin6; + salen = sizeof (sin6); + } + else + { + sin.sin_family = AF_INET; + TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1); + sin.sin_port = htons (80); + sa = &sin; + salen = sizeof (sin); + } + + char host[64]; + char service[64]; + int ret = getnameinfo (sa, salen, host, + sizeof (host), service, sizeof (service), + NI_NAMEREQD | NI_NUMERICSERV); + switch (ret) + { + case 0: + TEST_COMPARE_STRING (host, expected); + TEST_COMPARE_STRING (service, "80"); + break; + case EAI_SYSTEM: + TEST_COMPARE_STRING (strerror (errno), expected); + break; + default: + TEST_COMPARE_STRING (gai_strerror (ret), expected); + } +} + +static int +do_test (void) +{ + /* Some reasonably upper bound for the maximum response size. */ + ntf = support_next_to_fault_allocate (4096); + + struct resolv_test *obj = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response + }); + + for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) + { + insert_sig = do_insert_sig; + + /* No PTR record, RCODE=0. */ + check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n"); + check_getnameinfo ("192.0.2.0", "Name or service not known"); + check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n"); + check_getnameinfo ("192.0.2.16", "Name or service not known"); + check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n"); + check_getnameinfo ("192.0.2.32", "Name or service not known"); + check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n"); + check_getnameinfo ("2001:db8::", "Name or service not known"); + check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n"); + check_getnameinfo ("2001:db8::10", "Name or service not known"); + check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n"); + check_getnameinfo ("2001:db8::20", "Name or service not known"); + + /* No PTR record, NXDOMAIN. */ + check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n"); + check_getnameinfo ("192.0.2.15", "Name or service not known"); + check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n"); + check_getnameinfo ("192.0.2.31", "Name or service not known"); + check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n"); + check_getnameinfo ("192.0.2.47", "Name or service not known"); + check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n"); + check_getnameinfo ("2001:db8::f", "Name or service not known"); + check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n"); + check_getnameinfo ("2001:db8::1f", "Name or service not known"); + check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n"); + check_getnameinfo ("2001:db8::2f", "Name or service not known"); + + /* Actual response data. Only the first PTR record is returned. */ + check_gethostbyaddr ("192.0.2.1", + "name: unique-0.cnames-0.addresses-1.example\n" + "address: 192.0.2.1\n"); + check_getnameinfo ("192.0.2.1", + "unique-0.cnames-0.addresses-1.example"); + check_gethostbyaddr ("192.0.2.17", + "name: unique-0.cnames-1.addresses-1.example\n" + "address: 192.0.2.17\n"); + check_getnameinfo ("192.0.2.17", + "unique-0.cnames-1.addresses-1.example"); + check_gethostbyaddr ("192.0.2.18", + "name: unique-0.cnames-1.addresses-2.example\n" + "address: 192.0.2.18\n"); + check_getnameinfo ("192.0.2.18", + "unique-0.cnames-1.addresses-2.example"); + check_gethostbyaddr ("192.0.2.33", + "name: unique-0.cnames-2.addresses-1.example\n" + "address: 192.0.2.33\n"); + check_getnameinfo ("192.0.2.33", + "unique-0.cnames-2.addresses-1.example"); + check_gethostbyaddr ("192.0.2.34", + "name: unique-0.cnames-2.addresses-2.example\n" + "address: 192.0.2.34\n"); + check_getnameinfo ("192.0.2.34", + "unique-0.cnames-2.addresses-2.example"); + + /* Same for IPv6 addresses. */ + check_gethostbyaddr ("2001:db8::1", + "name: unique-0.cnames-0.addresses-1.example\n" + "address: 2001:db8::1\n"); + check_getnameinfo ("2001:db8::1", + "unique-0.cnames-0.addresses-1.example"); + check_gethostbyaddr ("2001:db8::11", + "name: unique-0.cnames-1.addresses-1.example\n" + "address: 2001:db8::11\n"); + check_getnameinfo ("2001:db8::11", + "unique-0.cnames-1.addresses-1.example"); + check_gethostbyaddr ("2001:db8::12", + "name: unique-0.cnames-1.addresses-2.example\n" + "address: 2001:db8::12\n"); + check_getnameinfo ("2001:db8::12", + "unique-0.cnames-1.addresses-2.example"); + check_gethostbyaddr ("2001:db8::21", + "name: unique-0.cnames-2.addresses-1.example\n" + "address: 2001:db8::21\n"); + check_getnameinfo ("2001:db8::21", + "unique-0.cnames-2.addresses-1.example"); + check_gethostbyaddr ("2001:db8::22", + "name: unique-0.cnames-2.addresses-2.example\n" + "address: 2001:db8::22\n"); + check_getnameinfo ("2001:db8::22", + "unique-0.cnames-2.addresses-2.example"); + } + + resolv_test_end (obj); + + support_next_to_fault_free (&ntf); + return 0; +} + +#include diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h new file mode 100644 index 0000000000..05725225af --- /dev/null +++ b/resolv/tst-resolv-maybe_insert_sig.h @@ -0,0 +1,32 @@ +/* Code snippet for optionally inserting ignored SIG records in resolver tests. + Copyright (C) 2022 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 + . */ + +/* Set to true for an alternative pass that inserts (ignored) SIG + records. This does not alter the response, so this property is not + encoded in the QNAME. The variable needs to be volatile because + leaf attributes tell GCC that the response function is not + called. */ +static volatile bool insert_sig; + +static void +maybe_insert_sig (struct resolv_response_builder *b, const char *owner) +{ + resolv_response_open_record (b, owner, C_IN, T_SIG, 60); + resolv_response_add_data (b, "", 1); + resolv_response_close_record (b); +} -- cgit 1.4.1 From bffc33e90ed57a4786c676dda92d935e3613e031 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: resolv: Add tst-resolv-aliases Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 87aa98aa80627553a66bdcad2701fd6307723645) --- resolv/Makefile | 2 + resolv/tst-resolv-aliases.c | 254 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 resolv/tst-resolv-aliases.c diff --git a/resolv/Makefile b/resolv/Makefile index 98b10d97a0..0038bb7028 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -89,6 +89,7 @@ tests += \ tst-ns_name_pton \ tst-res_hconf_reorder \ tst-res_hnok \ + tst-resolv-aliases \ tst-resolv-basic \ tst-resolv-binary \ tst-resolv-byaddr \ @@ -259,6 +260,7 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales) $(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales) $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \ $(gen-locales) $(objpfx)tst-no-libidn2.so +$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library) diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c new file mode 100644 index 0000000000..b212823aa0 --- /dev/null +++ b/resolv/tst-resolv-aliases.c @@ -0,0 +1,254 @@ +/* Test alias handling (mainly for gethostbyname). + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tst-resolv-maybe_insert_sig.h" + +/* QNAME format: + + aADDRESSES-cCNAMES.example.net + + CNAMES is the length of the CNAME chain, ADDRESSES is the number of + addresses in the response. The special value 255 means that there + are no addresses, and the RCODE is NXDOMAIN. */ +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + TEST_COMPARE (qclass, C_IN); + if (qtype != T_A) + TEST_COMPARE (qtype, T_AAAA); + + unsigned int addresses, cnames; + char *tail; + if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3) + { + if (strcmp (tail, ".example.com") == 0 + || strcmp (tail, ".example.net.example.net") == 0 + || strcmp (tail, ".example.net.example.com") == 0) + /* These only happen after NXDOMAIN. */ + TEST_VERIFY (addresses == 255); + else if (strcmp (tail, ".example.net") != 0) + FAIL_EXIT1 ("invalid QNAME: %s", qname); + } + free (tail); + + int rcode; + if (addresses == 255) + { + /* Special case: Use no addresses with NXDOMAIN response. */ + rcode = ns_r_nxdomain; + addresses = 0; + } + else + rcode = 0; + + struct resolv_response_flags flags = { .rcode = rcode }; + resolv_response_init (b, flags); + resolv_response_add_question (b, qname, qclass, qtype); + resolv_response_section (b, ns_s_an); + maybe_insert_sig (b, qname); + + /* Provide the requested number of CNAME records. */ + char *previous_name = (char *) qname; + for (int unique = 0; unique < cnames; ++unique) + { + resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); + char *new_name = xasprintf ("%d.alias.example", unique); + resolv_response_add_name (b, new_name); + resolv_response_close_record (b); + + maybe_insert_sig (b, qname); + + if (previous_name != qname) + free (previous_name); + previous_name = new_name; + } + + for (int unique = 0; unique < addresses; ++unique) + { + resolv_response_open_record (b, previous_name, qclass, qtype, 60); + + if (qtype == T_A) + { + char ipv4[4] = {192, 0, 2, 1 + unique}; + resolv_response_add_data (b, &ipv4, sizeof (ipv4)); + } + else if (qtype == T_AAAA) + { + char ipv6[16] = + { + 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1 + unique + }; + resolv_response_add_data (b, &ipv6, sizeof (ipv6)); + } + resolv_response_close_record (b); + } + + if (previous_name != qname) + free (previous_name); +} + +static char * +make_qname (bool do_search, int cnames, int addresses) +{ + return xasprintf ("a%d-c%d%s", + addresses, cnames, do_search ? "" : ".example.net"); +} + +static void +check_cnames_failure (int af, bool do_search, int cnames, int addresses) +{ + char *qname = make_qname (do_search, cnames, addresses); + + struct hostent *e; + if (af == AF_UNSPEC) + e = gethostbyname (qname); + else + e = gethostbyname2 (qname, af); + + if (addresses == 0) + check_hostent (qname, e, "error: NO_RECOVERY\n"); + else + check_hostent (qname, e, "error: HOST_NOT_FOUND\n"); + + free (qname); +} + +static void +check (int af, bool do_search, int cnames, int addresses) +{ + char *qname = make_qname (do_search, cnames, addresses); + char *fqdn = make_qname (false, cnames, addresses); + + struct hostent *e; + if (af == AF_UNSPEC) + e = gethostbyname (qname); + else + e = gethostbyname2 (qname, af); + if (e == NULL) + FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses); + + if (af == AF_UNSPEC || af == AF_INET) + { + TEST_COMPARE (e->h_addrtype, AF_INET); + TEST_COMPARE (e->h_length, 4); + } + else + { + TEST_COMPARE (e->h_addrtype, AF_INET6); + TEST_COMPARE (e->h_length, 16); + } + + for (int i = 0; i < addresses; ++i) + { + char ipv4[4] = {192, 0, 2, 1 + i}; + char ipv6[16] = + { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i }; + char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6; + TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length, + expected, e->h_length); + } + TEST_VERIFY (e->h_addr_list[addresses] == NULL); + + + if (cnames == 0) + { + /* QNAME is fully qualified. */ + TEST_COMPARE_STRING (e->h_name, fqdn); + TEST_VERIFY (e->h_aliases[0] == NULL); + } + else + { + /* Fully-qualified QNAME is demoted to an aliases. */ + TEST_COMPARE_STRING (e->h_aliases[0], fqdn); + + for (int i = 1; i <= cnames; ++i) + { + char *expected = xasprintf ("%d.alias.example", i - 1); + if (i == cnames) + TEST_COMPARE_STRING (e->h_name, expected); + else + TEST_COMPARE_STRING (e->h_aliases[i], expected); + free (expected); + } + TEST_VERIFY (e->h_aliases[cnames] == NULL); + } + + free (fqdn); + free (qname); +} + +static int +do_test (void) +{ + struct resolv_test *obj = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + .search = { "example.net", "example.com" }, + }); + + static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 }; + + for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) + { + insert_sig = do_insert_sig; + + /* If do_search is true, a bare host name (for example, a1-c1) + is used. This exercises search path processing and FQDN + qualification. */ + for (int do_search = 0; do_search < 2; ++do_search) + for (const int *paf = families; paf != array_end (families); ++paf) + { + for (int cnames = 0; cnames <= 100; ++cnames) + { + check_cnames_failure (*paf, do_search, cnames, 0); + /* Now with NXDOMAIN responses. */ + check_cnames_failure (*paf, do_search, cnames, 255); + } + + for (int cnames = 0; cnames <= 10; ++cnames) + for (int addresses = 1; addresses <= 10; ++addresses) + check (*paf, do_search, cnames, addresses); + + /* The current implementation is limited to 47 aliases. + Addresses do not have such a limit. */ + check (*paf, do_search, 47, 60); + } + } + + resolv_test_end (obj); + + return 0; +} + +#include -- cgit 1.4.1 From 3c9b4004e2dccc9ca2ace078a0106f9d682fd1a0 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: resolv: Add internal __res_binary_hnok function During package parsing, only the binary representation is available, and it is convenient to check that directly for conformance with host name requirements. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit c79327bf00a4be6d60259227acc78ef80ead3622) --- include/resolv.h | 3 +++ resolv/res-name-checking.c | 14 +++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/resolv.h b/include/resolv.h index 3590b6f496..4dbbac3800 100644 --- a/include/resolv.h +++ b/include/resolv.h @@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery) extern __typeof (__res_queriesmatch) __libc_res_queriesmatch; libc_hidden_proto (__libc_res_queriesmatch) +/* Variant of res_hnok which operates on binary (but uncompressed) names. */ +bool __res_binary_hnok (const unsigned char *dn) attribute_hidden; + # endif /* _RESOLV_H_ && !_ISOMAC */ #endif diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c index 07a412d8ff..213edceaf3 100644 --- a/resolv/res-name-checking.c +++ b/resolv/res-name-checking.c @@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn) return dn[0] > 0 && dn[1] == '-'; } +bool +__res_binary_hnok (const unsigned char *dn) +{ + return !binary_leading_dash (dn) && binary_hnok (dn); +} + /* Return 1 if res_hnok is a valid host name. Labels must only contain [0-9a-zA-Z_-] characters, and the name must not start with a '-'. The latter is to avoid confusion with program options. */ @@ -145,11 +151,9 @@ int ___res_hnok (const char *dn) { unsigned char buf[NS_MAXCDNAME]; - if (!printable_string (dn) - || __ns_name_pton (dn, buf, sizeof (buf)) < 0 - || binary_leading_dash (buf)) - return 0; - return binary_hnok (buf); + return (printable_string (dn) + && __ns_name_pton (dn, buf, sizeof (buf)) >= 0 + && __res_binary_hnok (buf)); } versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34); versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE); -- cgit 1.4.1 From 20ec40a51d3a8e9487f40dc9352d158def23ea8c Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: resolv: Add the __ns_samebinaryname function During packet parsing, only the binary name is available. If the name equality check is performed before conversion to text, we can sometimes skip the last step. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 394085a34d25a51513019a4dc411acd3527fbd33) --- include/arpa/nameser.h | 6 ++++ resolv/Makefile | 5 ++++ resolv/ns_samebinaryname.c | 55 +++++++++++++++++++++++++++++++++++++ resolv/tst-ns_samebinaryname.c | 62 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 resolv/ns_samebinaryname.c create mode 100644 resolv/tst-ns_samebinaryname.c diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h index 53f1dbc7c3..bb1dede187 100644 --- a/include/arpa/nameser.h +++ b/include/arpa/nameser.h @@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW; int __ns_name_unpack (const unsigned char *, const unsigned char *, const unsigned char *, unsigned char *, size_t) __THROW; +/* Like ns_samename, but for uncompressed binary names. Return true + if the two arguments compare are equal as case-insensitive domain + names. */ +_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *) + attribute_hidden; + #define ns_msg_getflag(handle, flag) \ (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) diff --git a/resolv/Makefile b/resolv/Makefile index 0038bb7028..ec61ad07bd 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -46,6 +46,7 @@ routines := \ ns_name_skip \ ns_name_uncompress \ ns_name_unpack \ + ns_samebinaryname \ ns_samename \ nsap_addr \ nss_dns_functions \ @@ -106,6 +107,10 @@ tests += \ tests-internal += tst-resolv-txnid-collision tests-static += tst-resolv-txnid-collision +# Likewise for __ns_samebinaryname. +tests-internal += tst-ns_samebinaryname +tests-static += tst-ns_samebinaryname + # These tests need libdl. ifeq (yes,$(build-shared)) tests += \ diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c new file mode 100644 index 0000000000..9a47d8e97a --- /dev/null +++ b/resolv/ns_samebinaryname.c @@ -0,0 +1,55 @@ +/* Compare two binary domain names for quality. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +/* Convert ASCII letters to upper case. */ +static inline int +ascii_toupper (unsigned char ch) +{ + if (ch >= 'a' && ch <= 'z') + return ch - 'a' + 'A'; + else + return ch; +} + +bool +__ns_samebinaryname (const unsigned char *a, const unsigned char *b) +{ + while (*a != 0 && *b != 0) + { + if (*a != *b) + /* Different label length. */ + return false; + int labellen = *a; + ++a; + ++b; + for (int i = 0; i < labellen; ++i) + { + if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b)) + /* Different character in label. */ + return false; + ++a; + ++b; + } + } + + /* Match if both names are at the root label. */ + return *a == 0 && *b == 0; +} diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c new file mode 100644 index 0000000000..b06ac610b4 --- /dev/null +++ b/resolv/tst-ns_samebinaryname.c @@ -0,0 +1,62 @@ +/* Test the __ns_samebinaryname function. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +/* First character denotes the comparison group: All names with the + same first character are expected to compare equal. */ +static const char *const cases[] = + { + " ", + "1\001a", "1\001A", + "2\002ab", "2\002aB", "2\002Ab", "2\002AB", + "3\001a\002ab", "3\001A\002ab", + "w\003www\007example\003com", "w\003Www\007Example\003Com", + "w\003WWW\007EXAMPLE\003COM", + "W\003WWW", "W\003www", + }; + +static int +do_test (void) +{ + for (int i = 0; i < array_length (cases); ++i) + for (int j = 0; j < array_length (cases); ++j) + { + unsigned char *a = (unsigned char *) &cases[i][1]; + unsigned char *b = (unsigned char *) &cases[j][1]; + bool actual = __ns_samebinaryname (a, b); + bool expected = cases[i][0] == cases[j][0]; + if (actual != expected) + { + char a1[NS_MAXDNAME]; + TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0); + char b1[NS_MAXDNAME]; + TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0); + printf ("error: \"%s\" \"%s\": expected %s\n", + a1, b1, expected ? "equal" : "unqueal"); + support_record_failure (); + } + } + return 0; +} + +#include -- cgit 1.4.1 From adb69f8ffe83db5d475868b42996bc70de8cff77 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: resolv: Add internal __ns_name_length_uncompressed function This function is useful for checking that the question name is uncompressed (as it should be). Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 78b1a4f0e49064e5dfb686c7cd87bd4df2640b29) --- include/arpa/nameser.h | 8 ++ resolv/Makefile | 5 ++ resolv/ns_name_length_uncompressed.c | 72 +++++++++++++++++ resolv/tst-ns_name_length_uncompressed.c | 135 +++++++++++++++++++++++++++++++ 4 files changed, 220 insertions(+) create mode 100644 resolv/ns_name_length_uncompressed.c create mode 100644 resolv/tst-ns_name_length_uncompressed.c diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h index bb1dede187..6e4808f00d 100644 --- a/include/arpa/nameser.h +++ b/include/arpa/nameser.h @@ -95,5 +95,13 @@ libc_hidden_proto (__ns_name_unpack) extern __typeof (ns_samename) __libc_ns_samename; libc_hidden_proto (__libc_ns_samename) +/* Packet parser helper functions. */ + +/* Verify that P points to an uncompressed domain name in wire format. + On success, return the length of the encoded name, including the + terminating null byte. On failure, return -1 and set errno. EOM + must point one past the last byte in the packet. */ +int __ns_name_length_uncompressed (const unsigned char *p, + const unsigned char *eom) attribute_hidden; # endif /* !_ISOMAC */ #endif diff --git a/resolv/Makefile b/resolv/Makefile index ec61ad07bd..bf28825f60 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -40,6 +40,7 @@ routines := \ inet_pton \ ns_makecanon \ ns_name_compress \ + ns_name_length_uncompressed \ ns_name_ntop \ ns_name_pack \ ns_name_pton \ @@ -111,6 +112,10 @@ tests-static += tst-resolv-txnid-collision tests-internal += tst-ns_samebinaryname tests-static += tst-ns_samebinaryname +# Likewise for __ns_name_length_uncompressed. +tests-internal += tst-ns_name_length_uncompressed +tests-static += tst-ns_name_length_uncompressed + # These tests need libdl. ifeq (yes,$(build-shared)) tests += \ diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c new file mode 100644 index 0000000000..51296b47ef --- /dev/null +++ b/resolv/ns_name_length_uncompressed.c @@ -0,0 +1,72 @@ +/* Skip over an uncompressed name in wire format. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +__ns_name_length_uncompressed (const unsigned char *p, + const unsigned char *eom) +{ + const unsigned char *start = p; + + while (true) + { + if (p == eom) + { + /* Truncated packet: no room for label length. */ + __set_errno (EMSGSIZE); + return -1; + } + + unsigned char b = *p; + ++p; + if (b == 0) + { + /* Root label. */ + size_t length = p - start; + if (length > NS_MAXCDNAME) + { + /* Domain name too long. */ + __set_errno (EMSGSIZE); + return -1; + } + return length; + } + + if (b <= 63) + { + /* Regular label. */ + if (b <= eom - p) + p += b; + else + { + /* Truncated packet: label incomplete. */ + __set_errno (EMSGSIZE); + return -1; + } + } + else + { + /* Compression reference or corrupted label length. */ + __set_errno (EMSGSIZE); + return -1; + } + } +} diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c new file mode 100644 index 0000000000..c4a2904db7 --- /dev/null +++ b/resolv/tst-ns_name_length_uncompressed.c @@ -0,0 +1,135 @@ +/* Test __ns_name_length_uncompressed. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +/* Reference implementation based on other building blocks. */ +static int +reference_length (const unsigned char *p, const unsigned char *eom) +{ + unsigned char buf[NS_MAXCDNAME]; + int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf)); + if (n < 0) + return n; + const unsigned char *q = buf; + if (__ns_name_skip (&q, array_end (buf)) < 0) + return -1; + if (q - buf != n) + /* Compressed name. */ + return -1; + return n; +} + +static int +do_test (void) +{ + { + unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 }; + TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2); + TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), + sizeof (buf) - 2); + TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1); + TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1, + array_end (buf)), 1); + buf[4] = 0xc0; /* Forward compression reference. */ + buf[5] = 0x06; + TEST_COMPARE (reference_length (buf, array_end (buf)), -1); + TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1); + } + + struct support_next_to_fault ntf = support_next_to_fault_allocate (300); + + /* Buffer region with all possible bytes at start and end. */ + for (int length = 1; length <= 300; ++length) + { + unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; + unsigned char *start = end - length; + memset (start, 'X', length); + for (int first = 0; first <= 255; ++first) + { + *start = first; + for (int last = 0; last <= 255; ++last) + { + start[length - 1] = last; + TEST_COMPARE (reference_length (start, end), + __ns_name_length_uncompressed (start, end)); + } + } + } + + /* Poor man's fuzz testing: patch two bytes. */ + { + unsigned char ref[] = + { + 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0 + }; + TEST_COMPARE (reference_length (ref, array_end (ref)), 13); + TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13); + + int good = 0; + int bad = 0; + for (int length = 1; length <= sizeof (ref); ++length) + { + unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; + unsigned char *start = end - length; + memcpy (start, ref, length); + + for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos) + { + for (int patch1_value = 0; patch1_value <= 255; ++patch1_value) + { + start[patch1_pos] = patch1_value; + for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos) + { + for (int patch2_value = 0; patch2_value <= 255; + ++patch2_value) + { + start[patch2_pos] = patch2_value; + int expected = reference_length (start, end); + errno = EINVAL; + int actual + = __ns_name_length_uncompressed (start, end); + if (actual > 0) + ++good; + else + { + TEST_COMPARE (errno, EMSGSIZE); + ++bad; + } + TEST_COMPARE (expected, actual); + } + start[patch2_pos] = ref[patch2_pos]; + } + } + start[patch1_pos] = ref[patch1_pos]; + } + } + printf ("info: patched inputs with success: %d\n", good); + printf ("info: patched inputs with failure: %d\n", bad); + } + + support_next_to_fault_free (&ntf); + return 0; +} + +#include -- cgit 1.4.1 From f0e9657067240b8b105c6d58d5da9dc926f2f0ed Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: resolv: Add DNS packet parsing helpers geared towards wire format The public parser functions around the ns_rr record type produce textual domain names, but usually, this is not what we need while parsing DNS packets within glibc. This commit adds two new helper functions, __ns_rr_cursor_init and __ns_rr_cursor_next, for writing packet parsers, and struct ns_rr_cursor, struct ns_rr_wire as supporting types. In theory, it is possible to avoid copying the owner name into the rname field in __ns_rr_cursor_next, but this would need more functions that work on compressed names. Eventually, __res_context_send could be enhanced to preserve the result of the packet parsing that is necessary for matching the incoming UDP packets, so that this works does not have to be done twice. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 857c890d9b42c50c8a94b76d47d4a61ab6d2f49c) --- include/arpa/nameser.h | 92 ++++++++++++++++++ resolv/Makefile | 6 ++ resolv/ns_rr_cursor_init.c | 62 +++++++++++++ resolv/ns_rr_cursor_next.c | 74 +++++++++++++++ resolv/tst-ns_rr_cursor.c | 227 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 461 insertions(+) create mode 100644 resolv/ns_rr_cursor_init.c create mode 100644 resolv/ns_rr_cursor_next.c create mode 100644 resolv/tst-ns_rr_cursor.c diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h index 6e4808f00d..c27e7886b7 100644 --- a/include/arpa/nameser.h +++ b/include/arpa/nameser.h @@ -103,5 +103,97 @@ libc_hidden_proto (__libc_ns_samename) must point one past the last byte in the packet. */ int __ns_name_length_uncompressed (const unsigned char *p, const unsigned char *eom) attribute_hidden; + +/* Iterator over the resource records in a DNS packet. */ +struct ns_rr_cursor +{ + /* These members are not changed after initialization. */ + const unsigned char *begin; /* First byte of packet. */ + const unsigned char *end; /* One past the last byte of the packet. */ + const unsigned char *first_rr; /* First resource record (or packet end). */ + + /* Advanced towards the end while reading the packet. */ + const unsigned char *current; +}; + +/* Returns the RCODE field from the DNS header. */ +static inline int +ns_rr_cursor_rcode (const struct ns_rr_cursor *c) +{ + return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */ +} + +/* Returns the length of the answer section according to the DNS header. */ +static inline int +ns_rr_cursor_ancount (const struct ns_rr_cursor *c) +{ + return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */ +} + +/* Returns the length of the authority (name server) section according + to the DNS header. */ +static inline int +ns_rr_cursor_nscount (const struct ns_rr_cursor *c) +{ + return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */ +} + +/* Returns the length of the additional data section according to the + DNS header. */ +static inline int +ns_rr_cursor_adcount (const struct ns_rr_cursor *c) +{ + return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */ +} + +/* Returns a pointer to the uncompressed question name in wire + format. */ +static inline const unsigned char * +ns_rr_cursor_qname (const struct ns_rr_cursor *c) +{ + return c->begin + 12; /* QNAME starts right after the header. */ +} + +/* Returns the question type of the first and only question. */ +static inline const int +ns_rr_cursor_qtype (const struct ns_rr_cursor *c) +{ + /* 16 bits 4 bytes back from the first RR header start. */ + return c->first_rr[-4] * 256 + c->first_rr[-3]; +} + +/* Returns the clss of the first and only question (usally C_IN). */ +static inline const int +ns_rr_cursor_qclass (const struct ns_rr_cursor *c) +{ + /* 16 bits 2 bytes back from the first RR header start. */ + return c->first_rr[-2] * 256 + c->first_rr[-1]; +} + +/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false + if LEN is less than sizeof (*HD), if the packet does not contain a + full (uncompressed) question, or if the question count is not 1. */ +_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c, + const unsigned char *buf, size_t len) + attribute_hidden; + +/* Like ns_rr, but the record owner name is not decoded into text format. */ +struct ns_rr_wire +{ + unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */ + uint16_t rtype; /* Resource record type (T_*). */ + uint16_t rclass; /* Resource record class (C_*). */ + uint32_t ttl; /* Time-to-live field. */ + const unsigned char *rdata; /* Start of resource record data. */ + uint16_t rdlength; /* Length of the data at rdata, in bytes. */ +}; + +/* Attempts to parse the record at C into *RR. On success, return + true, and C is advanced past the record, and RR->rdata points to + the record data. On failure, errno is set to EMSGSIZE, and false + is returned. */ +_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) + attribute_hidden; + # endif /* !_ISOMAC */ #endif diff --git a/resolv/Makefile b/resolv/Makefile index bf28825f60..018b1808d6 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -47,6 +47,8 @@ routines := \ ns_name_skip \ ns_name_uncompress \ ns_name_unpack \ + ns_rr_cursor_init \ + ns_rr_cursor_next \ ns_samebinaryname \ ns_samename \ nsap_addr \ @@ -116,6 +118,10 @@ tests-static += tst-ns_samebinaryname tests-internal += tst-ns_name_length_uncompressed tests-static += tst-ns_name_length_uncompressed +# Likewise for struct ns_rr_cursor and its functions. +tests-internal += tst-ns_rr_cursor +tests-static += tst-ns_rr_cursor + # These tests need libdl. ifeq (yes,$(build-shared)) tests += \ diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c new file mode 100644 index 0000000000..6ee80b30e9 --- /dev/null +++ b/resolv/ns_rr_cursor_init.c @@ -0,0 +1,62 @@ +/* Initialize a simple DNS packet parser. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +bool +__ns_rr_cursor_init (struct ns_rr_cursor *c, + const unsigned char *buf, size_t len) +{ + c->begin = buf; + c->end = buf + len; + + /* Check for header size and 16-bit question count value (it must be 1). */ + if (len < 12 || buf[4] != 0 || buf[5] != 1) + { + __set_errno (EMSGSIZE); + c->current = c->end; + return false; + } + c->current = buf + 12; + + int consumed = __ns_name_length_uncompressed (c->current, c->end); + if (consumed < 0) + { + __set_errno (EMSGSIZE); + c->current = c->end; + c->first_rr = NULL; + return false; + } + c->current += consumed; + + /* Ensure there is room for question type and class. */ + if (c->end - c->current < 4) + { + __set_errno (EMSGSIZE); + c->current = c->end; + c->first_rr = NULL; + return false; + } + c->current += 4; + c->first_rr = c->current; + + return true; +} diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c new file mode 100644 index 0000000000..33652fc5da --- /dev/null +++ b/resolv/ns_rr_cursor_next.c @@ -0,0 +1,74 @@ +/* Simple DNS record parser without textual name decoding. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +bool +__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) +{ + rr->rdata = NULL; + + /* Extract the record owner name. */ + int consumed = __ns_name_unpack (c->begin, c->end, c->current, + rr->rname, sizeof (rr->rname)); + if (consumed < 0) + { + memset (rr, 0, sizeof (*rr)); + __set_errno (EMSGSIZE); + return false; + } + c->current += consumed; + + /* Extract the metadata. */ + struct + { + uint16_t rtype; + uint16_t rclass; + uint32_t ttl; + uint16_t rdlength; + } __attribute__ ((packed)) metadata; + _Static_assert (sizeof (metadata) == 10, "sizeof metadata"); + if (c->end - c->current < sizeof (metadata)) + { + memset (rr, 0, sizeof (*rr)); + __set_errno (EMSGSIZE); + return false; + } + memcpy (&metadata, c->current, sizeof (metadata)); + c->current += sizeof (metadata); + /* Endianess conversion. */ + rr->rtype = ntohs (metadata.rtype); + rr->rclass = ntohs (metadata.rclass); + rr->ttl = ntohl (metadata.ttl); + rr->rdlength = ntohs (metadata.rdlength); + + /* Extract record data. */ + if (c->end - c->current < rr->rdlength) + { + memset (rr, 0, sizeof (*rr)); + __set_errno (EMSGSIZE); + return false; + } + rr->rdata = c->current; + c->current += rr->rdlength; + + return true; +} diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c new file mode 100644 index 0000000000..c3c0908905 --- /dev/null +++ b/resolv/tst-ns_rr_cursor.c @@ -0,0 +1,227 @@ +/* Tests for resource record parsing. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +/* Reference packet for packet parsing. */ +static const unsigned char valid_packet[] = + { 0x11, 0x12, 0x13, 0x14, + 0x00, 0x01, /* Question count. */ + 0x00, 0x02, /* Answer count. */ + 0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */ + 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0, + 0x00, 0x1c, /* Question type: AAAA. */ + 0x00, 0x01, /* Question class: IN. */ + 0xc0, 0x0c, /* Compression reference to QNAME. */ + 0x00, 0x1c, /* Record type: AAAA. */ + 0x00, 0x01, /* Record class: IN. */ + 0x12, 0x34, 0x56, 0x78, /* Record TTL. */ + 0x00, 0x10, /* Record data length (16 bytes). */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */ + 0xc0, 0x0c, /* Compression reference to QNAME. */ + 0x00, 0x1c, /* Record type: AAAA. */ + 0x00, 0x01, /* Record class: IN. */ + 0x11, 0x33, 0x55, 0x77, /* Record TTL. */ + 0x00, 0x10, /* Record data length (16 bytes). */ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */ + }; + +/* Special offsets in valid_packet. */ +enum + { + offset_of_first_record = 29, + offset_of_second_record = 57, + }; + +/* Check that parsing valid_packet succeeds. */ +static void +test_valid (void) +{ + struct ns_rr_cursor c; + TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet, + sizeof (valid_packet))); + TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); + TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); + TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); + TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); + TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); + TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); + TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); + TEST_COMPARE (c.current - valid_packet, offset_of_first_record); + + struct ns_rr_wire r; + TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); + TEST_COMPARE (r.rtype, T_AAAA); + TEST_COMPARE (r.rclass, C_IN); + TEST_COMPARE (r.ttl, 0x12345678); + TEST_COMPARE_BLOB (r.rdata, r.rdlength, + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); + TEST_COMPARE (c.current - valid_packet, offset_of_second_record); + TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); + TEST_COMPARE (r.rtype, T_AAAA); + TEST_COMPARE (r.rclass, C_IN); + TEST_COMPARE (r.ttl, 0x11335577); + TEST_COMPARE_BLOB (r.rdata, r.rdlength, + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16); + TEST_VERIFY (c.current == c.end); +} + +/* Check that trying to parse a packet with a compressed QNAME fails. */ +static void +test_compressed_qname (void) +{ + static const unsigned char packet[] = + { 0x11, 0x12, 0x13, 0x14, + 0x00, 0x01, /* Question count. */ + 0x00, 0x00, /* Answer count. */ + 0x00, 0x00, 0x00, 0x00, /* Other counts. */ + 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, + 0x00, 0x01, /* Question type: A. */ + 0x00, 0x01, /* Question class: IN. */ + }; + + struct ns_rr_cursor c; + TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); +} + +/* Check that trying to parse a packet with two questions fails. */ +static void +test_two_questions (void) +{ + static const unsigned char packet[] = + { 0x11, 0x12, 0x13, 0x14, + 0x00, 0x02, /* Question count. */ + 0x00, 0x00, /* Answer count. */ + 0x00, 0x00, 0x00, 0x00, /* Other counts. */ + 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, + 0x00, 0x01, /* Question type: A. */ + 0x00, 0x01, /* Question class: IN. */ + 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, + 0x00, 0x1c, /* Question type: AAAA. */ + 0x00, 0x01, /* Question class: IN. */ + }; + + struct ns_rr_cursor c; + TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); +} + +/* Used to check that parsing truncated packets does not over-read. */ +static struct support_next_to_fault ntf; + +/* Truncated packet in the second resource record. */ +static void +test_truncated_one_rr (size_t length) +{ + unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; + unsigned char *start = end - length; + + /* Produce the truncated packet. */ + memcpy (start, valid_packet, length); + + struct ns_rr_cursor c; + TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); + TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); + TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); + TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); + TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); + TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); + TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); + TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); + TEST_COMPARE (c.current - start, offset_of_first_record); + + struct ns_rr_wire r; + TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); + TEST_COMPARE (r.rtype, T_AAAA); + TEST_COMPARE (r.rclass, C_IN); + TEST_COMPARE (r.ttl, 0x12345678); + TEST_COMPARE_BLOB (r.rdata, r.rdlength, + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); + TEST_COMPARE (c.current - start, offset_of_second_record); + TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); +} + +/* Truncated packet in the first resource record. */ +static void +test_truncated_no_rr (size_t length) +{ + unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; + unsigned char *start = end - length; + + /* Produce the truncated packet. */ + memcpy (start, valid_packet, length); + + struct ns_rr_cursor c; + TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); + TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); + TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); + TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); + TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); + TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); + TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); + TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); + TEST_COMPARE (c.current - start, offset_of_first_record); + + struct ns_rr_wire r; + TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); +} + +/* Truncated packet before first resource record. */ +static void +test_truncated_before_rr (size_t length) +{ + unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; + unsigned char *start = end - length; + + /* Produce the truncated packet. */ + memcpy (start, valid_packet, length); + + struct ns_rr_cursor c; + TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length)); +} + +static int +do_test (void) +{ + ntf = support_next_to_fault_allocate (sizeof (valid_packet)); + + test_valid (); + test_compressed_qname (); + test_two_questions (); + + for (int length = offset_of_second_record; length < sizeof (valid_packet); + ++length) + test_truncated_one_rr (length); + for (int length = offset_of_first_record; length < offset_of_second_record; + ++length) + test_truncated_no_rr (length); + for (int length = 0; length < offset_of_first_record; ++length) + test_truncated_before_rr (length); + + support_next_to_fault_free (&ntf); + return 0; +} + +#include -- cgit 1.4.1 From b714ab7e3ce999b79401cdd22291128a7fd6d8ef Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: nss_dns: Split getanswer_ptr from getanswer_r And expand the use of name_ok and qtype in getanswer_ptr (the former also in getanswer_r). After further cleanups, not much code will be shared between the two functions. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 0dcc43e9981005540bf39dc7bf33fbab62cf9e84) --- resolv/nss_dns/dns-host.c | 320 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 268 insertions(+), 52 deletions(-) diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 544cffbecd..d384e1f82d 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -116,6 +116,11 @@ static enum nss_status getanswer_r (struct resolv_context *ctx, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp); +static enum nss_status getanswer_ptr (const querybuf *answer, int anslen, + const char *qname, + struct hostent *result, char *buffer, + size_t buflen, int *errnop, + int *h_errnop, int32_t *ttlp); static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, int anslen2, @@ -561,9 +566,8 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; } - status = getanswer_r - (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen, - errnop, h_errnop, 0 /* XXX */, ttlp, NULL); + status = getanswer_ptr (host_buffer.buf, n, qbuf, result, + buffer, buflen, errnop, h_errnop, ttlp); if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); if (status != NSS_STATUS_SUCCESS) @@ -659,8 +663,6 @@ getanswer_r (struct resolv_context *ctx, int haveanswer, had_error; char *bp, **ap, **hap; char tbuf[MAXDNAME]; - const char *tname; - int (*name_ok) (const char *); u_char packtmp[NS_MAXCDNAME]; int have_to_map = 0; uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); @@ -679,22 +681,8 @@ getanswer_r (struct resolv_context *ctx, if (buflen - sizeof (struct host_data) != linebuflen) linebuflen = INT_MAX; - tname = qname; result->h_name = NULL; end_of_message = answer->buf + anslen; - switch (qtype) - { - case T_A: - case T_AAAA: - name_ok = __libc_res_hnok; - break; - case T_PTR: - name_ok = __libc_res_dnok; - break; - default: - *errnop = ENOENT; - return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */ - } /* * find first satisfactory answer @@ -729,7 +717,7 @@ getanswer_r (struct resolv_context *ctx, *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } - if (__glibc_unlikely (name_ok (bp) == 0)) + if (__glibc_unlikely (__libc_res_hnok (bp) == 0)) { errno = EBADMSG; *errnop = EBADMSG; @@ -783,7 +771,7 @@ getanswer_r (struct resolv_context *ctx, n = -1; } - if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0)) + if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) { ++had_error; continue; @@ -816,7 +804,7 @@ getanswer_r (struct resolv_context *ctx, continue; /* XXX - had_error++ ? */ } - if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) + if (type == T_CNAME) { /* A CNAME could also have a TTL entry. */ if (ttlp != NULL && ttl < *ttlp) @@ -826,7 +814,7 @@ getanswer_r (struct resolv_context *ctx, continue; n = __libc_dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf); - if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0)) + if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) { ++had_error; continue; @@ -857,7 +845,260 @@ getanswer_r (struct resolv_context *ctx, continue; } - if (qtype == T_PTR && type == T_CNAME) + if (type == T_A && qtype == T_AAAA && map) + have_to_map = 1; + else if (__glibc_unlikely (type != qtype)) + { + cp += n; + continue; /* XXX - had_error++ ? */ + } + + switch (type) + { + case T_A: + case T_AAAA: + if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) + { + cp += n; + continue; /* XXX - had_error++ ? */ + } + + /* Stop parsing at a record whose length is incorrect. */ + if (n != rrtype_to_rdata_length (type)) + { + ++had_error; + break; + } + + /* Skip records of the wrong type. */ + if (n != result->h_length) + { + cp += n; + continue; + } + if (!haveanswer) + { + int nn; + + /* We compose a single hostent out of the entire chain of + entries, so the TTL of the hostent is essentially the lowest + TTL in the chain. */ + if (ttlp != NULL && ttl < *ttlp) + *ttlp = ttl; + if (canonp != NULL) + *canonp = bp; + result->h_name = bp; + nn = strlen (bp) + 1; /* for the \0 */ + bp += nn; + linebuflen -= nn; + } + + /* Provide sufficient alignment for both address + families. */ + enum { align = 4 }; + _Static_assert ((align % __alignof__ (struct in_addr)) == 0, + "struct in_addr alignment"); + _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, + "struct in6_addr alignment"); + { + char *new_bp = PTR_ALIGN_UP (bp, align); + linebuflen -= new_bp - bp; + bp = new_bp; + } + + if (__glibc_unlikely (n > linebuflen)) + goto too_small; + bp = __mempcpy (*hap++ = bp, cp, n); + cp += n; + linebuflen -= n; + break; + default: + abort (); + } + if (had_error == 0) + ++haveanswer; + } + + if (haveanswer > 0) + { + *ap = NULL; + *hap = NULL; + /* + * Note: we sort even if host can take only one address + * in its return structures - should give it the "best" + * address in that case, not some random one + */ + if (haveanswer > 1 && qtype == T_A + && __resolv_context_sort_count (ctx) > 0) + addrsort (ctx, host_data->h_addr_ptrs, haveanswer); + + if (result->h_name == NULL) + { + n = strlen (qname) + 1; /* For the \0. */ + if (n > linebuflen) + goto too_small; + if (n >= MAXHOSTNAMELEN) + goto no_recovery; + result->h_name = bp; + bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ + linebuflen -= n; + } + + if (have_to_map) + if (map_v4v6_hostent (result, &bp, &linebuflen)) + goto too_small; + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; + } + no_recovery: + *h_errnop = NO_RECOVERY; + *errnop = ENOENT; + /* Special case here: if the resolver sent a result but it only + contains a CNAME while we are looking for a T_A or T_AAAA record, + we fail with NOTFOUND instead of TRYAGAIN. */ + return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases + ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); +} + +static enum nss_status +getanswer_ptr (const querybuf *answer, int anslen, const char *qname, + struct hostent *result, char *buffer, size_t buflen, + int *errnop, int *h_errnop, int32_t *ttlp) +{ + struct host_data + { + char *aliases[MAX_NR_ALIASES]; + unsigned char host_addr[16]; /* IPv4 or IPv6 */ + char *h_addr_ptrs[0]; + } *host_data; + int linebuflen; + const HEADER *hp; + const u_char *end_of_message, *cp; + int n, ancount, qdcount; + int haveanswer, had_error; + char *bp, **ap, **hap; + char tbuf[MAXDNAME]; + const char *tname; + u_char packtmp[NS_MAXCDNAME]; + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + if (__glibc_unlikely (buflen < sizeof (struct host_data))) + { + /* The buffer is too small. */ + too_small: + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + host_data = (struct host_data *) buffer; + linebuflen = buflen - sizeof (struct host_data); + if (buflen - sizeof (struct host_data) != linebuflen) + linebuflen = INT_MAX; + + tname = qname; + result->h_name = NULL; + end_of_message = answer->buf + anslen; + + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + ancount = ntohs (hp->ancount); + qdcount = ntohs (hp->qdcount); + cp = answer->buf + HFIXEDSZ; + if (__glibc_unlikely (qdcount != 1)) + { + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) + goto too_small; + bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; + linebuflen -= (ancount + 1) * sizeof (char *); + + n = __ns_name_unpack (answer->buf, end_of_message, cp, + packtmp, sizeof packtmp); + if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) + { + if (__glibc_unlikely (errno == EMSGSIZE)) + goto too_small; + + n = -1; + } + + if (__glibc_unlikely (n < 0)) + { + *errnop = errno; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + if (__glibc_unlikely (__libc_res_dnok (bp) == 0)) + { + errno = EBADMSG; + *errnop = EBADMSG; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + cp += n + QFIXEDSZ; + + ap = host_data->aliases; + *ap = NULL; + result->h_aliases = host_data->aliases; + hap = host_data->h_addr_ptrs; + *hap = NULL; + result->h_addr_list = host_data->h_addr_ptrs; + haveanswer = 0; + had_error = 0; + + while (ancount-- > 0 && cp < end_of_message && had_error == 0) + { + int type, class; + + n = __ns_name_unpack (answer->buf, end_of_message, cp, + packtmp, sizeof packtmp); + if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) + { + if (__glibc_unlikely (errno == EMSGSIZE)) + goto too_small; + + n = -1; + } + + if (__glibc_unlikely (n < 0 || __libc_res_dnok (bp) == 0)) + { + ++had_error; + continue; + } + cp += n; /* name */ + + if (__glibc_unlikely (cp + 10 > end_of_message)) + { + ++had_error; + continue; + } + + NS_GET16 (type, cp); + NS_GET16 (class, cp); + int32_t ttl; + NS_GET32 (ttl, cp); + NS_GET16 (n, cp); /* RDATA length. */ + + if (end_of_message - cp < n) + { + /* RDATA extends beyond the end of the packet. */ + ++had_error; + continue; + } + + if (__glibc_unlikely (class != C_IN)) + { + /* XXX - debug? syslog? */ + cp += n; + continue; /* XXX - had_error++ ? */ + } + + if (type == T_CNAME) { /* A CNAME could also have a TTL entry. */ if (ttlp != NULL && ttl < *ttlp) @@ -886,14 +1127,6 @@ getanswer_r (struct resolv_context *ctx, continue; } - if (type == T_A && qtype == T_AAAA && map) - have_to_map = 1; - else if (__glibc_unlikely (type != qtype)) - { - cp += n; - continue; /* XXX - had_error++ ? */ - } - switch (type) { case T_PTR: @@ -955,8 +1188,6 @@ getanswer_r (struct resolv_context *ctx, TTL in the chain. */ if (ttlp != NULL && ttl < *ttlp) *ttlp = ttl; - if (canonp != NULL) - *canonp = bp; result->h_name = bp; nn = strlen (bp) + 1; /* for the \0 */ bp += nn; @@ -983,7 +1214,8 @@ getanswer_r (struct resolv_context *ctx, linebuflen -= n; break; default: - abort (); + cp += n; + continue; /* XXX - had_error++ ? */ } if (had_error == 0) ++haveanswer; @@ -993,14 +1225,6 @@ getanswer_r (struct resolv_context *ctx, { *ap = NULL; *hap = NULL; - /* - * Note: we sort even if host can take only one address - * in its return structures - should give it the "best" - * address in that case, not some random one - */ - if (haveanswer > 1 && qtype == T_A - && __resolv_context_sort_count (ctx) > 0) - addrsort (ctx, host_data->h_addr_ptrs, haveanswer); if (result->h_name == NULL) { @@ -1014,23 +1238,15 @@ getanswer_r (struct resolv_context *ctx, linebuflen -= n; } - if (have_to_map) - if (map_v4v6_hostent (result, &bp, &linebuflen)) - goto too_small; *h_errnop = NETDB_SUCCESS; return NSS_STATUS_SUCCESS; } no_recovery: *h_errnop = NO_RECOVERY; *errnop = ENOENT; - /* Special case here: if the resolver sent a result but it only - contains a CNAME while we are looking for a T_A or T_AAAA record, - we fail with NOTFOUND instead of TRYAGAIN. */ - return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases - ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); + return NSS_STATUS_TRYAGAIN; } - static enum nss_status gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, struct gaih_addrtuple ***patp, -- cgit 1.4.1 From 77f523c473878ec0051582ef15161c6982879095 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: nss_dns: Rewrite _nss_dns_gethostbyaddr2_r and getanswer_ptr The simplification takes advantage of the split from getanswer_r. It fixes various aliases issues, and optimizes NSS buffer usage. The new DNS packet parsing helpers are used, too. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit e32547d661a43da63368e488b6cfa9c53b4dcf92) --- resolv/nss_dns/dns-host.c | 405 ++++++++++++---------------------------------- 1 file changed, 102 insertions(+), 303 deletions(-) diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index d384e1f82d..cd26399b7e 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -69,6 +69,7 @@ * --Copyright-- */ +#include #include #include #include @@ -116,10 +117,9 @@ static enum nss_status getanswer_r (struct resolv_context *ctx, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp); -static enum nss_status getanswer_ptr (const querybuf *answer, int anslen, - const char *qname, - struct hostent *result, char *buffer, - size_t buflen, int *errnop, +static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, + struct alloc_buffer *abuf, + char **hnamep, int *errnop, int *h_errnop, int32_t *ttlp); static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, @@ -456,36 +456,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; static const u_char v6local[] = { 0,0, 0,1 }; const u_char *uaddr = (const u_char *)addr; - struct host_data - { - char *aliases[MAX_NR_ALIASES]; - unsigned char host_addr[16]; /* IPv4 or IPv6 */ - char *h_addr_ptrs[MAX_NR_ADDRS + 1]; - char linebuffer[0]; - } *host_data = (struct host_data *) buffer; - union - { - querybuf *buf; - u_char *ptr; - } host_buffer; - querybuf *orig_host_buffer; char qbuf[MAXDNAME+1], *qp = NULL; size_t size; int n, status; int olderr = errno; - uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); - buffer += pad; - buflen = buflen > pad ? buflen - pad : 0; - - if (__glibc_unlikely (buflen < sizeof (struct host_data))) - { - *errnop = ERANGE; - *h_errnop = NETDB_INTERNAL; - return NSS_STATUS_TRYAGAIN; - } - - host_data = (struct host_data *) buffer; + /* Prepare the allocation buffer. Store the pointer array first, to + benefit from buffer alignment. */ + struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); + char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2); + if (address_array == NULL) + { + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } struct resolv_context *ctx = __resolv_context_get (); if (ctx == NULL) @@ -529,8 +514,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, return NSS_STATUS_UNAVAIL; } - host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); - switch (af) { case AF_INET: @@ -554,35 +537,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, break; } - n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf, - 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); + unsigned char dns_packet_buffer[1024]; + unsigned char *alt_dns_packet_buffer = dns_packet_buffer; + n = __res_context_query (ctx, qbuf, C_IN, T_PTR, + dns_packet_buffer, sizeof (dns_packet_buffer), + &alt_dns_packet_buffer, + NULL, NULL, NULL, NULL); if (n < 0) { *h_errnop = h_errno; __set_errno (olderr); - if (host_buffer.buf != orig_host_buffer) - free (host_buffer.buf); + if (alt_dns_packet_buffer != dns_packet_buffer) + free (alt_dns_packet_buffer); __resolv_context_put (ctx); return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; } - status = getanswer_ptr (host_buffer.buf, n, qbuf, result, - buffer, buflen, errnop, h_errnop, ttlp); - if (host_buffer.buf != orig_host_buffer) - free (host_buffer.buf); + status = getanswer_ptr (alt_dns_packet_buffer, n, + &abuf, &result->h_name, errnop, h_errnop, ttlp); + + if (alt_dns_packet_buffer != dns_packet_buffer) + free (alt_dns_packet_buffer); + __resolv_context_put (ctx); + if (status != NSS_STATUS_SUCCESS) - { - __resolv_context_put (ctx); - return status; - } + return status; + /* result->h_name has already been set by getanswer_ptr. */ result->h_addrtype = af; result->h_length = len; - memcpy (host_data->host_addr, addr, len); - host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; - host_data->h_addr_ptrs[1] = NULL; + /* Increase the alignment to 4, in case there are applications out + there that expect at least this level of address alignment. */ + address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t); + alloc_buffer_copy_bytes (&abuf, uaddr, len); + address_array[1] = NULL; + + /* This check also covers allocation failure in getanswer_ptr. */ + if (alloc_buffer_has_failed (&abuf)) + { + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + result->h_addr_list = address_array; + result->h_aliases = &address_array[1]; /* Points to NULL. */ + *h_errnop = NETDB_SUCCESS; - __resolv_context_put (ctx); return NSS_STATUS_SUCCESS; } libc_hidden_def (_nss_dns_gethostbyaddr2_r) @@ -961,287 +961,86 @@ getanswer_r (struct resolv_context *ctx, } static enum nss_status -getanswer_ptr (const querybuf *answer, int anslen, const char *qname, - struct hostent *result, char *buffer, size_t buflen, +getanswer_ptr (unsigned char *packet, size_t packetlen, + struct alloc_buffer *abuf, char **hnamep, int *errnop, int *h_errnop, int32_t *ttlp) { - struct host_data - { - char *aliases[MAX_NR_ALIASES]; - unsigned char host_addr[16]; /* IPv4 or IPv6 */ - char *h_addr_ptrs[0]; - } *host_data; - int linebuflen; - const HEADER *hp; - const u_char *end_of_message, *cp; - int n, ancount, qdcount; - int haveanswer, had_error; - char *bp, **ap, **hap; - char tbuf[MAXDNAME]; - const char *tname; - u_char packtmp[NS_MAXCDNAME]; - uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); - buffer += pad; - buflen = buflen > pad ? buflen - pad : 0; - if (__glibc_unlikely (buflen < sizeof (struct host_data))) - { - /* The buffer is too small. */ - too_small: - *errnop = ERANGE; - *h_errnop = NETDB_INTERNAL; - return NSS_STATUS_TRYAGAIN; - } - host_data = (struct host_data *) buffer; - linebuflen = buflen - sizeof (struct host_data); - if (buflen - sizeof (struct host_data) != linebuflen) - linebuflen = INT_MAX; - - tname = qname; - result->h_name = NULL; - end_of_message = answer->buf + anslen; - - /* - * find first satisfactory answer - */ - hp = &answer->hdr; - ancount = ntohs (hp->ancount); - qdcount = ntohs (hp->qdcount); - cp = answer->buf + HFIXEDSZ; - if (__glibc_unlikely (qdcount != 1)) - { - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; - } - if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) - goto too_small; - bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; - linebuflen -= (ancount + 1) * sizeof (char *); - - n = __ns_name_unpack (answer->buf, end_of_message, cp, - packtmp, sizeof packtmp); - if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) + struct ns_rr_cursor c; + if (!__ns_rr_cursor_init (&c, packet, packetlen)) { - if (__glibc_unlikely (errno == EMSGSIZE)) - goto too_small; - - n = -1; - } - - if (__glibc_unlikely (n < 0)) - { - *errnop = errno; - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; - } - if (__glibc_unlikely (__libc_res_dnok (bp) == 0)) - { - errno = EBADMSG; - *errnop = EBADMSG; + /* This should not happen because __res_context_query already + perfroms response validation. */ *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } - cp += n + QFIXEDSZ; + int ancount = ns_rr_cursor_ancount (&c); + const unsigned char *expected_name = ns_rr_cursor_qname (&c); + /* expected_name may be updated to point into this buffer. */ + unsigned char name_buffer[NS_MAXCDNAME]; - ap = host_data->aliases; - *ap = NULL; - result->h_aliases = host_data->aliases; - hap = host_data->h_addr_ptrs; - *hap = NULL; - result->h_addr_list = host_data->h_addr_ptrs; - haveanswer = 0; - had_error = 0; - - while (ancount-- > 0 && cp < end_of_message && had_error == 0) + while (ancount > 0) { - int type, class; - - n = __ns_name_unpack (answer->buf, end_of_message, cp, - packtmp, sizeof packtmp); - if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) + struct ns_rr_wire rr; + if (!__ns_rr_cursor_next (&c, &rr)) { - if (__glibc_unlikely (errno == EMSGSIZE)) - goto too_small; - - n = -1; - } - - if (__glibc_unlikely (n < 0 || __libc_res_dnok (bp) == 0)) - { - ++had_error; - continue; - } - cp += n; /* name */ - - if (__glibc_unlikely (cp + 10 > end_of_message)) - { - ++had_error; - continue; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; } - NS_GET16 (type, cp); - NS_GET16 (class, cp); - int32_t ttl; - NS_GET32 (ttl, cp); - NS_GET16 (n, cp); /* RDATA length. */ + /* Skip over records with the wrong class. */ + if (rr.rclass != C_IN) + continue; - if (end_of_message - cp < n) - { - /* RDATA extends beyond the end of the packet. */ - ++had_error; - continue; - } - - if (__glibc_unlikely (class != C_IN)) - { - /* XXX - debug? syslog? */ - cp += n; - continue; /* XXX - had_error++ ? */ - } + /* Update TTL for known record types. */ + if ((rr.rtype == T_CNAME || rr.rtype == T_PTR) + && ttlp != NULL && *ttlp > rr.ttl) + *ttlp = rr.ttl; - if (type == T_CNAME) + if (rr.rtype == T_CNAME) { - /* A CNAME could also have a TTL entry. */ - if (ttlp != NULL && ttl < *ttlp) - *ttlp = ttl; - - n = __libc_dn_expand (answer->buf, end_of_message, cp, - tbuf, sizeof tbuf); - if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0)) - { - ++had_error; - continue; - } - cp += n; - /* Get canonical name. */ - n = strlen (tbuf) + 1; /* For the \0. */ - if (__glibc_unlikely (n > linebuflen)) - goto too_small; - if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) + /* NB: No check for owner name match, based on historic + precedent. Record the CNAME target as the new expected + name. */ + int n = __ns_name_unpack (c.begin, c.end, rr.rdata, + name_buffer, sizeof (name_buffer)); + if (n < 0) { - ++had_error; - continue; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; } - tname = bp; - bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ - linebuflen -= n; - continue; + expected_name = name_buffer; } - - switch (type) + else if (rr.rtype == T_PTR + && __ns_samebinaryname (rr.rname, expected_name)) { - case T_PTR: - if (__glibc_unlikely (__strcasecmp (tname, bp) != 0)) - { - cp += n; - continue; /* XXX - had_error++ ? */ - } - - n = __ns_name_unpack (answer->buf, end_of_message, cp, - packtmp, sizeof packtmp); - if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) - { - if (__glibc_unlikely (errno == EMSGSIZE)) - goto too_small; - - n = -1; - } - - if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) + /* Decompress the target of the PTR record. This is the + host name we are looking for. We can only use it if it + is syntactically valid. Historically, only one host name + is returned here. If the recursive resolver performs DNS + record rotation, the returned host name is essentially + random, which is why multiple PTR records are rarely + used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for + additional length checking. */ + char hname[MAXHOSTNAMELEN + 1]; + if (__ns_name_unpack (c.begin, c.end, rr.rdata, + name_buffer, sizeof (name_buffer)) < 0 + || !__res_binary_hnok (expected_name) + || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0) { - ++had_error; - break; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; } - if (ttlp != NULL && ttl < *ttlp) - *ttlp = ttl; - /* bind would put multiple PTR records as aliases, but we don't do - that. */ - result->h_name = bp; - *h_errnop = NETDB_SUCCESS; + /* Successful allocation is checked by the caller. */ + *hnamep = alloc_buffer_copy_string (abuf, hname); return NSS_STATUS_SUCCESS; - case T_A: - case T_AAAA: - if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) - { - cp += n; - continue; /* XXX - had_error++ ? */ - } - - /* Stop parsing at a record whose length is incorrect. */ - if (n != rrtype_to_rdata_length (type)) - { - ++had_error; - break; - } - - /* Skip records of the wrong type. */ - if (n != result->h_length) - { - cp += n; - continue; - } - if (!haveanswer) - { - int nn; - - /* We compose a single hostent out of the entire chain of - entries, so the TTL of the hostent is essentially the lowest - TTL in the chain. */ - if (ttlp != NULL && ttl < *ttlp) - *ttlp = ttl; - result->h_name = bp; - nn = strlen (bp) + 1; /* for the \0 */ - bp += nn; - linebuflen -= nn; - } - - /* Provide sufficient alignment for both address - families. */ - enum { align = 4 }; - _Static_assert ((align % __alignof__ (struct in_addr)) == 0, - "struct in_addr alignment"); - _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, - "struct in6_addr alignment"); - { - char *new_bp = PTR_ALIGN_UP (bp, align); - linebuflen -= new_bp - bp; - bp = new_bp; - } - - if (__glibc_unlikely (n > linebuflen)) - goto too_small; - bp = __mempcpy (*hap++ = bp, cp, n); - cp += n; - linebuflen -= n; - break; - default: - cp += n; - continue; /* XXX - had_error++ ? */ } - if (had_error == 0) - ++haveanswer; } - if (haveanswer > 0) - { - *ap = NULL; - *hap = NULL; - - if (result->h_name == NULL) - { - n = strlen (qname) + 1; /* For the \0. */ - if (n > linebuflen) - goto too_small; - if (n >= MAXHOSTNAMELEN) - goto no_recovery; - result->h_name = bp; - bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ - linebuflen -= n; - } + /* No PTR record found. */ + if (ttlp != NULL) + /* No caching of negative responses. */ + *ttlp = 0; - *h_errnop = NETDB_SUCCESS; - return NSS_STATUS_SUCCESS; - } - no_recovery: *h_errnop = NO_RECOVERY; *errnop = ENOENT; return NSS_STATUS_TRYAGAIN; -- cgit 1.4.1 From 5165080fec63a1f03aa1985b77bca300465bf570 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: nss_dns: Remove remnants of IPv6 address mapping res_use_inet6 always returns false since commit 3f8b44be0a658266adff5 ("resolv: Remove support for RES_USE_INET6 and the inet6 option"). Reviewed-by: Siddhesh Poyarekar (cherry picked from commit a7fc30b522a0cd7c8c5e7e285b9531b704e02f04) --- resolv/README | 3 -- resolv/mapv4v6addr.h | 69 -------------------------------------- resolv/mapv4v6hostent.h | 84 ----------------------------------------------- resolv/nss_dns/dns-host.c | 54 +++++------------------------- 4 files changed, 9 insertions(+), 201 deletions(-) delete mode 100644 resolv/mapv4v6addr.h delete mode 100644 resolv/mapv4v6hostent.h diff --git a/resolv/README b/resolv/README index 514e9bb617..2146bc3b27 100644 --- a/resolv/README +++ b/resolv/README @@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c. res_hconf.c and res_hconf.h were contributed by David Mosberger, and do not come from BIND. - -The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are -leftovers from BIND 4.9.7. diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h deleted file mode 100644 index 7f85f7d5e3..0000000000 --- a/resolv/mapv4v6addr.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ++Copyright++ 1985, 1988, 1993 - * - - * Copyright (c) 1985, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - - * --Copyright-- - */ - -#include -#include - -static void -map_v4v6_address (const char *src, char *dst) -{ - u_char *p = (u_char *) dst; - int i; - - /* Move the IPv4 part to the right position. */ - memcpy (dst + 12, src, INADDRSZ); - - /* Mark this ipv6 addr as a mapped ipv4. */ - for (i = 0; i < 10; i++) - *p++ = 0x00; - *p++ = 0xff; - *p = 0xff; -} diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h deleted file mode 100644 index c11038adf3..0000000000 --- a/resolv/mapv4v6hostent.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ++Copyright++ 1985, 1988, 1993 - * - - * Copyright (c) 1985, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - - * --Copyright-- - */ - -#include -#include - -typedef union { - int32_t al; - char ac; -} align; - -static int -map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp) -{ - char **ap; - - if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) - return 0; - hp->h_addrtype = AF_INET6; - hp->h_length = IN6ADDRSZ; - for (ap = hp->h_addr_list; *ap; ap++) - { - int i = sizeof (align) - ((u_long) *bpp % sizeof (align)); - - if (*lenp < (i + IN6ADDRSZ)) - /* Out of memory. */ - return 1; - *bpp += i; - *lenp -= i; - map_v4v6_address (*ap, *bpp); - *ap = *bpp; - *bpp += IN6ADDRSZ; - *lenp -= IN6ADDRSZ; - } - return 0; -} diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index cd26399b7e..8e38583e15 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -87,10 +87,6 @@ #include #include -/* Get implementations of some internal functions. */ -#include -#include - #define RESOLVSORT #if PACKETSZ > 65536 @@ -116,7 +112,7 @@ static enum nss_status getanswer_r (struct resolv_context *ctx, const char *qname, int qtype, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, - int map, int32_t *ttlp, char **canonp); + int32_t *ttlp, char **canonp); static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, struct alloc_buffer *abuf, char **hnamep, int *errnop, @@ -197,7 +193,6 @@ gethostbyname3_context (struct resolv_context *ctx, char tmp[NS_MAXDNAME]; int size, type, n; const char *cp; - int map = 0; int olderr = errno; enum nss_status status; @@ -258,32 +253,12 @@ gethostbyname3_context (struct resolv_context *ctx, *errnop = EAGAIN; else __set_errno (olderr); - - /* If we are looking for an IPv6 address and mapping is enabled - by having the RES_USE_INET6 bit in _res.options set, we try - another lookup. */ - if (af == AF_INET6 && res_use_inet6 ()) - n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf, - host_buffer.buf != orig_host_buffer - ? MAXPACKET : 1024, &host_buffer.ptr, - NULL, NULL, NULL, NULL); - - if (n < 0) - { - if (host_buffer.buf != orig_host_buffer) - free (host_buffer.buf); - return status; - } - - map = 1; - - result->h_addrtype = AF_INET; - result->h_length = INADDRSZ; } + else + status = getanswer_r + (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, + errnop, h_errnop, ttlp, canonp); - status = getanswer_r - (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, - errnop, h_errnop, map, ttlp, canonp); if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); return status; @@ -329,13 +304,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, *h_errnop = NETDB_INTERNAL; return NSS_STATUS_UNAVAIL; } - status = NSS_STATUS_NOTFOUND; - if (res_use_inet6 ()) - status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, - buflen, errnop, h_errnop, NULL, NULL); - if (status == NSS_STATUS_NOTFOUND) - status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, - buflen, errnop, h_errnop, NULL, NULL); + status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, + buflen, errnop, h_errnop, NULL, NULL); __resolv_context_put (ctx); return status; } @@ -648,7 +618,7 @@ static enum nss_status getanswer_r (struct resolv_context *ctx, const querybuf *answer, int anslen, const char *qname, int qtype, struct hostent *result, char *buffer, size_t buflen, - int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp) + int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) { struct host_data { @@ -664,7 +634,6 @@ getanswer_r (struct resolv_context *ctx, char *bp, **ap, **hap; char tbuf[MAXDNAME]; u_char packtmp[NS_MAXCDNAME]; - int have_to_map = 0; uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); buffer += pad; buflen = buflen > pad ? buflen - pad : 0; @@ -845,9 +814,7 @@ getanswer_r (struct resolv_context *ctx, continue; } - if (type == T_A && qtype == T_AAAA && map) - have_to_map = 1; - else if (__glibc_unlikely (type != qtype)) + if (__glibc_unlikely (type != qtype)) { cp += n; continue; /* XXX - had_error++ ? */ @@ -944,9 +911,6 @@ getanswer_r (struct resolv_context *ctx, linebuflen -= n; } - if (have_to_map) - if (map_v4v6_hostent (result, &bp, &linebuflen)) - goto too_small; *h_errnop = NETDB_SUCCESS; return NSS_STATUS_SUCCESS; } -- cgit 1.4.1 From 78c8ef21fa54e994451d5b42ead6080d99a88a49 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: nss_dns: Rewrite getanswer_r to match getanswer_ptr (bug 12154, bug 29305) Allocate the pointer arrays only at the end, when their sizes are known. This addresses bug 29305. Skip over invalid names instead of failing lookups. This partially fixes bug 12154 (for gethostbyname, fixing getaddrinfo requires different changes). Reviewed-by: Siddhesh Poyarekar (cherry picked from commit d101d836e7e4bd1d4e4972b0e0bd0a55c9b650fa) --- resolv/nss_dns/dns-host.c | 478 +++++++++++++++++----------------------------- 1 file changed, 180 insertions(+), 298 deletions(-) diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 8e38583e15..b887e77e9c 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -107,12 +107,19 @@ typedef union querybuf u_char buf[MAXPACKET]; } querybuf; -static enum nss_status getanswer_r (struct resolv_context *ctx, - const querybuf *answer, int anslen, - const char *qname, int qtype, - struct hostent *result, char *buffer, - size_t buflen, int *errnop, int *h_errnop, - int32_t *ttlp, char **canonp); +/* For historic reasons, pointers to IP addresses are char *, so use a + single list type for addresses and host names. */ +#define DYNARRAY_STRUCT ptrlist +#define DYNARRAY_ELEMENT char * +#define DYNARRAY_PREFIX ptrlist_ +#include + +static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen, + uint16_t qtype, struct alloc_buffer *abuf, + struct ptrlist *addresses, + struct ptrlist *aliases, + int *errnop, int *h_errnop, int32_t *ttlp); +static void addrsort (struct resolv_context *ctx, char **ap, int num); static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, struct alloc_buffer *abuf, char **hnamep, int *errnop, @@ -184,12 +191,6 @@ gethostbyname3_context (struct resolv_context *ctx, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) { - union - { - querybuf *buf; - u_char *ptr; - } host_buffer; - querybuf *orig_host_buffer; char tmp[NS_MAXDNAME]; int size, type, n; const char *cp; @@ -223,10 +224,12 @@ gethostbyname3_context (struct resolv_context *ctx, && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL) name = cp; - host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); + unsigned char dns_packet_buffer[1024]; + unsigned char *alt_dns_packet_buffer = dns_packet_buffer; - n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf, - 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); + n = __res_context_search (ctx, name, C_IN, type, + dns_packet_buffer, sizeof (dns_packet_buffer), + &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); if (n < 0) { switch (errno) @@ -255,12 +258,77 @@ gethostbyname3_context (struct resolv_context *ctx, __set_errno (olderr); } else - status = getanswer_r - (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, - errnop, h_errnop, ttlp, canonp); + { + struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); - if (host_buffer.buf != orig_host_buffer) - free (host_buffer.buf); + struct ptrlist addresses; + ptrlist_init (&addresses); + struct ptrlist aliases; + ptrlist_init (&aliases); + + status = getanswer_r (alt_dns_packet_buffer, n, type, + &abuf, &addresses, &aliases, + errnop, h_errnop, ttlp); + if (status == NSS_STATUS_SUCCESS) + { + if (ptrlist_has_failed (&addresses) + || ptrlist_has_failed (&aliases)) + { + /* malloc failure. Do not retry using the ERANGE protocol. */ + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + status = NSS_STATUS_UNAVAIL; + } + + /* Reserve the address and alias arrays in the result + buffer. Both are NULL-terminated, but the first element + of the alias array is stored in h_name, so no extra space + for the NULL terminator is needed there. */ + result->h_addr_list + = alloc_buffer_alloc_array (&abuf, char *, + ptrlist_size (&addresses) + 1); + result->h_aliases + = alloc_buffer_alloc_array (&abuf, char *, + ptrlist_size (&aliases)); + if (alloc_buffer_has_failed (&abuf)) + { + /* Retry using the ERANGE protocol. */ + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + status = NSS_STATUS_TRYAGAIN; + } + else + { + /* Copy the address list and NULL-terminate it. */ + memcpy (result->h_addr_list, ptrlist_begin (&addresses), + ptrlist_size (&addresses) * sizeof (char *)); + result->h_addr_list[ptrlist_size (&addresses)] = NULL; + + /* Sort the address list if requested. */ + if (type == T_A && __resolv_context_sort_count (ctx) > 0) + addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses)); + + /* Copy the aliases, excluding the last one. */ + memcpy (result->h_aliases, ptrlist_begin (&aliases), + (ptrlist_size (&aliases) - 1) * sizeof (char *)); + result->h_aliases[ptrlist_size (&aliases) - 1] = NULL; + + /* The last alias goes into h_name. */ + assert (ptrlist_size (&aliases) >= 1); + result->h_name = ptrlist_end (&aliases)[-1]; + + /* This is also the canonical name. */ + if (canonp != NULL) + *canonp = result->h_name; + } + } + + ptrlist_free (&aliases); + ptrlist_free (&addresses); + } + + if (alt_dns_packet_buffer != dns_packet_buffer) + free (alt_dns_packet_buffer); return status; } @@ -614,314 +682,128 @@ addrsort (struct resolv_context *ctx, char **ap, int num) break; } -static enum nss_status -getanswer_r (struct resolv_context *ctx, - const querybuf *answer, int anslen, const char *qname, int qtype, - struct hostent *result, char *buffer, size_t buflen, - int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) +/* Convert the uncompressed, binary domain name CDNAME into its + textual representation and add it to the end of ALIASES, allocating + space for a copy of the name from ABUF. Skip adding the name if it + is not a valid host name, and return false in that case, otherwise + true. */ +static bool +getanswer_r_store_alias (const unsigned char *cdname, + struct alloc_buffer *abuf, + struct ptrlist *aliases) { - struct host_data - { - char *aliases[MAX_NR_ALIASES]; - unsigned char host_addr[16]; /* IPv4 or IPv6 */ - char *h_addr_ptrs[0]; - } *host_data; - int linebuflen; - const HEADER *hp; - const u_char *end_of_message, *cp; - int n, ancount, qdcount; - int haveanswer, had_error; - char *bp, **ap, **hap; - char tbuf[MAXDNAME]; - u_char packtmp[NS_MAXCDNAME]; - uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); - buffer += pad; - buflen = buflen > pad ? buflen - pad : 0; - if (__glibc_unlikely (buflen < sizeof (struct host_data))) - { - /* The buffer is too small. */ - too_small: - *errnop = ERANGE; - *h_errnop = NETDB_INTERNAL; - return NSS_STATUS_TRYAGAIN; - } - host_data = (struct host_data *) buffer; - linebuflen = buflen - sizeof (struct host_data); - if (buflen - sizeof (struct host_data) != linebuflen) - linebuflen = INT_MAX; - - result->h_name = NULL; - end_of_message = answer->buf + anslen; - - /* - * find first satisfactory answer - */ - hp = &answer->hdr; - ancount = ntohs (hp->ancount); - qdcount = ntohs (hp->qdcount); - cp = answer->buf + HFIXEDSZ; - if (__glibc_unlikely (qdcount != 1)) - { - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; - } - if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) - goto too_small; - bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; - linebuflen -= (ancount + 1) * sizeof (char *); - - n = __ns_name_unpack (answer->buf, end_of_message, cp, - packtmp, sizeof packtmp); - if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) - { - if (__glibc_unlikely (errno == EMSGSIZE)) - goto too_small; - - n = -1; - } + /* Filter out domain names that are not host names. */ + if (!__res_binary_hnok (cdname)) + return false; + + /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks + for length. */ + char dname[MAXHOSTNAMELEN + 1]; + if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0) + return false; + /* Do not report an error on allocation failure, instead store NULL + or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS + and detect the memory allocation failure or buffer space + exhaustion, and report it accordingly. */ + ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname)); + return true; +} - if (__glibc_unlikely (n < 0)) - { - *errnop = errno; - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; - } - if (__glibc_unlikely (__libc_res_hnok (bp) == 0)) +static enum nss_status __attribute__ ((noinline)) +getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype, + struct alloc_buffer *abuf, + struct ptrlist *addresses, struct ptrlist *aliases, + int *errnop, int *h_errnop, int32_t *ttlp) +{ + struct ns_rr_cursor c; + if (!__ns_rr_cursor_init (&c, packet, packetlen)) { - errno = EBADMSG; - *errnop = EBADMSG; + /* This should not happen because __res_context_query already + perfroms response validation. */ *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } - cp += n + QFIXEDSZ; - if (qtype == T_A || qtype == T_AAAA) + /* Treat the QNAME just like an alias. Error out if it is not a + valid host name. */ + if (ns_rr_cursor_rcode (&c) == NXDOMAIN + || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases)) { - /* res_send() has already verified that the query name is the - * same as the one we sent; this just gets the expanded name - * (i.e., with the succeeding search-domain tacked on). - */ - n = strlen (bp) + 1; /* for the \0 */ - if (n >= MAXHOSTNAMELEN) - { - *h_errnop = NO_RECOVERY; - *errnop = ENOENT; - return NSS_STATUS_TRYAGAIN; - } - result->h_name = bp; - bp += n; - linebuflen -= n; - if (linebuflen < 0) - goto too_small; - /* The qname can be abbreviated, but h_name is now absolute. */ - qname = result->h_name; + if (ttlp != NULL) + /* No negative caching. */ + *ttlp = 0; + *h_errnop = HOST_NOT_FOUND; + *errnop = ENOENT; + return NSS_STATUS_NOTFOUND; } - ap = host_data->aliases; - *ap = NULL; - result->h_aliases = host_data->aliases; - hap = host_data->h_addr_ptrs; - *hap = NULL; - result->h_addr_list = host_data->h_addr_ptrs; - haveanswer = 0; - had_error = 0; + int ancount = ns_rr_cursor_ancount (&c); + const unsigned char *expected_name = ns_rr_cursor_qname (&c); + /* expected_name may be updated to point into this buffer. */ + unsigned char name_buffer[NS_MAXCDNAME]; - while (ancount-- > 0 && cp < end_of_message && had_error == 0) + for (; ancount > 0; --ancount) { - int type, class; - - n = __ns_name_unpack (answer->buf, end_of_message, cp, - packtmp, sizeof packtmp); - if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) - { - if (__glibc_unlikely (errno == EMSGSIZE)) - goto too_small; - - n = -1; - } - - if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) - { - ++had_error; - continue; - } - cp += n; /* name */ - - if (__glibc_unlikely (cp + 10 > end_of_message)) + struct ns_rr_wire rr; + if (!__ns_rr_cursor_next (&c, &rr)) { - ++had_error; - continue; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; } - NS_GET16 (type, cp); - NS_GET16 (class, cp); - int32_t ttl; - NS_GET32 (ttl, cp); - NS_GET16 (n, cp); /* RDATA length. */ - - if (end_of_message - cp < n) - { - /* RDATA extends beyond the end of the packet. */ - ++had_error; - continue; - } + /* Skip over records with the wrong class. */ + if (rr.rclass != C_IN) + continue; - if (__glibc_unlikely (class != C_IN)) - { - /* XXX - debug? syslog? */ - cp += n; - continue; /* XXX - had_error++ ? */ - } + /* Update TTL for recognized record types. */ + if ((rr.rtype == T_CNAME || rr.rtype == qtype) + && ttlp != NULL && *ttlp > rr.ttl) + *ttlp = rr.ttl; - if (type == T_CNAME) + if (rr.rtype == T_CNAME) { - /* A CNAME could also have a TTL entry. */ - if (ttlp != NULL && ttl < *ttlp) - *ttlp = ttl; - - if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1]) - continue; - n = __libc_dn_expand (answer->buf, end_of_message, cp, - tbuf, sizeof tbuf); - if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) - { - ++had_error; - continue; - } - cp += n; - /* Store alias. */ - *ap++ = bp; - n = strlen (bp) + 1; /* For the \0. */ - if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) - { - ++had_error; - continue; - } - bp += n; - linebuflen -= n; - /* Get canonical name. */ - n = strlen (tbuf) + 1; /* For the \0. */ - if (__glibc_unlikely (n > linebuflen)) - goto too_small; - if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) + /* NB: No check for owner name match, based on historic + precedent. Record the CNAME target as the new expected + name. */ + int n = __ns_name_unpack (c.begin, c.end, rr.rdata, + name_buffer, sizeof (name_buffer)); + if (n < 0) { - ++had_error; - continue; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; } - result->h_name = bp; - bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ - linebuflen -= n; - continue; + /* And store the new name as an alias. */ + getanswer_r_store_alias (name_buffer, abuf, aliases); + expected_name = name_buffer; } - - if (__glibc_unlikely (type != qtype)) + else if (rr.rtype == qtype + && __ns_samebinaryname (rr.rname, expected_name) + && rr.rdlength == rrtype_to_rdata_length (qtype)) { - cp += n; - continue; /* XXX - had_error++ ? */ + /* Make a copy of the address and store it. Increase the + alignment to 4, in case there are applications out there + that expect at least this level of address alignment. */ + ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t)); + alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength); } - - switch (type) - { - case T_A: - case T_AAAA: - if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) - { - cp += n; - continue; /* XXX - had_error++ ? */ - } - - /* Stop parsing at a record whose length is incorrect. */ - if (n != rrtype_to_rdata_length (type)) - { - ++had_error; - break; - } - - /* Skip records of the wrong type. */ - if (n != result->h_length) - { - cp += n; - continue; - } - if (!haveanswer) - { - int nn; - - /* We compose a single hostent out of the entire chain of - entries, so the TTL of the hostent is essentially the lowest - TTL in the chain. */ - if (ttlp != NULL && ttl < *ttlp) - *ttlp = ttl; - if (canonp != NULL) - *canonp = bp; - result->h_name = bp; - nn = strlen (bp) + 1; /* for the \0 */ - bp += nn; - linebuflen -= nn; - } - - /* Provide sufficient alignment for both address - families. */ - enum { align = 4 }; - _Static_assert ((align % __alignof__ (struct in_addr)) == 0, - "struct in_addr alignment"); - _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, - "struct in6_addr alignment"); - { - char *new_bp = PTR_ALIGN_UP (bp, align); - linebuflen -= new_bp - bp; - bp = new_bp; - } - - if (__glibc_unlikely (n > linebuflen)) - goto too_small; - bp = __mempcpy (*hap++ = bp, cp, n); - cp += n; - linebuflen -= n; - break; - default: - abort (); - } - if (had_error == 0) - ++haveanswer; } - if (haveanswer > 0) + if (ptrlist_size (addresses) == 0) { - *ap = NULL; - *hap = NULL; - /* - * Note: we sort even if host can take only one address - * in its return structures - should give it the "best" - * address in that case, not some random one - */ - if (haveanswer > 1 && qtype == T_A - && __resolv_context_sort_count (ctx) > 0) - addrsort (ctx, host_data->h_addr_ptrs, haveanswer); - - if (result->h_name == NULL) - { - n = strlen (qname) + 1; /* For the \0. */ - if (n > linebuflen) - goto too_small; - if (n >= MAXHOSTNAMELEN) - goto no_recovery; - result->h_name = bp; - bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ - linebuflen -= n; - } + /* No address record found. */ + if (ttlp != NULL) + /* No caching of negative responses. */ + *ttlp = 0; + *h_errnop = NO_RECOVERY; + *errnop = ENOENT; + return NSS_STATUS_TRYAGAIN; + } + else + { *h_errnop = NETDB_SUCCESS; return NSS_STATUS_SUCCESS; } - no_recovery: - *h_errnop = NO_RECOVERY; - *errnop = ENOENT; - /* Special case here: if the resolver sent a result but it only - contains a CNAME while we are looking for a T_A or T_AAAA record, - we fail with NOTFOUND instead of TRYAGAIN. */ - return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases - ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); } static enum nss_status -- cgit 1.4.1 From 7a236dc44a22dc4252e803d1ee1d3b970ec43805 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: nss_dns: In gaih_getanswer_slice, skip strange aliases (bug 12154) If the name is not a host name, skip adding it to the result, instead of reporting query failure. This fixes bug 12154 for getaddrinfo. This commit still keeps the old parsing code, and only adjusts when a host name is copied. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 32b599ac8c21c4c332cc3900a792a1395bca79c7) --- resolv/nss_dns/dns-host.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index b887e77e9c..bea505d697 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -970,12 +970,12 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, n = -1; } - if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0)) + if (__glibc_unlikely (n < 0)) { ++had_error; continue; } - if (*firstp && canon == NULL) + if (*firstp && canon == NULL && __libc_res_hnok (buffer)) { h_name = buffer; buffer += h_namelen; @@ -1021,14 +1021,14 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, n = __libc_dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf); - if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) + if (__glibc_unlikely (n < 0)) { ++had_error; continue; } cp += n; - if (*firstp) + if (*firstp && __libc_res_hnok (tbuf)) { /* Reclaim buffer space. */ if (h_name + h_namelen == buffer) -- cgit 1.4.1 From e2ec6a8db38a6b734bbdb41e498fdc9460f7566a Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: resolv: Add new tst-resolv-invalid-cname This test checks resolution through CNAME chains that do not contain host names (bug 12154). Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 9caf782276ecea4bc86fc94fbb52779736f3106d) --- resolv/Makefile | 3 + resolv/tst-resolv-invalid-cname.c | 406 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 409 insertions(+) create mode 100644 resolv/tst-resolv-invalid-cname.c diff --git a/resolv/Makefile b/resolv/Makefile index 018b1808d6..f8a92c6cff 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -98,6 +98,7 @@ tests += \ tst-resolv-binary \ tst-resolv-byaddr \ tst-resolv-edns \ + tst-resolv-invalid-cname \ tst-resolv-network \ tst-resolv-noaaaa \ tst-resolv-nondecimal \ @@ -287,6 +288,8 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ $(shared-thread-library) $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \ $(shared-thread-library) +$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \ + $(shared-thread-library) $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c new file mode 100644 index 0000000000..ae2d4419b1 --- /dev/null +++ b/resolv/tst-resolv-invalid-cname.c @@ -0,0 +1,406 @@ +/* Test handling of CNAMEs with non-host domain names (bug 12154). + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Query strings describe the CNAME chain in the response. They have + the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are + replaced by unsigned decimal numbers. COUNT is the number of CNAME + records in the response. BITS has two bits for each CNAME record, + describing a special prefix that is added to that CNAME. + + 0: No special leading label. + 1: Starting with "*.". + 2: Starting with "-x.". + 3: Starting with "star.*.". + + The first CNAME in the response using the two least significant + bits. + + For PTR queries, the QNAME format is different, it is either + COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still + decimal), or: + +COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. + + where BITS and COUNT are hexadecimal. */ + +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + TEST_COMPARE (qclass, C_IN); + + /* The only other query type besides A is PTR. */ + if (qtype != T_A && qtype != T_AAAA) + TEST_COMPARE (qtype, T_PTR); + + unsigned int bits, bits1, count; + char *tail = NULL; + if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3) + TEST_COMPARE_STRING (tail, "example"); + else if (strstr (qname, "in-addr.arpa") != NULL + && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3) + TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa"); + else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4) + { + TEST_COMPARE_STRING (tail, "\ +0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); + bits |= bits1 << 4; + } + else + FAIL_EXIT1 ("invalid QNAME: %s\n", qname); + free (tail); + + struct resolv_response_flags flags = {}; + resolv_response_init (b, flags); + resolv_response_add_question (b, qname, qclass, qtype); + resolv_response_section (b, ns_s_an); + + /* Provide the requested number of CNAME records. */ + char *previous_name = (char *) qname; + unsigned int original_bits = bits; + for (int unique = 0; unique < count; ++unique) + { + resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); + + static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." }; + char *new_name = xasprintf ("%sunique%d.example", + bits_to_prefix[bits & 3], unique); + bits >>= 2; + resolv_response_add_name (b, new_name); + resolv_response_close_record (b); + + if (previous_name != qname) + free (previous_name); + previous_name = new_name; + } + + /* Actual answer record. */ + resolv_response_open_record (b, previous_name, qclass, qtype, 60); + switch (qtype) + { + case T_A: + { + char ipv4[4] = {192, 168, count, original_bits}; + resolv_response_add_data (b, &ipv4, sizeof (ipv4)); + } + break; + case T_AAAA: + { + char ipv6[16] = + { + 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + count, original_bits + }; + resolv_response_add_data (b, &ipv6, sizeof (ipv6)); + } + break; + + case T_PTR: + { + char *name = xasprintf ("bits%u.count%u.example", + original_bits, count); + resolv_response_add_name (b, name); + free (name); + } + break; + } + resolv_response_close_record (b); + + if (previous_name != qname) + free (previous_name); +} + +/* Controls which name resolution function is invoked. */ +enum test_mode + { + byname, /* gethostbyname. */ + byname2, /* gethostbyname2. */ + gai, /* getaddrinfo without AI_CANONNAME. */ + gai_canon, /* getaddrinfo with AI_CANONNAME. */ + + test_mode_num /* Number of enum values. */ + }; + +static const char * +test_mode_to_string (enum test_mode mode) +{ + switch (mode) + { + case byname: + return "byname"; + case byname2: + return "byname2"; + case gai: + return "gai"; + case gai_canon: + return "gai_canon"; + case test_mode_num: + /* Report error below. */ + } + FAIL_EXIT1 ("invalid test_mode: %d", mode); +} + +/* Append the name and aliases to OUT. */ +static void +append_names (FILE *out, const char *qname, int bits, int count, + enum test_mode mode) +{ + /* Largest valid index which has a corresponding zero in bits + (meaning a syntactically valid CNAME). */ + int last_valid_cname = -1; + + for (int i = 0; i < count; ++i) + if ((bits & (3 << (i * 2))) == 0) + last_valid_cname = i; + + if (mode != gai) + { + const char *label; + if (mode == gai_canon) + label = "canonname"; + else + label = "name"; + if (last_valid_cname >= 0) + fprintf (out, "%s: unique%d.example\n", label, last_valid_cname); + else + fprintf (out, "%s: %s\n", label, qname); + } + + if (mode == byname || mode == byname2) + { + if (last_valid_cname >= 0) + fprintf (out, "alias: %s\n", qname); + for (int i = 0; i < count; ++i) + { + if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname) + fprintf (out, "alias: unique%d.example\n", i); + } + } +} + +/* Append the address information to OUT. */ +static void +append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode) +{ + int last = count * 256 + bits; + if (mode == gai || mode == gai_canon) + { + if (af == AF_INET || af == AF_UNSPEC) + fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits); + if (af == AF_INET6 || af == AF_UNSPEC) + { + if (last == 0) + fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n"); + else + fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last); + } + } + else + { + TEST_VERIFY (af != AF_UNSPEC); + if (af == AF_INET) + fprintf (out, "address: 192.168.%d.%d\n", count, bits); + if (af == AF_INET6) + { + if (last == 0) + fprintf (out, "address: 2001:db8::\n"); + else + fprintf (out, "address: 2001:db8::%x\n", last); + } + } +} + +/* Perform one test using a forward lookup. */ +static void +check_forward (int af, int bits, int count, enum test_mode mode) +{ + char *qname = xasprintf ("bits%d.count%d.example", bits, count); + char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s", + af, bits, count, test_mode_to_string (mode), qname); + + struct xmemstream expected; + xopen_memstream (&expected); + if (mode == gai_canon) + fprintf (expected.out, "flags: AI_CANONNAME\n"); + append_names (expected.out, qname, bits, count, mode); + append_addresses (expected.out, af, bits, count, mode); + xfclose_memstream (&expected); + + if (mode == gai || mode == gai_canon) + { + struct addrinfo *ai; + struct addrinfo hints = + { + .ai_family = af, + .ai_socktype = SOCK_STREAM, + }; + if (mode == gai_canon) + hints.ai_flags |= AI_CANONNAME; + int ret = getaddrinfo (qname, "80", &hints, &ai); + check_addrinfo (label, ai, ret, expected.buffer); + if (ret == 0) + freeaddrinfo (ai); + } + else + { + struct hostent *e; + if (mode == gai) + { + TEST_COMPARE (af, AF_INET); + e = gethostbyname (qname); + } + else + { + if (af != AF_INET) + TEST_COMPARE (af, AF_INET6); + e = gethostbyname2 (qname, af); + } + check_hostent (label, e, expected.buffer); + } + + free (expected.buffer); + free (label); + free (qname); +} + +/* Perform one check using a reverse lookup. */ + +static void +check_reverse (int af, int bits, int count) +{ + TEST_VERIFY (af == AF_INET || af == AF_INET6); + + char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count); + char *fqdn = xasprintf ("bits%d.count%d.example", bits, count); + + struct xmemstream expected; + xopen_memstream (&expected); + fprintf (expected.out, "name: %s\n", fqdn); + append_addresses (expected.out, af, bits, count, byname); + xfclose_memstream (&expected); + + char addr[16] = { 0 }; + socklen_t addrlen; + if (af == AF_INET) + { + addr[0] = 192; + addr[1] = 168; + addr[2] = count; + addr[3] = bits; + addrlen = 4; + } + else + { + addr[0] = 0x20; + addr[1] = 0x01; + addr[2] = 0x0d; + addr[3] = 0xb8; + addr[14] = count; + addr[15] = bits; + addrlen = 16; + } + + struct hostent *e = gethostbyaddr (addr, addrlen, af); + check_hostent (label, e, expected.buffer); + + /* getnameinfo check is different. There is no generic check_* + function for it. */ + { + struct sockaddr_in sin = { }; + struct sockaddr_in6 sin6 = { }; + void *sa; + socklen_t salen; + if (af == AF_INET) + { + sin.sin_family = AF_INET; + memcpy (&sin.sin_addr, addr, addrlen); + sin.sin_port = htons (80); + sa = &sin; + salen = sizeof (sin); + } + else + { + sin6.sin6_family = AF_INET6; + memcpy (&sin6.sin6_addr, addr, addrlen); + sin6.sin6_port = htons (80); + sa = &sin6; + salen = sizeof (sin6); + } + + char host[64]; + char service[64]; + int ret = getnameinfo (sa, salen, host, + sizeof (host), service, sizeof (service), + NI_NAMEREQD | NI_NUMERICSERV); + TEST_COMPARE (ret, 0); + TEST_COMPARE_STRING (host, fqdn); + TEST_COMPARE_STRING (service, "80"); + } + + free (expected.buffer); + free (fqdn); + free (label); +} + +static int +do_test (void) +{ + struct resolv_test *obj = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response + }); + + for (int count = 0; count <= 3; ++count) + for (int bits = 0; bits <= 1 << (count * 2); ++bits) + { + if (count > 0 && bits == count) + /* The last bits value is only checked if count == 0. */ + continue; + + for (enum test_mode mode = 0; mode < test_mode_num; ++mode) + { + check_forward (AF_INET, bits, count, mode); + if (mode != byname) + check_forward (AF_INET6, bits, count, mode); + if (mode == gai || mode == gai_canon) + check_forward (AF_UNSPEC, bits, count, mode); + } + + check_reverse (AF_INET, bits, count); + check_reverse (AF_INET6, bits, count); + } + + resolv_test_end (obj); + + return 0; +} + +#include -- cgit 1.4.1 From c5cdb39c20e96d9ac0d46fc7284b8276a537fd35 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 10:02:49 +0200 Subject: nss_dns: Rewrite _nss_dns_gethostbyname4_r using current interfaces Introduce struct alloc_buffer to this function, and use it and struct ns_rr_cursor in gaih_getanswer_slice. Adjust gaih_getanswer and gaih_getanswer_noaaaa accordingly. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 1d495912a746e2a1ffb780c9a81fd234ec2464e8) --- resolv/nss_dns/dns-host.c | 443 +++++++++++++++++----------------------------- 1 file changed, 162 insertions(+), 281 deletions(-) diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index bea505d697..9fa81f23c8 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -100,13 +100,6 @@ #endif #define MAXHOSTNAMELEN 256 -/* We need this time later. */ -typedef union querybuf -{ - HEADER hdr; - u_char buf[MAXPACKET]; -} querybuf; - /* For historic reasons, pointers to IP addresses are char *, so use a single list type for addresses and host names. */ #define DYNARRAY_STRUCT ptrlist @@ -125,18 +118,18 @@ static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, char **hnamep, int *errnop, int *h_errnop, int32_t *ttlp); -static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, - const querybuf *answer2, int anslen2, - const char *qname, +static enum nss_status gaih_getanswer (unsigned char *packet1, + size_t packet1len, + unsigned char *packet2, + size_t packet2len, + struct alloc_buffer *abuf, struct gaih_addrtuple **pat, - char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp); -static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1, - int anslen1, - const char *qname, +static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet, + size_t packetlen, + struct alloc_buffer *abuf, struct gaih_addrtuple **pat, - char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp); @@ -408,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, name = cp; } - union - { - querybuf *buf; - u_char *ptr; - } host_buffer; - querybuf *orig_host_buffer; - host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048); + unsigned char dns_packet_buffer[2048]; + unsigned char *alt_dns_packet_buffer = dns_packet_buffer; u_char *ans2p = NULL; int nans2p = 0; int resplen2 = 0; int ans2p_malloced = 0; + struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); int olderr = errno; @@ -427,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, if ((ctx->resp->options & RES_NOAAAA) == 0) { n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, - host_buffer.buf->buf, 2048, &host_buffer.ptr, - &ans2p, &nans2p, &resplen2, &ans2p_malloced); + dns_packet_buffer, sizeof (dns_packet_buffer), + &alt_dns_packet_buffer, &ans2p, &nans2p, + &resplen2, &ans2p_malloced); if (n >= 0) - status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, - resplen2, name, pat, buffer, buflen, - errnop, herrnop, ttlp); + status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2, + &abuf, pat, errnop, herrnop, ttlp); } else { n = __res_context_search (ctx, name, C_IN, T_A, - host_buffer.buf->buf, 2048, NULL, - NULL, NULL, NULL, NULL); + dns_packet_buffer, sizeof (dns_packet_buffer), + NULL, NULL, NULL, NULL, NULL); if (n >= 0) - status = gaih_getanswer_noaaaa (host_buffer.buf, n, - name, pat, buffer, buflen, - errnop, herrnop, ttlp); + status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, + &abuf, pat, errnop, herrnop, ttlp); } if (n < 0) { @@ -473,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, __set_errno (olderr); } + /* Implement the buffer resizing protocol. */ + if (alloc_buffer_has_failed (&abuf)) + { + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + status = NSS_STATUS_TRYAGAIN; + } + /* Check whether ans2p was separately allocated. */ if (ans2p_malloced) free (ans2p); - if (host_buffer.buf != orig_host_buffer) - free (host_buffer.buf); + if (alt_dns_packet_buffer != dns_packet_buffer) + free (alt_dns_packet_buffer); __resolv_context_put (ctx); return status; @@ -892,259 +888,152 @@ getanswer_ptr (unsigned char *packet, size_t packetlen, return NSS_STATUS_TRYAGAIN; } +/* Parses DNS data found in PACKETLEN bytes at PACKET in struct + gaih_addrtuple address tuples. The new address tuples are linked + from **TAILP, with backing store allocated from ABUF, and *TAILP is + updated to point where the next tuple pointer should be stored. If + TTLP is not null, *TTLP is updated to reflect the minimum TTL. If + STORE_CANON is true, the canonical name is stored as part of the + first address tuple being written. */ static enum nss_status -gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, - struct gaih_addrtuple ***patp, - char **bufferp, size_t *buflenp, - int *errnop, int *h_errnop, int32_t *ttlp, int *firstp) +gaih_getanswer_slice (unsigned char *packet, size_t packetlen, + struct alloc_buffer *abuf, + struct gaih_addrtuple ***tailp, + int *errnop, int *h_errnop, int32_t *ttlp, + bool store_canon) { - char *buffer = *bufferp; - size_t buflen = *buflenp; - - struct gaih_addrtuple **pat = *patp; - const HEADER *hp = &answer->hdr; - int ancount = ntohs (hp->ancount); - int qdcount = ntohs (hp->qdcount); - const u_char *cp = answer->buf + HFIXEDSZ; - const u_char *end_of_message = answer->buf + anslen; - if (__glibc_unlikely (qdcount != 1)) - { - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; - } - - u_char packtmp[NS_MAXCDNAME]; - int n = __ns_name_unpack (answer->buf, end_of_message, cp, - packtmp, sizeof packtmp); - /* We unpack the name to check it for validity. But we do not need - it later. */ - if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1) - { - if (__glibc_unlikely (errno == EMSGSIZE)) - { - too_small: - *errnop = ERANGE; - *h_errnop = NETDB_INTERNAL; - return NSS_STATUS_TRYAGAIN; - } - - n = -1; - } - - if (__glibc_unlikely (n < 0)) - { - *errnop = errno; - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; - } - if (__glibc_unlikely (__libc_res_hnok (buffer) == 0)) + struct ns_rr_cursor c; + if (!__ns_rr_cursor_init (&c, packet, packetlen)) { - errno = EBADMSG; - *errnop = EBADMSG; + /* This should not happen because __res_context_query already + perfroms response validation. */ *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } - cp += n + QFIXEDSZ; + bool haveanswer = false; /* Set to true if at least one address. */ + uint16_t qtype = ns_rr_cursor_qtype (&c); + int ancount = ns_rr_cursor_ancount (&c); + const unsigned char *expected_name = ns_rr_cursor_qname (&c); + /* expected_name may be updated to point into this buffer. */ + unsigned char name_buffer[NS_MAXCDNAME]; - int haveanswer = 0; - int had_error = 0; - char *canon = NULL; - char *h_name = NULL; - int h_namelen = 0; + /* This is a pointer to a possibly-compressed name in the packet. + Eventually it is equivalent to the canonical name. If needed, it + is uncompressed and translated to text form when the first + address tuple is encountered. */ + const unsigned char *compressed_alias_name = expected_name; - if (ancount == 0) + if (ancount == 0 || !__res_binary_hnok (compressed_alias_name)) { *h_errnop = HOST_NOT_FOUND; return NSS_STATUS_NOTFOUND; } - while (ancount-- > 0 && cp < end_of_message && had_error == 0) + for (; ancount > -0; --ancount) { - n = __ns_name_unpack (answer->buf, end_of_message, cp, - packtmp, sizeof packtmp); - if (n != -1 && - (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1) - { - if (__glibc_unlikely (errno == EMSGSIZE)) - goto too_small; - - n = -1; - } - if (__glibc_unlikely (n < 0)) - { - ++had_error; - continue; - } - if (*firstp && canon == NULL && __libc_res_hnok (buffer)) - { - h_name = buffer; - buffer += h_namelen; - buflen -= h_namelen; - } - - cp += n; /* name */ - - if (__glibc_unlikely (cp + 10 > end_of_message)) - { - ++had_error; - continue; - } - - uint16_t type; - NS_GET16 (type, cp); - uint16_t class; - NS_GET16 (class, cp); - int32_t ttl; - NS_GET32 (ttl, cp); - NS_GET16 (n, cp); /* RDATA length. */ - - if (end_of_message - cp < n) + struct ns_rr_wire rr; + if (!__ns_rr_cursor_next (&c, &rr)) { - /* RDATA extends beyond the end of the packet. */ - ++had_error; - continue; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; } - if (class != C_IN) - { - cp += n; - continue; - } + /* Update TTL for known record types. */ + if ((rr.rtype == T_CNAME || rr.rtype == qtype) + && ttlp != NULL && *ttlp > rr.ttl) + *ttlp = rr.ttl; - if (type == T_CNAME) + if (rr.rtype == T_CNAME) { - char tbuf[MAXDNAME]; - - /* A CNAME could also have a TTL entry. */ - if (ttlp != NULL && ttl < *ttlp) - *ttlp = ttl; - - n = __libc_dn_expand (answer->buf, end_of_message, cp, - tbuf, sizeof tbuf); - if (__glibc_unlikely (n < 0)) - { - ++had_error; - continue; - } - cp += n; - - if (*firstp && __libc_res_hnok (tbuf)) + /* NB: No check for owner name match, based on historic + precedent. Record the CNAME target as the new expected + name. */ + int n = __ns_name_unpack (c.begin, c.end, rr.rdata, + name_buffer, sizeof (name_buffer)); + if (n < 0) { - /* Reclaim buffer space. */ - if (h_name + h_namelen == buffer) - { - buffer = h_name; - buflen += h_namelen; - } - - n = strlen (tbuf) + 1; - if (__glibc_unlikely (n > buflen)) - goto too_small; - if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) - { - ++had_error; - continue; - } - - canon = buffer; - buffer = __mempcpy (buffer, tbuf, n); - buflen -= n; - h_namelen = 0; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; } - continue; + expected_name = name_buffer; + if (store_canon && __res_binary_hnok (name_buffer)) + /* This name can be used as a canonical name. Do not + translate to text form here to conserve buffer space. + Point to the compressed name because name_buffer can be + overwritten with an unusable name later. */ + compressed_alias_name = rr.rdata; } - - /* Stop parsing if we encounter a record with incorrect RDATA - length. */ - if (type == T_A || type == T_AAAA) + else if (rr.rtype == qtype + && __ns_samebinaryname (rr.rname, expected_name) + && rr.rdlength == rrtype_to_rdata_length (qtype)) { - if (n != rrtype_to_rdata_length (type)) + struct gaih_addrtuple *ntup + = alloc_buffer_alloc (abuf, struct gaih_addrtuple); + /* Delay error reporting to the callers (they implement the + ERANGE buffer resizing handshake). */ + if (ntup != NULL) { - ++had_error; - continue; + ntup->next = NULL; + if (store_canon && compressed_alias_name != NULL) + { + /* This assumes that all the CNAME records come + first. Use MAXHOSTNAMELEN instead of + NS_MAXCDNAME for additional length checking. + However, these checks are not expected to fail + because all size NS_MAXCDNAME names should into + the hname buffer because no escaping is + needed. */ + char unsigned nbuf[NS_MAXCDNAME]; + char hname[MAXHOSTNAMELEN + 1]; + if (__ns_name_unpack (c.begin, c.end, + compressed_alias_name, + nbuf, sizeof (nbuf)) >= 0 + && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0) + /* Space checking is performed by the callers. */ + ntup->name = alloc_buffer_copy_string (abuf, hname); + store_canon = false; + } + else + ntup->name = NULL; + if (rr.rdlength == 4) + ntup->family = AF_INET; + else + ntup->family = AF_INET6; + memcpy (ntup->addr, rr.rdata, rr.rdlength); + ntup->scopeid = 0; + + /* Link in the new tuple, and update the tail pointer to + point to its next field. */ + **tailp = ntup; + *tailp = &ntup->next; + + haveanswer = true; } } - else - { - /* Skip unknown records. */ - cp += n; - continue; - } - - assert (type == T_A || type == T_AAAA); - if (*pat == NULL) - { - uintptr_t pad = (-(uintptr_t) buffer - % __alignof__ (struct gaih_addrtuple)); - buffer += pad; - buflen = buflen > pad ? buflen - pad : 0; - - if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) - goto too_small; - - *pat = (struct gaih_addrtuple *) buffer; - buffer += sizeof (struct gaih_addrtuple); - buflen -= sizeof (struct gaih_addrtuple); - } - - (*pat)->name = NULL; - (*pat)->next = NULL; - - if (*firstp) - { - /* We compose a single hostent out of the entire chain of - entries, so the TTL of the hostent is essentially the lowest - TTL in the chain. */ - if (ttlp != NULL && ttl < *ttlp) - *ttlp = ttl; - - (*pat)->name = canon ?: h_name; - - *firstp = 0; - } - - (*pat)->family = type == T_A ? AF_INET : AF_INET6; - memcpy ((*pat)->addr, cp, n); - cp += n; - (*pat)->scopeid = 0; - - pat = &((*pat)->next); - - haveanswer = 1; } if (haveanswer) { - *patp = pat; - *bufferp = buffer; - *buflenp = buflen; - *h_errnop = NETDB_SUCCESS; return NSS_STATUS_SUCCESS; } - - /* Special case here: if the resolver sent a result but it only - contains a CNAME while we are looking for a T_A or T_AAAA record, - we fail with NOTFOUND instead of TRYAGAIN. */ - if (canon != NULL) + else { + /* Special case here: if the resolver sent a result but it only + contains a CNAME while we are looking for a T_A or T_AAAA + record, we fail with NOTFOUND. */ *h_errnop = HOST_NOT_FOUND; return NSS_STATUS_NOTFOUND; } - - *h_errnop = NETDB_INTERNAL; - return NSS_STATUS_TRYAGAIN; } static enum nss_status -gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, - int anslen2, const char *qname, - struct gaih_addrtuple **pat, char *buffer, size_t buflen, +gaih_getanswer (unsigned char *packet1, size_t packet1len, + unsigned char *packet2, size_t packet2len, + struct alloc_buffer *abuf, struct gaih_addrtuple **pat, int *errnop, int *h_errnop, int32_t *ttlp) { - int first = 1; - enum nss_status status = NSS_STATUS_NOTFOUND; /* Combining the NSS status of two distinct queries requires some @@ -1156,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable). A recoverable TRYAGAIN is almost always due to buffer size issues and returns ERANGE in errno and the caller is expected to retry - with a larger buffer. + with a larger buffer. (The caller, _nss_dns_gethostbyname4_r, + ignores the return status if it detects that the result buffer + has been exhausted and generates a TRYAGAIN failure with an + ERANGE code.) Lastly, you may be tempted to make significant changes to the conditions in this code to bring about symmetry between responses. @@ -1236,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, is a recoverable error we now return TRYAGIN even if the first response was SUCCESS. */ - if (anslen1 > 0) - status = gaih_getanswer_slice(answer1, anslen1, qname, - &pat, &buffer, &buflen, - errnop, h_errnop, ttlp, - &first); - - if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND - || (status == NSS_STATUS_TRYAGAIN - /* We want to look at the second answer in case of an - NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e. - *h_errnop is NO_RECOVERY. If not, and if the failure was due to - an insufficient buffer (ERANGE), then we need to drop the results - and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can - repeat the query with a larger buffer. */ - && (*errnop != ERANGE || *h_errnop == NO_RECOVERY))) - && answer2 != NULL && anslen2 > 0) + if (packet1len > 0) { - enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname, - &pat, &buffer, &buflen, - errnop, h_errnop, ttlp, - &first); + status = gaih_getanswer_slice (packet1, packet1len, + abuf, &pat, errnop, h_errnop, ttlp, true); + if (alloc_buffer_has_failed (abuf)) + /* Do not try parsing the second packet if a larger result + buffer is needed. The caller implements the resizing + protocol because *abuf has been exhausted. */ + return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */ + } + + if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND) + && packet2 != NULL && packet2len > 0) + { + enum nss_status status2 + = gaih_getanswer_slice (packet2, packet2len, + abuf, &pat, errnop, h_errnop, ttlp, + /* Success means that data with a + canonical name has already been + stored. Do not store the name again. */ + status != NSS_STATUS_SUCCESS); /* Use the second response status in some cases. */ if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND) status = status2; - /* Do not return a truncated second response (unless it was - unavoidable e.g. unrecoverable TRYAGAIN). */ - if (status == NSS_STATUS_SUCCESS - && (status2 == NSS_STATUS_TRYAGAIN - && *errnop == ERANGE && *h_errnop != NO_RECOVERY)) - status = NSS_STATUS_TRYAGAIN; } return status; @@ -1273,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, /* Variant of gaih_getanswer without a second (AAAA) response. */ static enum nss_status -gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname, - struct gaih_addrtuple **pat, - char *buffer, size_t buflen, +gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen, + struct alloc_buffer *abuf, struct gaih_addrtuple **pat, int *errnop, int *h_errnop, int32_t *ttlp) { - int first = 1; - enum nss_status status = NSS_STATUS_NOTFOUND; - if (anslen1 > 0) - status = gaih_getanswer_slice (answer1, anslen1, qname, - &pat, &buffer, &buflen, - errnop, h_errnop, ttlp, - &first); + if (packetlen > 0) + status = gaih_getanswer_slice (packet, packetlen, + abuf, &pat, errnop, h_errnop, ttlp, true); return status; } -- cgit 1.4.1 From a7fa604f3050a1024dc8ec28ff28bad811f6151f Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 30 Aug 2022 13:30:03 +0200 Subject: resolv: Fix building tst-resolv-invalid-cname for earlier C standards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes this compiler error: tst-resolv-invalid-cname.c: In function ‘test_mode_to_string’: tst-resolv-invalid-cname.c:164:10: error: label at end of compound statement case test_mode_num: ^~~~~~~~~~~~~ Fixes commit 9caf782276ecea4bc86fc94fbb52779736f3106d ("resolv: Add new tst-resolv-invalid-cname"). (cherry picked from commit d09aa4a17229bcaa2ec7642006b12612498582e7) --- resolv/tst-resolv-invalid-cname.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c index ae2d4419b1..63dac90e02 100644 --- a/resolv/tst-resolv-invalid-cname.c +++ b/resolv/tst-resolv-invalid-cname.c @@ -162,7 +162,7 @@ test_mode_to_string (enum test_mode mode) case gai_canon: return "gai_canon"; case test_mode_num: - /* Report error below. */ + break; /* Report error below. */ } FAIL_EXIT1 ("invalid test_mode: %d", mode); } -- cgit 1.4.1 From 5d885617cec5713fdde42177398fe98acb66b7a2 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 13 Sep 2022 13:22:27 +0200 Subject: NEWS: Note bug 12154 and bug 29305 as fixed --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 9360596fcc..03281e3ab4 100644 --- a/NEWS +++ b/NEWS @@ -16,7 +16,9 @@ Security related changes: The following bugs are resolved with this release: + [12154] Do not fail DNS resolution for CNAMEs which are not host names [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning + [29305] Conserve NSS buffer space during DNS packet parsing [29415] nscd: Fix netlink cache invalidation if epoll is used [29446] _dlopen now ignores dl_caller argument in static mode [29485] Linux: Terminate subprocess on late failure in tst-pidfd -- cgit 1.4.1 From df51334828f2af214105aad82042140ee3a6de0a Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 13 Sep 2022 19:57:43 +0200 Subject: elf: Run tst-audit-tlsdesc, tst-audit-tlsdesc-dlopen everywhere The test is valid for all TLS models, but we want to make a reasonable effort to test the GNU2 model specifically. For example, aarch64 defaults to GNU2, but does not have -mtls-dialect=gnu2, and the test was not run there. Suggested-by: Martin Coufal (cherry picked from commit dd2315a866a4ac2b838ea1cb10c5ea1c35d51a2f) Fixes early backport commit 924e4f3eaa502ce82fccf8537f021a796d158771 ("elf: Call __libc_early_init for reused namespaces (bug 29528)"); it had a wrong conflict resolution. --- elf/Makefile | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/elf/Makefile b/elf/Makefile index 43353a4b08..72178d33ff 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -374,6 +374,8 @@ tests += \ tst-align \ tst-align2 \ tst-align3 \ + tst-audit-tlsdesc \ + tst-audit-tlsdesc-dlopen \ tst-audit1 \ tst-audit2 \ tst-audit8 \ @@ -766,6 +768,8 @@ modules-names += \ tst-alignmod3 \ tst-array2dep \ tst-array5dep \ + tst-audit-tlsdesc-mod1 \ + tst-audit-tlsdesc-mod2 \ tst-audit11mod1 \ tst-audit11mod2 \ tst-audit12mod1 \ @@ -799,6 +803,7 @@ modules-names += \ tst-auditmanymod7 \ tst-auditmanymod8 \ tst-auditmanymod9 \ + tst-auditmod-tlsdesc \ tst-auditmod1 \ tst-auditmod9a \ tst-auditmod9b \ @@ -993,23 +998,8 @@ modules-names += tst-gnu2-tls1mod $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so tst-gnu2-tls1mod.so-no-z-defs = yes CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2 +endif # $(have-mtls-dialect-gnu2) -tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen -modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc -$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ - $(objpfx)tst-audit-tlsdesc-mod2.so \ - $(shared-thread-library) -CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 -CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 -$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) -$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \ - $(objpfx)tst-audit-tlsdesc-mod2.so -$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so -$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so -tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so -$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so -tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so -endif ifeq (yes,$(have-protected-data)) modules-names += tst-protected1moda tst-protected1modb tests += tst-protected1a tst-protected1b -- cgit 1.4.1 From 4b95b6e8bbb5a2b6856f707bf3bc3308ebef595a Mon Sep 17 00:00:00 2001 From: Javier Pello Date: Mon, 5 Sep 2022 20:09:01 +0200 Subject: elf: Fix hwcaps string size overestimation Commit dad90d528259b669342757c37dedefa8577e2636 added glibc-hwcaps support for LD_LIBRARY_PATH and, for this, it adjusted the total string size required in _dl_important_hwcaps. However, in doing so it inadvertently altered the calculation of the size required for the power set strings, as the computation of the power set string size depended on the first value assigned to the total variable, which is later shifted, resulting in overallocation of string space. Fix this now by using a different variable to hold the string size required for glibc-hwcaps. Signed-off-by: Javier Pello (cherry picked from commit a23820f6052a740246fdc7dcd9c43ce8eed0c45a) --- elf/dl-hwcaps.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c index 6f161f6ad5..92eb53790e 100644 --- a/elf/dl-hwcaps.c +++ b/elf/dl-hwcaps.c @@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix and a "/" suffix once stored in the result. */ hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1; - size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) + size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) + hwcaps_counts.total_length); /* Count the number of bits set in the masked value. */ @@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, assert (m == cnt); /* Determine the total size of all strings together. */ + size_t total; if (cnt == 1) - total += temp[0].len + 1; + total = temp[0].len + 1; else { - total += temp[0].len + temp[cnt - 1].len + 2; + total = temp[0].len + temp[cnt - 1].len + 2; if (cnt > 2) { total <<= 1; @@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, /* This is the overall result, including both glibc-hwcaps subdirectories and the legacy hwcaps subdirectories using the power set construction. */ + total += hwcaps_sz; struct r_strlenpair *overall_result = malloc (*sz * sizeof (*result) + total); if (overall_result == NULL) -- cgit 1.4.1 From 7a3f8c8a7aeb41d4bbfeec07d0be1e92c3019919 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 6 Sep 2022 07:38:10 +0200 Subject: scripts/dso-ordering-test.py: Generate program run-time dependencies The main program needs to depend on all shared objects, even objects that have link-time dependencies among shared objects. Filtering out shared objects that already have an link-time dependencies is not necessary here; make will do this automatically. Reviewed-by: Adhemerval Zanella (cherry picked from commit 183d99737298bb3200f0610fdcd1c7549c8ed560) --- scripts/dso-ordering-test.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py index 2dd6bfda18..b87cf2f809 100644 --- a/scripts/dso-ordering-test.py +++ b/scripts/dso-ordering-test.py @@ -707,13 +707,12 @@ def process_testcase(t): "\t$(compile.c) $(OUTPUT_OPTION)\n") makefile.write (rule) - not_depended_objs = find_objs_not_depended_on(test_descr) - if not_depended_objs: - depstr = "" - for dep in not_depended_objs: - depstr += (" $(objpfx)" + test_subdir + "/" - + test_name + "-" + dep + ".so") - makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr)) + # Ensure that all shared objects are built before running the + # test, whether there link-time dependencies or not. + depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep) + for dep in test_descr.objs] + makefile.write("$(objpfx){}.out: {}\n".format( + base_test_name, " ".join(depobjs))) # Add main executable to test-srcs makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name)) -- cgit 1.4.1 From d1241cf00139733de069c84933cd576dc1a1f45e Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 6 Sep 2022 07:38:10 +0200 Subject: elf: Rename _dl_sort_maps parameter from skip to force_first The new implementation will not be able to skip an arbitrary number of objects. Reviewed-by: Adhemerval Zanella (cherry picked from commit dbb75513f5cf9285c77c9e55777c5c35b653f890) --- elf/dl-sort-maps.c | 14 +++++++------- sysdeps/generic/ldsodefs.h | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c index 96638d7ed1..5b550b1e94 100644 --- a/elf/dl-sort-maps.c +++ b/elf/dl-sort-maps.c @@ -27,12 +27,12 @@ If FOR_FINI is true, this is called for finishing an object. */ static void _dl_sort_maps_original (struct link_map **maps, unsigned int nmaps, - unsigned int skip, bool for_fini) + bool force_first, bool for_fini) { /* Allows caller to do the common optimization of skipping the first map, usually the main binary. */ - maps += skip; - nmaps -= skip; + maps += force_first; + nmaps -= force_first; /* A list of one element need not be sorted. */ if (nmaps <= 1) @@ -182,7 +182,7 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map, static void _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, - unsigned int skip __attribute__ ((unused)), bool for_fini) + bool force_first __attribute__ ((unused)), bool for_fini) { for (int i = nmaps - 1; i >= 0; i--) maps[i]->l_visited = 0; @@ -286,7 +286,7 @@ _dl_sort_maps_init (void) void _dl_sort_maps (struct link_map **maps, unsigned int nmaps, - unsigned int skip, bool for_fini) + bool force_first, bool for_fini) { /* It can be tempting to use a static function pointer to store and call the current selected sorting algorithm routine, but experimentation @@ -296,9 +296,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, input cases. A simple if-case with direct function calls appears to be the fastest. */ if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)) - _dl_sort_maps_original (maps, nmaps, skip, for_fini); + _dl_sort_maps_original (maps, nmaps, force_first, for_fini); else - _dl_sort_maps_dfs (maps, nmaps, skip, for_fini); + _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini); } #endif /* HAVE_TUNABLES. */ diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 050a3032de..6b256b8388 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -1048,9 +1048,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv, initializer functions have completed. */ extern void _dl_fini (void) attribute_hidden; -/* Sort array MAPS according to dependencies of the contained objects. */ +/* Sort array MAPS according to dependencies of the contained objects. + If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies + say otherwise. */ extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps, - unsigned int skip, bool for_fini) attribute_hidden; + bool force_first, bool for_fini) attribute_hidden; /* The dynamic linker calls this function before and having changing any shared object mappings. The `r_state' member of `struct r_debug' -- cgit 1.4.1 From da5f134f6d59701a3a6119309ae91c93c3fa5b51 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 20 Sep 2022 11:00:42 +0200 Subject: elf: Implement force_first handling in _dl_sort_maps_dfs (bug 28937) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The implementation in _dl_close_worker requires that the first element of l_initfini is always this very map (“We are always the zeroth entry, and since we don't include ourselves in the dependency analysis start at 1.”). Rather than fixing that assumption, this commit adds an implementation of the force_first argument to the new dependency sorting algorithm. This also means that the directly dlopen'ed shared object is always initialized last, which is the least surprising behavior in the presence of cycles. Reviewed-by: Adhemerval Zanella (cherry picked from commit 1df71d32fe5f5905ffd5d100e5e9ca8ad6210891) --- NEWS | 1 + elf/dl-sort-maps.c | 32 +++++++++++++++++++++++--------- elf/dso-sort-tests-1.def | 7 +++++++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index 03281e3ab4..5b4753416f 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,7 @@ The following bugs are resolved with this release: [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning [29305] Conserve NSS buffer space during DNS packet parsing [29415] nscd: Fix netlink cache invalidation if epoll is used + [28937] New DSO dependency sorter does not put new map first if in a cycle [29446] _dlopen now ignores dl_caller argument in static mode [29485] Linux: Terminate subprocess on late failure in tst-pidfd [29490] alpha: New __brk_call implementation is broken diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c index 5b550b1e94..3e2a6a584e 100644 --- a/elf/dl-sort-maps.c +++ b/elf/dl-sort-maps.c @@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map, static void _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, - bool force_first __attribute__ ((unused)), bool for_fini) + bool force_first, bool for_fini) { + struct link_map *first_map = maps[0]; for (int i = nmaps - 1; i >= 0; i--) maps[i]->l_visited = 0; @@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, Adjusting the order so that maps[0] is last traversed naturally avoids this problem. - Further, the old "optimization" of skipping the main object at maps[0] - from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general - no longer valid, since traversing along object dependency-links - may "find" the main object even when it is not included in the initial - order (e.g. a dlopen()'ed shared object can have circular dependencies - linked back to itself). In such a case, traversing N-1 objects will - create a N-object result, and raise problems. - To summarize, just passing in the full list, and iterating from back to front makes things much more straightforward. */ @@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, } 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 + first object even when it is not included in the initial order + (e.g., a dlopen'ed shared object can have circular dependencies + linked back to itself). In such a case, traversing N-1 objects + will create a N-object result, and raise problems. Instead, + force the object back into first place after sorting. This naive + approach may introduce further dependency ordering violations + compared to rotating the cycle until the first map is again in + the first position, but as there is a cycle, at least one + violation is already present. */ + if (force_first && maps[0] != first_map) + { + int i; + for (i = 0; maps[i] != first_map; ++i) + ; + assert (i < nmaps); + memmove (&maps[1], maps, i * sizeof (maps[0])); + maps[0] = first_map; + } } void diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def index 5f7f18ef27..4bf9052db1 100644 --- a/elf/dso-sort-tests-1.def +++ b/elf/dso-sort-tests-1.def @@ -64,3 +64,10 @@ output: b>a>{}b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[a1;a->a2;a2->a;b->b1;c->a1;c=>a1 +output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());} Date: Tue, 20 Sep 2022 12:12:43 +0200 Subject: gconv: Use 64-bit interfaces in gconv_parseconfdir (bug 29583) It's possible that inode numbers are outside the 32-bit range. The existing code only handles the in-libc case correctly, and still uses the legacy interfaces when building iconv. Suggested-by: Helge Deller (cherry picked from commit f97905f24631097af325d6a231093071c3077a5f) --- NEWS | 1 + iconv/gconv_parseconfdir.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 5b4753416f..eab882987b 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,7 @@ The following bugs are resolved with this release: [29490] alpha: New __brk_call implementation is broken [29528] elf: Call __libc_early_init for reused namespaces [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are + [29583] Use 64-bit interfaces in gconv_parseconfdir Version 2.36 diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h index debb96b322..b72933b526 100644 --- a/iconv/gconv_parseconfdir.h +++ b/iconv/gconv_parseconfdir.h @@ -29,14 +29,14 @@ # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr) # define asprintf __asprintf # define opendir __opendir -# define readdir __readdir +# define readdir64 __readdir64 # define closedir __closedir # define mempcpy __mempcpy -# define struct_stat struct __stat64_t64 -# define lstat __lstat64_time64 +# define struct_stat64 struct __stat64_t64 +# define lstat64 __lstat64_time64 # define feof_unlocked __feof_unlocked #else -# define struct_stat struct stat +# define struct_stat64 struct stat64 #endif /* Name of the file containing the module information in the directories @@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) DIR *confdir = opendir (buf); if (confdir != NULL) { - struct dirent *ent; - while ((ent = readdir (confdir)) != NULL) + struct dirent64 *ent; + while ((ent = readdir64 (confdir)) != NULL) { if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN) continue; @@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) { char *conf; - struct_stat st; + struct_stat64 st; if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) continue; if (ent->d_type != DT_UNKNOWN - || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode))) + || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) found |= read_conf_file (conf, dir, dir_len); free (conf); -- cgit 1.4.1 From 2628500f5dff1dd99c49a09b418b3b1ea3a6b5d3 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 30 Aug 2022 10:33:15 -0300 Subject: m68k: Enforce 4-byte alignment on internal locks (BZ #29537) A new internal definition, __LIBC_LOCK_ALIGNMENT, is used to force the 4-byte alignment only for m68k, other architecture keep the natural alignment of the type used internally (and hppa does not require 16-byte alignment for kernel-assisted CAS). Reviewed-by: Florian Weimer (cherry picked from commit aeb4d2e9815d459e2640a31f5abb8ef803830107) --- NEWS | 1 + sysdeps/generic/libc-lock-arch.h | 25 +++++++++++++++++++++++++ sysdeps/nptl/libc-lock.h | 8 +++++++- sysdeps/nptl/libc-lockP.h | 3 ++- sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h | 25 +++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 sysdeps/generic/libc-lock-arch.h create mode 100644 sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h diff --git a/NEWS b/NEWS index eab882987b..1cc9a16bbf 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,7 @@ The following bugs are resolved with this release: [29485] Linux: Terminate subprocess on late failure in tst-pidfd [29490] alpha: New __brk_call implementation is broken [29528] elf: Call __libc_early_init for reused namespaces + [29537] libc: [2.34 regression]: Alignment issue on m68k when using [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are [29583] Use 64-bit interfaces in gconv_parseconfdir diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h new file mode 100644 index 0000000000..4713b30a8a --- /dev/null +++ b/sysdeps/generic/libc-lock-arch.h @@ -0,0 +1,25 @@ +/* Private libc-internal arch-specific definitions. Generic version. + Copyright (C) 2022 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; see the file COPYING.LIB. If + not, see . */ + +#ifndef _LIBC_LOCK_ARCH_H +#define _LIBC_LOCK_ARCH_H + +/* The default definition uses the natural alignment from the lock type. */ +#define __LIBC_LOCK_ALIGNMENT + +#endif diff --git a/sysdeps/nptl/libc-lock.h b/sysdeps/nptl/libc-lock.h index 5af476c48b..63b3f3d75c 100644 --- a/sysdeps/nptl/libc-lock.h +++ b/sysdeps/nptl/libc-lock.h @@ -22,6 +22,7 @@ #include #define __need_NULL #include +#include /* Mutex type. */ @@ -29,7 +30,12 @@ # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; # else -typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; +typedef struct +{ + int lock __LIBC_LOCK_ALIGNMENT; + int cnt; + void *owner; +} __libc_lock_recursive_t; # endif #else typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h index d3a6837fd2..425f514c5c 100644 --- a/sysdeps/nptl/libc-lockP.h +++ b/sysdeps/nptl/libc-lockP.h @@ -32,9 +32,10 @@ ld.so might be used on old kernels with a different libc.so. */ #include #include +#include /* Mutex type. */ -typedef int __libc_lock_t; +typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT; typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t; typedef pthread_rwlock_t __libc_rwlock_t; diff --git a/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h new file mode 100644 index 0000000000..1844bbaf6f --- /dev/null +++ b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h @@ -0,0 +1,25 @@ +/* Private libc-internal arch-specific definitions. m68k version. + Copyright (C) 2022 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; see the file COPYING.LIB. If + not, see . */ + +#ifndef _LIBC_LOCK_ARCH_H +#define _LIBC_LOCK_ARCH_H + +/* Linux enforces 4-bytes alignment on futex inputs. */ +#define __LIBC_LOCK_ALIGNMENT __attribute__ ((__aligned__ (4))) + +#endif -- cgit 1.4.1 From 227c9035872fc9e9e2cf56ec8f89219747ee19bc Mon Sep 17 00:00:00 2001 From: Jörg Sonnenberger Date: Mon, 26 Sep 2022 13:59:16 -0400 Subject: 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 (cherry picked from commit c9226c03da0276593a0918eaa9a14835183343e8) --- sysdeps/posix/getaddrinfo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index bcff909b2f..5cda9bb072 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -540,11 +540,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; -- cgit 1.4.1 From 76e05613ee28f4ac4a0ab97effc32e0e78e37a56 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Thu, 29 Sep 2022 16:15:20 -0300 Subject: stdlib: Fix __getrandom_nocancel type and arc4random usage (BZ #29638) Using an unsigned type prevents the fallback to be used if kernel does not support getrandom syscall. Checked on x86_64-linux-gnu. Reviewed-by: Wilco Dijkstra (cherry picked from commit 13db9ee2cb3b77e25f852be7d6952882e1be6f00) --- NEWS | 1 + stdlib/arc4random.c | 2 +- sysdeps/unix/sysv/linux/not-cancel.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 1cc9a16bbf..91bcfeb7a6 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,7 @@ The following bugs are resolved with this release: [29537] libc: [2.34 regression]: Alignment issue on m68k when using [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are [29583] Use 64-bit interfaces in gconv_parseconfdir + [29638] libc: stdlib: arc4random fallback is never used Version 2.36 diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c index e417ef624d..960a38f295 100644 --- a/stdlib/arc4random.c +++ b/stdlib/arc4random.c @@ -34,7 +34,7 @@ void __arc4random_buf (void *p, size_t n) { static int seen_initialized; - size_t l; + ssize_t l; int fd; if (n == 0) diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h index a263d294b1..cf35c8bfc9 100644 --- a/sysdeps/unix/sysv/linux/not-cancel.h +++ b/sysdeps/unix/sysv/linux/not-cancel.h @@ -68,7 +68,7 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt) INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt); } -static inline int +static inline ssize_t __getrandom_nocancel (void *buf, size_t buflen, unsigned int flags) { return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags); -- cgit 1.4.1 From d1d8379bff34f02f86f82db2cef5bf66746d3560 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sat, 1 Oct 2022 19:49:25 +0000 Subject: hppa: Fix initialization of dp register [BZ 29635] After upgrading glibc to Debian 2.35-1, gdb faulted on startup and dropped core in a function call in the main application. This was caused by not initializing the global dp register for the main application early enough. Restore the code to initialize dp in _dl_start_user. It was removed when code was added to initialize dp in elf_machine_runtime_setup. Signed-off-by: John David Anglin --- sysdeps/hppa/dl-machine.h | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h index c865713be1..1d51948566 100644 --- a/sysdeps/hppa/dl-machine.h +++ b/sysdeps/hppa/dl-machine.h @@ -347,6 +347,16 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], its return value is the user program's entry point. */ #define RTLD_START \ +/* Set up dp for any non-PIC lib constructors that may be called. */ \ +static struct link_map * __attribute__((used)) \ +set_dp (struct link_map *map) \ +{ \ + register Elf32_Addr dp asm ("%r27"); \ + dp = D_PTR (map, l_info[DT_PLTGOT]); \ + asm volatile ("" : : "r" (dp)); \ + return map; \ +} \ + \ asm ( \ " .text\n" \ " .globl _start\n" \ @@ -426,6 +436,13 @@ asm ( \ direct loader invocation. Thus, argc and argv must be \ reloaded from from _dl_argc and _dl_argv. */ \ \ + /* Load main_map from _rtld_local and setup dp. */ \ +" addil LT'_rtld_local,%r19\n" \ +" ldw RT'_rtld_local(%r1),%r26\n" \ +" bl set_dp, %r2\n" \ +" ldw 0(%r26),%r26\n" \ +" copy %ret0,%r26\n" \ + \ /* Load argc from _dl_argc. */ \ " addil LT'_dl_argc,%r19\n" \ " ldw RT'_dl_argc(%r1),%r20\n" \ @@ -438,13 +455,10 @@ asm ( \ " ldw 0(%r20),%r24\n" \ " stw %r24,-44(%sp)\n" \ \ - /* Call _dl_init(main_map, argc, argv, envp). */ \ -" addil LT'_rtld_local,%r19\n" \ -" ldw RT'_rtld_local(%r1),%r26\n" \ -" ldw 0(%r26),%r26\n" \ - \ /* envp = argv + argc + 1 */ \ " sh2add %r25,%r24,%r23\n" \ + \ + /* Call _dl_init(main_map, argc, argv, envp). */ \ " bl _dl_init,%r2\n" \ " ldo 4(%r23),%r23\n" /* delay slot */ \ \ -- cgit 1.4.1 From cdc496eb55e30f8f2461bedb0a7381c0a7a3d3ae Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Tue, 20 Sep 2022 20:14:14 +0000 Subject: hppa: undef __ASSUME_SET_ROBUST_LIST QEMU does not support support set_robust_list. Thus, we need to enable detection of set_robust_list system call. Signed-off-by: John David Anglin --- sysdeps/unix/sysv/linux/hppa/kernel-features.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sysdeps/unix/sysv/linux/hppa/kernel-features.h b/sysdeps/unix/sysv/linux/hppa/kernel-features.h index 0cd21ef0fa..079612e4aa 100644 --- a/sysdeps/unix/sysv/linux/hppa/kernel-features.h +++ b/sysdeps/unix/sysv/linux/hppa/kernel-features.h @@ -30,3 +30,6 @@ #undef __ASSUME_CLONE_DEFAULT #define __ASSUME_CLONE_BACKWARDS 1 + +/* QEMU does not support set_robust_list. */ +#undef __ASSUME_SET_ROBUST_LIST -- cgit 1.4.1 From 18bec23cbb4d530a2a8ce95353770661fabcd55f Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 3 Oct 2022 23:46:11 +0200 Subject: x86: include BMI1 and BMI2 in x86-64-v3 level The "System V Application Binary Interface AMD64 Architecture Processor Supplement" mandates the BMI1 and BMI2 CPU features for the x86-64-v3 level. Reviewed-by: Noah Goldstein (cherry picked from commit b80f16adbd979831bf25ea491e1261e81885c2b6) --- sysdeps/x86/get-isa-level.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h index 1ade78ab73..5b4dd5f062 100644 --- a/sysdeps/x86/get-isa-level.h +++ b/sysdeps/x86/get-isa-level.h @@ -47,6 +47,8 @@ get_isa_level (const struct cpu_features *cpu_features) isa_level |= GNU_PROPERTY_X86_ISA_1_V2; if (CPU_FEATURE_USABLE_P (cpu_features, AVX) && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURE_USABLE_P (cpu_features, BMI1) + && CPU_FEATURE_USABLE_P (cpu_features, BMI2) && CPU_FEATURE_USABLE_P (cpu_features, F16C) && CPU_FEATURE_USABLE_P (cpu_features, FMA) && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) -- cgit 1.4.1 From 46479e5d10ed87825aa277da158d6a687974518b Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 3 Oct 2022 23:46:11 +0200 Subject: x86-64: Require BMI2 for AVX2 str(n)casecmp implementations The AVX2 str(n)casecmp implementations use the 'bzhi' instruction, which belongs to the BMI2 CPU feature. NB: It also uses the 'tzcnt' BMI1 instruction, but it is executed as BSF as BSF if the CPU doesn't support TZCNT, and produces the same result for non-zero input. Partially fixes: b77b06e0e296 ("x86: Optimize strcmp-avx2.S") Partially resolves: BZ #29611 Reviewed-by: Noah Goldstein (cherry picked from commit 10f79d3670b036925da63dc532b122d27ce65ff8) --- sysdeps/x86_64/multiarch/ifunc-impl-list.c | 28 ++++++++++++++++++++-------- sysdeps/x86_64/multiarch/ifunc-strcasecmp.h | 1 + 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c index a71444eccb..d208fae4bf 100644 --- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c +++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c @@ -448,13 +448,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, strcasecmp, X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp, (CPU_FEATURE_USABLE (AVX512VL) - && CPU_FEATURE_USABLE (AVX512BW)), + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), __strcasecmp_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __strcasecmp_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __strcasecmp_avx2_rtm) X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp, @@ -470,13 +473,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, strcasecmp_l, X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp, (CPU_FEATURE_USABLE (AVX512VL) - && CPU_FEATURE_USABLE (AVX512BW)), + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), __strcasecmp_l_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __strcasecmp_l_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __strcasecmp_l_avx2_rtm) X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp_l, @@ -638,13 +644,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, strncasecmp, X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp, (CPU_FEATURE_USABLE (AVX512VL) - && CPU_FEATURE_USABLE (AVX512BW)), + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), __strncasecmp_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __strncasecmp_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __strncasecmp_avx2_rtm) X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp, @@ -660,13 +669,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, strncasecmp_l, X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp, (CPU_FEATURE_USABLE (AVX512VL) - && CPU_FEATURE_USABLE (AVX512BW)), + & CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), __strncasecmp_l_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __strncasecmp_l_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __strncasecmp_l_avx2_rtm) X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp_l, diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h index 68646ef199..7622af259c 100644 --- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h @@ -34,6 +34,7 @@ IFUNC_SELECTOR (void) const struct cpu_features *cpu_features = __get_cpu_features (); if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load, )) { -- cgit 1.4.1 From 7afbd1e56acb721031bffd876f275dcb1af7e530 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 3 Oct 2022 23:46:11 +0200 Subject: x86-64: Require BMI2 for AVX2 strcmp implementation The AVX2 strcmp implementation uses the 'bzhi' instruction, which belongs to the BMI2 CPU feature. NB: It also uses the 'tzcnt' BMI1 instruction, but it is executed as BSF as BSF if the CPU doesn't support TZCNT, and produces the same result for non-zero input. Partially fixes: b77b06e0e296 ("x86: Optimize strcmp-avx2.S") Partially resolves: BZ #29611 Reviewed-by: Noah Goldstein (cherry picked from commit 4d64c6445735e9b34e2ac8e369312cbfc2f88e17) --- sysdeps/x86_64/multiarch/ifunc-impl-list.c | 4 +++- sysdeps/x86_64/multiarch/strcmp.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c index d208fae4bf..a42b0a4620 100644 --- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c +++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c @@ -591,10 +591,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, && CPU_FEATURE_USABLE (BMI2)), __strcmp_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __strcmp_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __strcmp_avx2_rtm) X86_IFUNC_IMPL_ADD_V2 (array, i, strcmp, diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c index fdd5afe3af..9d6c9f66ba 100644 --- a/sysdeps/x86_64/multiarch/strcmp.c +++ b/sysdeps/x86_64/multiarch/strcmp.c @@ -45,12 +45,12 @@ IFUNC_SELECTOR (void) const struct cpu_features *cpu_features = __get_cpu_features (); if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load, )) { if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) - && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) - && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) return OPTIMIZE (evex); if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) -- cgit 1.4.1 From 29c577e0f54fe6e70ceacb3659179781c5569903 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 3 Oct 2022 23:46:11 +0200 Subject: x86-64: Require BMI2 for AVX2 strncmp implementation The AVX2 strncmp implementations uses the 'bzhi' instruction, which belongs to the BMI2 CPU feature. NB: It also uses the 'tzcnt' BMI1 instruction, but it is executed as BSF as BSF if the CPU doesn't support TZCNT, and produces the same result for non-zero input. Partially fixes: b77b06e0e296 ("x86: Optimize strcmp-avx2.S") Partially resolves: BZ #29611 Reviewed-by: Noah Goldstein (cherry picked from commit fc7de1d9b99ae1676bc626ddca422d7abee0eb48) --- sysdeps/x86_64/multiarch/ifunc-impl-list.c | 7 +++++-- sysdeps/x86_64/multiarch/strncmp.c | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c index a42b0a4620..aebef3daaf 100644 --- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c +++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c @@ -1176,13 +1176,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, strncmp, X86_IFUNC_IMPL_ADD_V4 (array, i, strncmp, (CPU_FEATURE_USABLE (AVX512VL) - && CPU_FEATURE_USABLE (AVX512BW)), + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2)), __strncmp_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __strncmp_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __strncmp_avx2_rtm) X86_IFUNC_IMPL_ADD_V2 (array, i, strncmp, diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c index 4ebe4bde30..c4f8b6bbb5 100644 --- a/sysdeps/x86_64/multiarch/strncmp.c +++ b/sysdeps/x86_64/multiarch/strncmp.c @@ -41,12 +41,12 @@ IFUNC_SELECTOR (void) const struct cpu_features *cpu_features = __get_cpu_features (); if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load, )) { if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) - && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) - && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) return OPTIMIZE (evex); if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) -- cgit 1.4.1 From d8bf4388df679fa5a3ae7889a649e573e3124530 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 3 Oct 2022 23:46:11 +0200 Subject: x86-64: Require BMI2 for AVX2 wcs(n)cmp implementations The AVX2 wcs(n)cmp implementations use the 'bzhi' instruction, which belongs to the BMI2 CPU feature. NB: It also uses the 'tzcnt' BMI1 instruction, but it is executed as BSF as BSF if the CPU doesn't support TZCNT, and produces the same result for non-zero input. Partially fixes: b77b06e0e296 ("x86: Optimize strcmp-avx2.S") Partially resolves: BZ #29611 Reviewed-by: Noah Goldstein (cherry picked from commit f31a5a884ed84bd37032729d4d1eb9d06c9f3c29) --- sysdeps/x86_64/multiarch/ifunc-impl-list.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c index aebef3daaf..fec8790c11 100644 --- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c +++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c @@ -810,10 +810,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, && CPU_FEATURE_USABLE (BMI2)), __wcscmp_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __wcscmp_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __wcscmp_avx2_rtm) /* ISA V2 wrapper for SSE2 implementation because the SSE2 @@ -830,10 +832,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, && CPU_FEATURE_USABLE (BMI2)), __wcsncmp_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __wcsncmp_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __wcsncmp_avx2_rtm) /* ISA V2 wrapper for GENERIC implementation because the -- cgit 1.4.1 From d9196d4f3fa9997388655813ddd236426a16dd92 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 3 Oct 2022 23:46:11 +0200 Subject: x86-64: Require BMI2 for AVX2 (raw|w)memchr implementations The AVX2 memchr, rawmemchr and wmemchr implementations use the 'bzhi' and 'sarx' instructions, which belongs to the BMI2 CPU feature. Fixes: acfd088a1963 ("x86: Optimize memchr-avx2.S") Partially resolves: BZ #29611 Reviewed-by: Noah Goldstein (cherry picked from commit e3e7fab7fe5186d18ca2046d99ba321c27db30ad) --- sysdeps/x86_64/multiarch/ifunc-impl-list.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c index fec8790c11..7c84963d92 100644 --- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c +++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c @@ -69,10 +69,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, && CPU_FEATURE_USABLE (BMI2)), __memchr_evex_rtm) X86_IFUNC_IMPL_ADD_V3 (array, i, memchr, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __memchr_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, memchr, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __memchr_avx2_rtm) /* ISA V2 wrapper for SSE2 implementation because the SSE2 @@ -335,10 +337,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, && CPU_FEATURE_USABLE (BMI2)), __rawmemchr_evex_rtm) X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __rawmemchr_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __rawmemchr_avx2_rtm) /* ISA V2 wrapper for SSE2 implementation because the SSE2 @@ -927,10 +931,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, && CPU_FEATURE_USABLE (BMI2)), __wmemchr_evex_rtm) X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2)), __wmemchr_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __wmemchr_avx2_rtm) /* ISA V2 wrapper for SSE2 implementation because the SSE2 -- cgit 1.4.1 From 923c3f3c373f499e62160e00831dda576443317b Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 3 Oct 2022 23:46:11 +0200 Subject: x86-64: Require BMI2 and LZCNT for AVX2 memrchr implementation The AVX2 memrchr implementation uses the 'shlxl' instruction, which belongs to the BMI2 CPU feature and uses the 'lzcnt' instruction, which belongs to the LZCNT CPU feature. Fixes: af5306a735eb ("x86: Optimize memrchr-avx2.S") Partially resolves: BZ #29611 Reviewed-by: Noah Goldstein (cherry picked from commit 3c0c78afabfed4b6fc161c159e628fbf14ff370b) --- sysdeps/x86/isa-level.h | 1 + sysdeps/x86_64/multiarch/ifunc-avx2.h | 1 + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 10 ++++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/sysdeps/x86/isa-level.h b/sysdeps/x86/isa-level.h index 3c4480aba7..bbb90f5c5e 100644 --- a/sysdeps/x86/isa-level.h +++ b/sysdeps/x86/isa-level.h @@ -80,6 +80,7 @@ #define AVX_X86_ISA_LEVEL 3 #define AVX2_X86_ISA_LEVEL 3 #define BMI2_X86_ISA_LEVEL 3 +#define LZCNT_X86_ISA_LEVEL 3 #define MOVBE_X86_ISA_LEVEL 3 /* ISA level >= 2 guaranteed includes. */ diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h index a57a9952f3..f1741083fd 100644 --- a/sysdeps/x86_64/multiarch/ifunc-avx2.h +++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h @@ -37,6 +37,7 @@ IFUNC_SELECTOR (void) if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, LZCNT) && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load, )) { diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c index 7c84963d92..ec1c5b55fb 100644 --- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c +++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c @@ -209,13 +209,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, memrchr, X86_IFUNC_IMPL_ADD_V4 (array, i, memrchr, (CPU_FEATURE_USABLE (AVX512VL) - && CPU_FEATURE_USABLE (AVX512BW)), + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (LZCNT)), __memrchr_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (LZCNT)), __memrchr_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (LZCNT) && CPU_FEATURE_USABLE (RTM)), __memrchr_avx2_rtm) /* ISA V2 wrapper for SSE2 implementation because the SSE2 -- cgit 1.4.1 From 2d8ef784bd6a784496a6fd460de6b6f57c70a501 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 3 Oct 2022 23:46:11 +0200 Subject: x86-64: Require BMI1/BMI2 for AVX2 strrchr and wcsrchr implementations The AVX2 strrchr and wcsrchr implementation uses the 'blsmsk' instruction which belongs to the BMI1 CPU feature and the 'shrx' instruction, which belongs to the BMI2 CPU feature. Fixes: df7e295d18ff ("x86: Optimize {str|wcs}rchr-avx2") Partially resolves: BZ #29611 Reviewed-by: Noah Goldstein (cherry picked from commit 7e8283170c5d6805b609a040801d819e362a6292) --- sysdeps/x86/isa-level.h | 1 + sysdeps/x86_64/multiarch/ifunc-avx2.h | 1 + sysdeps/x86_64/multiarch/ifunc-impl-list.c | 17 ++++++++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/sysdeps/x86/isa-level.h b/sysdeps/x86/isa-level.h index bbb90f5c5e..06f6c9663e 100644 --- a/sysdeps/x86/isa-level.h +++ b/sysdeps/x86/isa-level.h @@ -79,6 +79,7 @@ /* ISA level >= 3 guaranteed includes. */ #define AVX_X86_ISA_LEVEL 3 #define AVX2_X86_ISA_LEVEL 3 +#define BMI1_X86_ISA_LEVEL 3 #define BMI2_X86_ISA_LEVEL 3 #define LZCNT_X86_ISA_LEVEL 3 #define MOVBE_X86_ISA_LEVEL 3 diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h index f1741083fd..f2f5e8a211 100644 --- a/sysdeps/x86_64/multiarch/ifunc-avx2.h +++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h @@ -36,6 +36,7 @@ IFUNC_SELECTOR (void) const struct cpu_features *cpu_features = __get_cpu_features (); if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI1) && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, LZCNT) && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c index ec1c5b55fb..00a91123d3 100644 --- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c +++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c @@ -578,13 +578,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, strrchr, X86_IFUNC_IMPL_ADD_V4 (array, i, strrchr, (CPU_FEATURE_USABLE (AVX512VL) - && CPU_FEATURE_USABLE (AVX512BW)), + && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI1) + && CPU_FEATURE_USABLE (BMI2)), __strrchr_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI1) + && CPU_FEATURE_USABLE (BMI2)), __strrchr_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI1) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __strrchr_avx2_rtm) /* ISA V2 wrapper for SSE2 implementation because the SSE2 @@ -797,13 +803,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, X86_IFUNC_IMPL_ADD_V4 (array, i, wcsrchr, (CPU_FEATURE_USABLE (AVX512VL) && CPU_FEATURE_USABLE (AVX512BW) + && CPU_FEATURE_USABLE (BMI1) && CPU_FEATURE_USABLE (BMI2)), __wcsrchr_evex) X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr, - CPU_FEATURE_USABLE (AVX2), + (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI1) + && CPU_FEATURE_USABLE (BMI2)), __wcsrchr_avx2) X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr, (CPU_FEATURE_USABLE (AVX2) + && CPU_FEATURE_USABLE (BMI1) + && CPU_FEATURE_USABLE (BMI2) && CPU_FEATURE_USABLE (RTM)), __wcsrchr_avx2_rtm) /* ISA V2 wrapper for SSE2 implementation because the SSE2 -- cgit 1.4.1 From 2bd815d8347851212b9a91dbdca8053f4dbdac87 Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Tue, 4 Oct 2022 18:43:50 -0400 Subject: nscd: Drop local address tuple variable [BZ #29607] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a request needs to be resent (e.g. due to insufficient buffer space), the references to subsequent tuples in the local variable are stale and should not be used. This used to work by accident before, but since 1d495912a it no longer does. Instead of trying to reset it, just let gethostbyname4_r write into TUMPBUF6 for us, thus maintaining a consistent state at all times. This is now consistent with what is done in gaih_inet for getaddrinfo. Resolves: BZ #29607 Reported-by: Holger Hoffstätte Tested-by: Holger Hoffstätte Reviewed-by: Carlos O'Donell (cherry picked from commit 6e33e5c4b73cea7b8aa3de0947123db16200fb65) --- NEWS | 2 ++ nscd/aicache.c | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 91bcfeb7a6..63e26d7062 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,8 @@ The following bugs are resolved with this release: [29537] libc: [2.34 regression]: Alignment issue on m68k when using [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are [29583] Use 64-bit interfaces in gconv_parseconfdir + [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is + enabled [29638] libc: stdlib: arc4random fallback is never used Version 2.36 diff --git a/nscd/aicache.c b/nscd/aicache.c index 51e793199f..e0baed170b 100644 --- a/nscd/aicache.c +++ b/nscd/aicache.c @@ -110,11 +110,10 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, "gethostbyname4_r"); if (fct4 != NULL) { - struct gaih_addrtuple atmem; struct gaih_addrtuple *at; while (1) { - at = &atmem; + at = NULL; rc6 = 0; herrno = 0; status[1] = DL_CALL_FCT (fct4, (key, &at, @@ -137,7 +136,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, goto next_nip; /* We found the data. Count the addresses and the size. */ - for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL; + for (const struct gaih_addrtuple *at2 = at; at2 != NULL; at2 = at2->next) { ++naddrs; -- cgit 1.4.1 From 3e279192749cfcae4ceebb1f21a3275e677d0561 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Fri, 12 Aug 2022 11:29:31 +1200 Subject: Ensure calculations happen with desired rounding mode in y1lf128 math/test-float128-y1 fails on x86_64 and ppc64el with gcc 12 and -O3, because code inside a block guarded by SET_RESTORE_ROUNDL is being moved after the rounding mode has been restored. Use math_force_eval to prevent this (and insert some math_opt_barrier calls to prevent code from being moved before the rounding mode is set). Fixes #29463 Reviewed-By: Wilco Dijkstra (cherry picked from commit 2b274fd8c9c776cf70fcdb8356e678ada522a7b0) --- NEWS | 1 + sysdeps/ieee754/ldbl-128/e_j1l.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 63e26d7062..bea1d8a11f 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ The following bugs are resolved with this release: [29446] _dlopen now ignores dl_caller argument in static mode [29485] Linux: Terminate subprocess on late failure in tst-pidfd [29490] alpha: New __brk_call implementation is broken + [29463] math/test-float128-y1 fails on x86_64 [29528] elf: Call __libc_early_init for reused namespaces [29537] libc: [2.34 regression]: Alignment issue on m68k when using [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are diff --git a/sysdeps/ieee754/ldbl-128/e_j1l.c b/sysdeps/ieee754/ldbl-128/e_j1l.c index 54c457681a..9a9c5c6f00 100644 --- a/sysdeps/ieee754/ldbl-128/e_j1l.c +++ b/sysdeps/ieee754/ldbl-128/e_j1l.c @@ -869,10 +869,13 @@ __ieee754_y1l (_Float128 x) { /* 0 <= x <= 2 */ SET_RESTORE_ROUNDL (FE_TONEAREST); + xx = math_opt_barrier (xx); + x = math_opt_barrier (x); z = xx * xx; p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); p = -TWOOPI / xx + p; p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p; + math_force_eval (p); return p; } -- cgit 1.4.1 From 700d3281f9e57b53c27bc991394b22d467432626 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 13 Sep 2022 16:10:20 +0200 Subject: nss: Implement --no-addrconfig option for getent The ahosts, ahostsv4, ahostsv6 commands unconditionally pass AI_ADDRCONFIG to getaddrinfo, which is not always desired. Reviewed-by: Carlos O'Donell (cherry picked from commit a623f13adfac47c8634a7288e08f821a846bc650) --- NEWS | 7 +++++++ nss/getent.c | 11 ++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index bea1d8a11f..462a12253d 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,13 @@ using `glibc' in the "product" field. Version 2.36.1 +Major new features: + +* The getent tool now supports the --no-addrconfig option. The output of + getent with --no-addrconfig may contain addresses of families not + configured on the current host i.e. as-if you had not passed + AI_ADDRCONFIG to getaddrinfo calls. + Security related changes: CVE-2022-39046: When the syslog function is passed a crafted input diff --git a/nss/getent.c b/nss/getent.c index 8178b4b470..d2d2524b0c 100644 --- a/nss/getent.c +++ b/nss/getent.c @@ -58,6 +58,8 @@ static const struct argp_option args_options[] = { { "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") }, { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") }, + { "no-addrconfig", 'A', NULL, 0, + N_("do not filter out unsupported IPv4/IPv6 addresses (with ahosts*)") }, { NULL, 0, NULL, 0, NULL }, }; @@ -79,6 +81,9 @@ static struct argp argp = /* Additional getaddrinfo flags for IDN encoding. */ static int idn_flags = AI_IDN | AI_CANONIDN; +/* Set to 0 by --no-addrconfig. */ +static int addrconfig_flags = AI_ADDRCONFIG; + /* Print the version information. */ static void print_version (FILE *stream, struct argp_state *state) @@ -346,7 +351,7 @@ ahosts_keys_int (int af, int xflags, int number, char *key[]) struct addrinfo hint; memset (&hint, '\0', sizeof (hint)); - hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME + hint.ai_flags = (AI_V4MAPPED | addrconfig_flags | AI_CANONNAME | idn_flags | xflags); hint.ai_family = af; @@ -905,6 +910,10 @@ parse_option (int key, char *arg, struct argp_state *state) idn_flags = 0; break; + case 'A': + addrconfig_flags = 0; + break; + default: return ARGP_ERR_UNKNOWN; } -- cgit 1.4.1 From 2681d38cafaceafeb330bc0536fa710b75ed5947 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 13 Sep 2022 16:11:40 +0200 Subject: nss: Fix tst-nss-files-hosts-long on single-stack hosts (bug 24816) getent implicitly passes AI_ADDRCONFIG to getaddrinfo by default. Use --no-addrconfig to suppress that, so that both IPv4 and IPv6 lookups succeed even if the address family is not supported by the host. Reviewed-by: Carlos O'Donell (cherry picked from commit c75d20b5b27b0a60f0678236f51a4d3b0b058c00) --- NEWS | 1 + nss/tst-nss-files-hosts-long.c | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 462a12253d..de775ab116 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ Security related changes: The following bugs are resolved with this release: [12154] Do not fail DNS resolution for CNAMEs which are not host names + [24816] Fix tst-nss-files-hosts-long on single-stack hosts [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning [29305] Conserve NSS buffer space during DNS packet parsing [29415] nscd: Fix netlink cache invalidation if epoll is used diff --git a/nss/tst-nss-files-hosts-long.c b/nss/tst-nss-files-hosts-long.c index 3942cf5fca..a7697e3143 100644 --- a/nss/tst-nss-files-hosts-long.c +++ b/nss/tst-nss-files-hosts-long.c @@ -28,14 +28,15 @@ do_test (void) { int ret; - /* Run getent to fetch the IPv4 address for host test4. - This forces /etc/hosts to be parsed. */ - ret = system("getent ahostsv4 test4"); + /* Run getent to fetch the IPv4 address for host test4. This forces + /etc/hosts to be parsed. Use --no-addrconfig to return addresses + even in an IPv6-only environment. */ + ret = system("getent --no-addrconfig ahostsv4 test4"); if (ret != 0) FAIL_EXIT1("ahostsv4 failed"); /* Likewise for IPv6. */ - ret = system("getent ahostsv6 test6"); + ret = system("getent --no-addrconfig ahostsv6 test6"); if (ret != 0) FAIL_EXIT1("ahostsv6 failed"); -- cgit 1.4.1 From 908454129d21126bf7fc58f2a520b1f304dc5f02 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 23 Sep 2022 19:30:57 +0200 Subject: nss: Use shared prefix in IPv4 address in tst-reload1 Otherwise, sorting based on the longest-matching prefix in getaddrinfo can reorder the addresses in ways the test does not expect, depending on the IPv4 address of the host. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit c02e29a0ba47d636281e1a026444a1a0a254aa12) --- nss/tst-reload1.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nss/tst-reload1.c b/nss/tst-reload1.c index fdc5bdd65b..bc32bb132a 100644 --- a/nss/tst-reload1.c +++ b/nss/tst-reload1.c @@ -43,12 +43,12 @@ static struct passwd pwd_table_1[] = { static const char *hostaddr_5[] = { - "ABCD", "abcd", "1234", NULL + "ABCd", "ABCD", "ABC4", NULL }; static const char *hostaddr_15[] = { - "4321", "ghij", NULL + "4321", "4322", NULL }; static const char *hostaddr_25[] = @@ -86,12 +86,12 @@ static const char *hostaddr_6[] = static const char *hostaddr_16[] = { - "7890", "a1b2", NULL + "7890", "7891", NULL }; static const char *hostaddr_26[] = { - "qwer", "tyui", NULL + "qwer", "qweR", NULL }; static struct hostent host_table_2[] = { -- cgit 1.4.1 From 19535f3b57306ea3ec559a6c0b10d2d7a87418a7 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 14 Oct 2022 11:02:25 +0200 Subject: elf: Do not completely clear reused namespace in dlmopen (bug 29600) The data in the _ns_debug member must be preserved, otherwise _dl_debug_initialize enters an infinite loop. To be conservative, only clear the libc_map member for now, to fix bug 29528. Fixes commit d0e357ff45a75553dee3b17ed7d303bfa544f6fe ("elf: Call __libc_early_init for reused namespaces (bug 29528)"), by reverting most of it. Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit 2c42257314536b94cc8d52edede86e94e98c1436) --- NEWS | 1 + elf/dl-open.c | 14 ++++++-------- elf/tst-dlmopen-twice.c | 28 ++++++++++++++++++++++++---- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index de775ab116..a6da588c85 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,7 @@ The following bugs are resolved with this release: [29537] libc: [2.34 regression]: Alignment issue on m68k when using [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are [29583] Use 64-bit interfaces in gconv_parseconfdir + [29600] Do not completely clear reused namespace in dlmopen [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is enabled [29638] libc: stdlib: arc4random fallback is never used diff --git a/elf/dl-open.c b/elf/dl-open.c index 46e8066fd8..e7db5e9642 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -844,15 +844,13 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, _dl_signal_error (EINVAL, file, NULL, N_("\ no more namespaces available for dlmopen()")); } + else if (nsid == GL(dl_nns)) + { + __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); + ++GL(dl_nns); + } - if (nsid == GL(dl_nns)) - ++GL(dl_nns); - - /* Initialize the new namespace. Most members are - zero-initialized, only the lock needs special treatment. */ - memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid])); - __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); - + GL(dl_ns)[nsid].libc_map = NULL; _dl_debug_update (nsid)->r_state = RT_CONSISTENT; } /* Never allow loading a DSO in a namespace which is empty. Such diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c index 449f3c8fa9..70c71fe19c 100644 --- a/elf/tst-dlmopen-twice.c +++ b/elf/tst-dlmopen-twice.c @@ -16,18 +16,38 @@ License along with the GNU C Library; if not, see . */ -#include +#include #include +#include -static int -do_test (void) +/* Run the test multiple times, to check finding a new namespace while + another namespace is already in use. This used to trigger bug 29600. */ +static void +recurse (int depth) { - void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW); + if (depth == 0) + return; + + printf ("info: running at depth %d\n", depth); + void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", + RTLD_NOW); xdlclose (handle); handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW); int (*run_check) (void) = xdlsym (handle, "run_check"); TEST_COMPARE (run_check (), 0); + recurse (depth - 1); xdlclose (handle); +} + +static int +do_test (void) +{ + /* First run the test without nesting. */ + recurse (1); + + /* Then with nesting. The constant needs to be less than the + internal DL_NNS namespace constant. */ + recurse (10); return 0; } -- cgit 1.4.1 From b357157361117182c7a68c90fda7ba431b64442c Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Mon, 22 Aug 2022 14:05:04 +1200 Subject: Fix BZ #29463 in the ibm128 implementation of y1l too Avoid moving code across SET_RESTORE_ROUNDL in order to fix [BZ #29463]. Tested-by: Aurelien Jarno Reviewed-by: Aurelien Jarno Reviewed-by: Tulio Magno Quites Machado Filho (cherry picked from commit b6e37b7805b0182c3e25cdab39ebf5f001c04d05) --- sysdeps/ieee754/ldbl-128ibm/e_j1l.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c index f85ba94466..0a5fe68342 100644 --- a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c +++ b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c @@ -792,10 +792,13 @@ __ieee754_y1l (long double x) { /* 0 <= x <= 2 */ SET_RESTORE_ROUNDL (FE_TONEAREST); + xx = math_opt_barrier (xx); + x = math_opt_barrier (x); z = xx * xx; p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); p = -TWOOPI / xx + p; p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p; + math_force_eval (p); return p; } -- cgit 1.4.1 From 9273b2d0e93e7355656cad3be3a1ca76489df483 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 10 Oct 2022 00:39:33 +0200 Subject: Avoid undefined behaviour in ibm128 implementation of llroundl (BZ #29488) Detecting an overflow edge case depended on signed overflow of a long long. Replace the additions and the overflow checks by __builtin_add_overflow(). Reviewed-by: Tulio Magno Quites Machado Filho (cherry picked from commit 2b5478569e72ee4820a6e163d306690c9c0eaf5e) --- NEWS | 2 ++ sysdeps/ieee754/ldbl-128ibm/s_llroundl.c | 21 +++++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index a6da588c85..8c60d3dc8d 100644 --- a/NEWS +++ b/NEWS @@ -33,6 +33,8 @@ The following bugs are resolved with this release: [29485] Linux: Terminate subprocess on late failure in tst-pidfd [29490] alpha: New __brk_call implementation is broken [29463] math/test-float128-y1 fails on x86_64 + [29488] test-ibm128-llround fails on ppc64el when built with gcc-12 and -O2 + or higher [29528] elf: Call __libc_early_init for reused namespaces [29537] libc: [2.34 regression]: Alignment issue on m68k when using [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are diff --git a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c index d85154e73a..d8c0de1faf 100644 --- a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c +++ b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c @@ -66,38 +66,35 @@ __llroundl (long double x) /* Peg at max/min values, assuming that the above conversions do so. Strictly speaking, we can return anything for values that overflow, but this is more useful. */ - res = hi + lo; - - /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */ - if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0))) + if (__glibc_unlikely (__builtin_add_overflow (hi, lo, &res))) goto overflow; xh -= lo; ldbl_canonicalize (&xh, &xl); - hi = res; if (xh > 0.5) { - res += 1; + if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res))) + goto overflow; } else if (xh == 0.5) { if (xl > 0.0 || (xl == 0.0 && res >= 0)) - res += 1; + if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res))) + goto overflow; } else if (-xh > 0.5) { - res -= 1; + if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res))) + goto overflow; } else if (-xh == 0.5) { if (xl < 0.0 || (xl == 0.0 && res <= 0)) - res -= 1; + if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res))) + goto overflow; } - if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0))) - goto overflow; - return res; } else -- cgit 1.4.1 From 7b7dfbb0cbdffebf0233c650627a4861212fbb60 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 19 Oct 2022 19:14:04 -0300 Subject: linux: Fix generic struct_stat for 64 bit time (BZ# 29657) The generic Linux struct_stat misses the conditionals to use bits/struct_stat_time64_helper.h in the __USE_TIME_BITS64 for architecture that uses __TIMESIZE == 32 (currently csky and nios2). Since newer ports should not support 32 bit time_t, the generic implementation should be used as default. For arm, hppa, and sh a copy of default struct_stat is added, while for csky and nios a new one based on generic is used, along with conditionals to use bits/struct_stat_time64_helper.h. The default struct_stat is also replaced with the generic one. Checked on aarch64-linux-gnu and arm-linux-gnueabihf. (cherry picked from commit 7a6ca82f8007ddbd43e2b8fce806ba7101ee47f5) --- NEWS | 2 + sysdeps/unix/sysv/linux/arm/bits/struct_stat.h | 139 +++++++++++++++++++++ sysdeps/unix/sysv/linux/bits/struct_stat.h | 116 ++++++++--------- sysdeps/unix/sysv/linux/csky/bits/struct_stat.h | 135 ++++++++++++++++++++ sysdeps/unix/sysv/linux/generic/bits/struct_stat.h | 127 ------------------- sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h | 139 +++++++++++++++++++++ sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h | 135 ++++++++++++++++++++ sysdeps/unix/sysv/linux/sh/bits/struct_stat.h | 139 +++++++++++++++++++++ 8 files changed, 741 insertions(+), 191 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/arm/bits/struct_stat.h create mode 100644 sysdeps/unix/sysv/linux/csky/bits/struct_stat.h delete mode 100644 sysdeps/unix/sysv/linux/generic/bits/struct_stat.h create mode 100644 sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h create mode 100644 sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h create mode 100644 sysdeps/unix/sysv/linux/sh/bits/struct_stat.h diff --git a/NEWS b/NEWS index 8c60d3dc8d..833045585f 100644 --- a/NEWS +++ b/NEWS @@ -43,6 +43,8 @@ The following bugs are resolved with this release: [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is enabled [29638] libc: stdlib: arc4random fallback is never used + [29657] libc: Incorrect struct stat for 64-bit time on linux/generic + platforms Version 2.36 diff --git a/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h new file mode 100644 index 0000000000..30ee6279d2 --- /dev/null +++ b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h @@ -0,0 +1,139 @@ +/* Definition for struct stat. Linux/arm version. + Copyright (C) 2020-2022 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 + . */ + +#if !defined _SYS_STAT_H && !defined _FCNTL_H +# error "Never include directly; use instead." +#endif + +#ifndef _BITS_STRUCT_STAT_H +#define _BITS_STRUCT_STAT_H 1 + +#include +#include + +struct stat + { +#ifdef __USE_TIME_BITS64 +# include +#else + __dev_t st_dev; /* Device. */ + unsigned short int __pad1; +# ifndef __USE_FILE_OFFSET64 + __ino_t st_ino; /* File serial number. */ +# else + __ino_t __st_ino; /* 32bit file serial number. */ +# endif + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + unsigned short int __pad2; +# ifndef __USE_FILE_OFFSET64 + __off_t st_size; /* Size of file, in bytes. */ +# else + __off64_t st_size; /* Size of file, in bytes. */ +# endif + __blksize_t st_blksize; /* Optimal block size for I/O. */ + +# ifndef __USE_FILE_OFFSET64 + __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ +# else + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +# endif +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif +# ifndef __USE_FILE_OFFSET64 + unsigned long int __glibc_reserved4; + unsigned long int __glibc_reserved5; +# else + __ino64_t st_ino; /* File serial number. */ +# endif +#endif /* __USE_TIME_BITS64 */ + }; + +#ifdef __USE_LARGEFILE64 +struct stat64 + { +# ifdef __USE_TIME_BITS64 +# include +# else + __dev_t st_dev; /* Device. */ + unsigned int __pad1; + + __ino_t __st_ino; /* 32bit file serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + unsigned int __pad2; + __off64_t st_size; /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + __ino64_t st_ino; /* File serial number. */ +# endif /* __USE_TIME_BITS64 */ + }; +#endif + +/* Tell code we have these members. */ +#define _STATBUF_ST_BLKSIZE +#define _STATBUF_ST_RDEV +/* Nanosecond resolution time values are supported. */ +#define _STATBUF_ST_NSEC + + +#endif /* _BITS_STRUCT_STAT_H */ diff --git a/sysdeps/unix/sysv/linux/bits/struct_stat.h b/sysdeps/unix/sysv/linux/bits/struct_stat.h index 25bd6cb638..fb11a3fba4 100644 --- a/sysdeps/unix/sysv/linux/bits/struct_stat.h +++ b/sysdeps/unix/sysv/linux/bits/struct_stat.h @@ -26,37 +26,36 @@ #include #include -struct stat - { -#ifdef __USE_TIME_BITS64 -# include -#else - __dev_t st_dev; /* Device. */ - unsigned short int __pad1; -# ifndef __USE_FILE_OFFSET64 - __ino_t st_ino; /* File serial number. */ -# else - __ino_t __st_ino; /* 32bit file serial number. */ +#if defined __USE_FILE_OFFSET64 +# define __field64(type, type64, name) type64 name +#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T +# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T +# error "ino_t and off_t must both be the same type" # endif - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - unsigned short int __pad2; -# ifndef __USE_FILE_OFFSET64 - __off_t st_size; /* Size of file, in bytes. */ -# else - __off64_t st_size; /* Size of file, in bytes. */ -# endif - __blksize_t st_blksize; /* Optimal block size for I/O. */ +# define __field64(type, type64, name) type name +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define __field64(type, type64, name) \ + type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad +#else +# define __field64(type, type64, name) \ + int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name +#endif -# ifndef __USE_FILE_OFFSET64 - __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ -# else - __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -# endif -# ifdef __USE_XOPEN2K8 +struct stat + { + __dev_t st_dev; /* Device. */ + __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + __dev_t __pad1; + __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ +#ifdef __USE_XOPEN2K8 /* Nanosecond resolution timestamps are stored in a format equivalent to 'struct timespec'. This is the type used whenever possible but the Unix namespace rules do not allow the @@ -66,47 +65,38 @@ struct stat struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -# else +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +#else __time_t st_atime; /* Time of last access. */ unsigned long int st_atimensec; /* Nscecs of last access. */ __time_t st_mtime; /* Time of last modification. */ unsigned long int st_mtimensec; /* Nsecs of last modification. */ __time_t st_ctime; /* Time of last status change. */ unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif -# ifndef __USE_FILE_OFFSET64 - unsigned long int __glibc_reserved4; - unsigned long int __glibc_reserved5; -# else - __ino64_t st_ino; /* File serial number. */ -# endif -#endif /* __USE_TIME_BITS64 */ +#endif + int __glibc_reserved[2]; }; +#undef __field64 + #ifdef __USE_LARGEFILE64 struct stat64 { -# ifdef __USE_TIME_BITS64 -# include -# else - __dev_t st_dev; /* Device. */ - unsigned int __pad1; - - __ino_t __st_ino; /* 32bit file serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - unsigned int __pad2; - __off64_t st_size; /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - - __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -# ifdef __USE_XOPEN2K8 + __dev_t st_dev; /* Device. */ + __ino64_t st_ino; /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + __dev_t __pad1; + __off64_t st_size; /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ +#ifdef __USE_XOPEN2K8 /* Nanosecond resolution timestamps are stored in a format equivalent to 'struct timespec'. This is the type used whenever possible but the Unix namespace rules do not allow the @@ -116,16 +106,15 @@ struct stat64 struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ -# else +#else __time_t st_atime; /* Time of last access. */ unsigned long int st_atimensec; /* Nscecs of last access. */ __time_t st_mtime; /* Time of last modification. */ unsigned long int st_mtimensec; /* Nsecs of last modification. */ __time_t st_ctime; /* Time of last status change. */ unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif - __ino64_t st_ino; /* File serial number. */ -# endif /* __USE_TIME_BITS64 */ +#endif + int __glibc_reserved[2]; }; #endif @@ -135,5 +124,4 @@ struct stat64 /* Nanosecond resolution time values are supported. */ #define _STATBUF_ST_NSEC - #endif /* _BITS_STRUCT_STAT_H */ diff --git a/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h new file mode 100644 index 0000000000..f0ee455748 --- /dev/null +++ b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h @@ -0,0 +1,135 @@ +/* Definition for struct stat. Linux/csky version. + Copyright (C) 2020-2022 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 + . */ + +#if !defined _SYS_STAT_H && !defined _FCNTL_H +# error "Never include directly; use instead." +#endif + +#ifndef _BITS_STRUCT_STAT_H +#define _BITS_STRUCT_STAT_H 1 + +#include +#include + +#if defined __USE_FILE_OFFSET64 +# define __field64(type, type64, name) type64 name +#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T +# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T +# error "ino_t and off_t must both be the same type" +# endif +# define __field64(type, type64, name) type name +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define __field64(type, type64, name) \ + type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad +#else +# define __field64(type, type64, name) \ + int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name +#endif + +struct stat + { +#ifdef __USE_TIME_BITS64 +# include +#else + __dev_t st_dev; /* Device. */ + __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + __dev_t __pad1; + __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + int __glibc_reserved[2]; +#endif + }; + +#undef __field64 + +#ifdef __USE_LARGEFILE64 +struct stat64 + { +# ifdef __USE_TIME_BITS64 +# include +# else + __dev_t st_dev; /* Device. */ + __ino64_t st_ino; /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + __dev_t __pad1; + __off64_t st_size; /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + int __glibc_reserved[2]; +# endif + }; +#endif + +/* Tell code we have these members. */ +#define _STATBUF_ST_BLKSIZE +#define _STATBUF_ST_RDEV +/* Nanosecond resolution time values are supported. */ +#define _STATBUF_ST_NSEC + +#endif /* _BITS_STRUCT_STAT_H */ diff --git a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h b/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h deleted file mode 100644 index fb11a3fba4..0000000000 --- a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Definition for struct stat. - Copyright (C) 2020-2022 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 - . */ - -#if !defined _SYS_STAT_H && !defined _FCNTL_H -# error "Never include directly; use instead." -#endif - -#ifndef _BITS_STRUCT_STAT_H -#define _BITS_STRUCT_STAT_H 1 - -#include -#include - -#if defined __USE_FILE_OFFSET64 -# define __field64(type, type64, name) type64 name -#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T -# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T -# error "ino_t and off_t must both be the same type" -# endif -# define __field64(type, type64, name) type name -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define __field64(type, type64, name) \ - type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad -#else -# define __field64(type, type64, name) \ - int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name -#endif - -struct stat - { - __dev_t st_dev; /* Device. */ - __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; - -#undef __field64 - -#ifdef __USE_LARGEFILE64 -struct stat64 - { - __dev_t st_dev; /* Device. */ - __ino64_t st_ino; /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __off64_t st_size; /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; -#endif - -/* Tell code we have these members. */ -#define _STATBUF_ST_BLKSIZE -#define _STATBUF_ST_RDEV -/* Nanosecond resolution time values are supported. */ -#define _STATBUF_ST_NSEC - -#endif /* _BITS_STRUCT_STAT_H */ diff --git a/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h new file mode 100644 index 0000000000..38b6e13e68 --- /dev/null +++ b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h @@ -0,0 +1,139 @@ +/* Definition for struct stat. Linux/hppa version. + Copyright (C) 2020-2022 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 + . */ + +#if !defined _SYS_STAT_H && !defined _FCNTL_H +# error "Never include directly; use instead." +#endif + +#ifndef _BITS_STRUCT_STAT_H +#define _BITS_STRUCT_STAT_H 1 + +#include +#include + +struct stat + { +#ifdef __USE_TIME_BITS64 +# include +#else + __dev_t st_dev; /* Device. */ + unsigned short int __pad1; +# ifndef __USE_FILE_OFFSET64 + __ino_t st_ino; /* File serial number. */ +# else + __ino_t __st_ino; /* 32bit file serial number. */ +# endif + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + unsigned short int __pad2; +# ifndef __USE_FILE_OFFSET64 + __off_t st_size; /* Size of file, in bytes. */ +# else + __off64_t st_size; /* Size of file, in bytes. */ +# endif + __blksize_t st_blksize; /* Optimal block size for I/O. */ + +# ifndef __USE_FILE_OFFSET64 + __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ +# else + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +# endif +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif +# ifndef __USE_FILE_OFFSET64 + unsigned long int __glibc_reserved4; + unsigned long int __glibc_reserved5; +# else + __ino64_t st_ino; /* File serial number. */ +# endif +#endif /* __USE_TIME_BITS64 */ + }; + +#ifdef __USE_LARGEFILE64 +struct stat64 + { +# ifdef __USE_TIME_BITS64 +# include +# else + __dev_t st_dev; /* Device. */ + unsigned int __pad1; + + __ino_t __st_ino; /* 32bit file serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + unsigned int __pad2; + __off64_t st_size; /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + __ino64_t st_ino; /* File serial number. */ +# endif /* __USE_TIME_BITS64 */ + }; +#endif + +/* Tell code we have these members. */ +#define _STATBUF_ST_BLKSIZE +#define _STATBUF_ST_RDEV +/* Nanosecond resolution time values are supported. */ +#define _STATBUF_ST_NSEC + + +#endif /* _BITS_STRUCT_STAT_H */ diff --git a/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h new file mode 100644 index 0000000000..e00e71173e --- /dev/null +++ b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h @@ -0,0 +1,135 @@ +/* Definition for struct stat. Linux/nios2 version. + Copyright (C) 2020-2022 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 + . */ + +#if !defined _SYS_STAT_H && !defined _FCNTL_H +# error "Never include directly; use instead." +#endif + +#ifndef _BITS_STRUCT_STAT_H +#define _BITS_STRUCT_STAT_H 1 + +#include +#include + +#if defined __USE_FILE_OFFSET64 +# define __field64(type, type64, name) type64 name +#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T +# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T +# error "ino_t and off_t must both be the same type" +# endif +# define __field64(type, type64, name) type name +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define __field64(type, type64, name) \ + type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad +#else +# define __field64(type, type64, name) \ + int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name +#endif + +struct stat + { +#ifdef __USE_TIME_BITS64 +# include +#else + __dev_t st_dev; /* Device. */ + __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + __dev_t __pad1; + __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + int __glibc_reserved[2]; +#endif + }; + +#undef __field64 + +#ifdef __USE_LARGEFILE64 +struct stat64 + { +# ifdef __USE_TIME_BITS64 +# include +# else + __dev_t st_dev; /* Device. */ + __ino64_t st_ino; /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + __dev_t __pad1; + __off64_t st_size; /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + int __glibc_reserved[2]; +# endif + }; +#endif + +/* Tell code we have these members. */ +#define _STATBUF_ST_BLKSIZE +#define _STATBUF_ST_RDEV +/* Nanosecond resolution time values are supported. */ +#define _STATBUF_ST_NSEC + +#endif /* _BITS_STRUCT_STAT_H */ diff --git a/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h new file mode 100644 index 0000000000..0f7c9cdc89 --- /dev/null +++ b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h @@ -0,0 +1,139 @@ +/* Definition for struct stat. Linux/sh version. + Copyright (C) 2020-2022 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 + . */ + +#if !defined _SYS_STAT_H && !defined _FCNTL_H +# error "Never include directly; use instead." +#endif + +#ifndef _BITS_STRUCT_STAT_H +#define _BITS_STRUCT_STAT_H 1 + +#include +#include + +struct stat + { +#ifdef __USE_TIME_BITS64 +# include +#else + __dev_t st_dev; /* Device. */ + unsigned short int __pad1; +# ifndef __USE_FILE_OFFSET64 + __ino_t st_ino; /* File serial number. */ +# else + __ino_t __st_ino; /* 32bit file serial number. */ +# endif + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + unsigned short int __pad2; +# ifndef __USE_FILE_OFFSET64 + __off_t st_size; /* Size of file, in bytes. */ +# else + __off64_t st_size; /* Size of file, in bytes. */ +# endif + __blksize_t st_blksize; /* Optimal block size for I/O. */ + +# ifndef __USE_FILE_OFFSET64 + __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ +# else + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +# endif +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif +# ifndef __USE_FILE_OFFSET64 + unsigned long int __glibc_reserved4; + unsigned long int __glibc_reserved5; +# else + __ino64_t st_ino; /* File serial number. */ +# endif +#endif /* __USE_TIME_BITS64 */ + }; + +#ifdef __USE_LARGEFILE64 +struct stat64 + { +# ifdef __USE_TIME_BITS64 +# include +# else + __dev_t st_dev; /* Device. */ + unsigned int __pad1; + + __ino_t __st_ino; /* 32bit file serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + unsigned int __pad2; + __off64_t st_size; /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + __ino64_t st_ino; /* File serial number. */ +# endif /* __USE_TIME_BITS64 */ + }; +#endif + +/* Tell code we have these members. */ +#define _STATBUF_ST_BLKSIZE +#define _STATBUF_ST_RDEV +/* Nanosecond resolution time values are supported. */ +#define _STATBUF_ST_NSEC + + +#endif /* _BITS_STRUCT_STAT_H */ -- cgit 1.4.1 From a1dc0be03c9dd850b864bd7a9c03cf8e396eb7ca Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 25 Oct 2022 13:19:16 -0300 Subject: elf: Reinstate on DL_DEBUG_BINDINGS _dl_lookup_symbol_x The prelink removal done by 6628c742b2c16e wrongly removed the debug support. Checked on x86_64-linux-gnu. (cherry picked from commit 891a7958a28eac6d4af1517dd2896fef5e4951d4) --- elf/dl-lookup.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index 4c86dc694e..67fb2e31e2 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -854,6 +854,23 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, if (__glibc_unlikely (current_value.m->l_used == 0)) current_value.m->l_used = 1; + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)) + { + const char *reference_name = undef_map->l_name; + + _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'", + DSO_FILENAME (reference_name), + undef_map->l_ns, + DSO_FILENAME (current_value.m->l_name), + current_value.m->l_ns, + protected ? "protected" : "normal", undef_name); + if (version) + _dl_debug_printf_c (" [%s]\n", version->name); + else + _dl_debug_printf_c ("\n"); + } + + *ref = current_value.s; return LOOKUP_VALUE (current_value.m); } -- cgit 1.4.1 From 4c6a78addabbd6e1b69763e286768919e56dfe0a Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Sat, 15 Oct 2022 14:12:13 +0800 Subject: longlong.h: update from GCC for LoongArch clz/ctz support Update longlong.h to GCC r13-3269. Keep our local change (prefer https for gnu.org URL). --- stdlib/longlong.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stdlib/longlong.h b/stdlib/longlong.h index 9b89469ac2..d8f76a43b5 100644 --- a/stdlib/longlong.h +++ b/stdlib/longlong.h @@ -593,6 +593,18 @@ extern UDItype __umulsidi3 (USItype, USItype); #define UMUL_TIME 14 #endif +#ifdef __loongarch__ +# if W_TYPE_SIZE == 32 +# define count_leading_zeros(count, x) ((count) = __builtin_clz (x)) +# define count_trailing_zeros(count, x) ((count) = __builtin_ctz (x)) +# define COUNT_LEADING_ZEROS_0 32 +# elif W_TYPE_SIZE == 64 +# define count_leading_zeros(count, x) ((count) = __builtin_clzll (x)) +# define count_trailing_zeros(count, x) ((count) = __builtin_ctzll (x)) +# define COUNT_LEADING_ZEROS_0 64 +# endif +#endif + #if defined (__M32R__) && W_TYPE_SIZE == 32 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ /* The cmp clears the condition bit. */ \ -- cgit 1.4.1 From dd4131c8322891a0ad7cfb661efa41aecc02b581 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Nov 2022 20:43:55 +0100 Subject: linux: Fix fstatat on MIPSn64 (BZ #29730) Commit 6e8a0aac2f883 ("time: Fix overflow itimer tests on 32-bit systems") changed in_time_t_range to assume a 32-bit time_t. This broke fstatat on MIPSn64 that was using it with a 64-bit time_t due to difference between stat and stat64. This commit fix that by adding a MIPSn64 specific version, which bypasses the EOVERFLOW tests. Resolves: BZ #29730 Reviewed-by: Adhemerval Zanella (cherry picked from commit 7457b7eef8dfe8cc48e55b9f9837df6dd397b80d) --- NEWS | 1 + sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c | 51 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c diff --git a/NEWS b/NEWS index 833045585f..e92d547e2c 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,7 @@ The following bugs are resolved with this release: [29638] libc: stdlib: arc4random fallback is never used [29657] libc: Incorrect struct stat for 64-bit time on linux/generic platforms + [29730] broken y2038 support in fstatat on MIPS N64 Version 2.36 diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c new file mode 100644 index 0000000000..fe6c3a0dda --- /dev/null +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c @@ -0,0 +1,51 @@ +/* Get file status. Linux/MIPSn64 version. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +/* Different than other ABIs, mips64 has different layouts for non-LFS + and LFS struct stat. */ +int +__fstatat (int fd, const char *file, struct stat *buf, int flag) +{ + struct __stat64_t64 st64; + int r = __fstatat64_time64 (fd, file, &st64, flag); + if (r == 0) + { + /* Clear internal pad and reserved fields. */ + memset (buf, 0, sizeof (*buf)); + + buf->st_dev = st64.st_dev; + buf->st_ino = st64.st_ino; + buf->st_mode = st64.st_mode; + buf->st_nlink = st64.st_nlink; + buf->st_uid = st64.st_uid; + buf->st_gid = st64.st_gid; + buf->st_rdev = st64.st_rdev; + buf->st_size = st64.st_size; + buf->st_blksize = st64.st_blksize; + buf->st_blocks = st64.st_blocks; + buf->st_atim = st64.st_atim; + buf->st_mtim = st64.st_mtim; + buf->st_ctim = st64.st_ctim; + } + return r; +} + +weak_alias (__fstatat, fstatat) -- cgit 1.4.1 From 2fce85f67c56e46863db40b8ca75bbf0fa993053 Mon Sep 17 00:00:00 2001 From: caiyinyu Date: Wed, 12 Oct 2022 20:28:42 +0800 Subject: LoongArch: Fix ABI related macros in elf.h to keep consistent with binutils[1]. [1]: https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=c4a7e6b56218e1d5a858682186b542e2eae01a4a;hp=0d94a8735055432029237612a6eb9165db1ec9dd [2]: Reference: https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_e_flags_identifies_abi_type_and_version --- elf/elf.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/elf/elf.h b/elf/elf.h index 02a1b3f52f..014393f3cc 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -4085,8 +4085,11 @@ enum #define R_NDS32_TLS_DESC 119 /* LoongArch ELF Flags */ -#define EF_LARCH_ABI 0x07 -#define EF_LARCH_ABI_LP64D 0x03 +#define EF_LARCH_ABI_MODIFIER_MASK 0x07 +#define EF_LARCH_ABI_SOFT_FLOAT 0x01 +#define EF_LARCH_ABI_SINGLE_FLOAT 0x02 +#define EF_LARCH_ABI_DOUBLE_FLOAT 0x03 +#define EF_LARCH_OBJABI_V1 0x40 /* LoongArch specific dynamic relocations */ #define R_LARCH_NONE 0 -- cgit 1.4.1 From 36cc06341a0c5029f49efaeef744dc3e9758e669 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Tue, 13 Sep 2022 13:39:13 -0400 Subject: Makerules: fix MAKEFLAGS assignment for upcoming make-4.4 [BZ# 29564] make-4.4 will add long flags to MAKEFLAGS variable: * WARNING: Backward-incompatibility! Previously only simple (one-letter) options were added to the MAKEFLAGS variable that was visible while parsing makefiles. Now, all options are available in MAKEFLAGS. This causes locale builds to fail when long options are used: $ make --shuffle ... make -C localedata install-locales make: invalid shuffle mode: '1662724426r' The change fixes it by passing eash option via whitespace and dashes. That way option is appended to both single-word form and whitespace separated form. While at it fixed --silent mode detection in $(MAKEFLAGS) by filtering out --long-options. Otherwise options like --shuffle flag enable silent mode unintentionally. $(silent-make) variable consolidates the checks. Resolves: BZ# 29564 CC: Paul Smith CC: Siddhesh Poyarekar Signed-off-by: Sergei Trofimovich Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 2d7ed98add14f75041499ac189696c9bd3d757fe) --- Makeconfig | 18 +++++++++++++++++- Makerules | 4 ++-- elf/rtld-Rules | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Makeconfig b/Makeconfig index ba70321af1..2bbcabd8f9 100644 --- a/Makeconfig +++ b/Makeconfig @@ -43,6 +43,22 @@ else $(error objdir must be defined by the build-directory Makefile) endif +# Did we request 'make -s' run? "yes" or "no". +# Starting from make-4.4 MAKEFLAGS now contains long +# options like '--shuffle'. To detect presence of 's' +# we pick first word with short options. Long options +# are guaranteed to come after whitespace. We use '-' +# prefix to always have a word before long options +# even if no short options were passed. +# Typical MAKEFLAGS values to watch for: +# "rs --shuffle=42" (silent) +# " --shuffle" (not silent) +ifeq ($(findstring s, $(firstword -$(MAKEFLAGS))),) +silent-make := no +else +silent-make := yes +endif + # Root of the sysdeps tree. sysdep_dir := $(..)sysdeps export sysdep_dir := $(sysdep_dir) @@ -917,7 +933,7 @@ endif # umpteen zillion filenames along with it (we use `...' instead) # but we don't want this echoing done when the user has said # he doesn't want to see commands echoed by using -s. -ifneq "$(findstring s,$(MAKEFLAGS))" "" # if -s +ifeq ($(silent-make),yes) # if -s +cmdecho := echo >/dev/null else # not -s +cmdecho := echo diff --git a/Makerules b/Makerules index d1e139d03c..09c0cf8357 100644 --- a/Makerules +++ b/Makerules @@ -794,7 +794,7 @@ endif # Maximize efficiency by minimizing the number of rules. .SUFFIXES: # Clear the suffix list. We don't use suffix rules. # Don't define any builtin rules. -MAKEFLAGS := $(MAKEFLAGS)r +MAKEFLAGS := $(MAKEFLAGS) -r # Generic rule for making directories. %/: @@ -811,7 +811,7 @@ MAKEFLAGS := $(MAKEFLAGS)r .PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c)) # Use the verbose option of ar and tar when not running silently. -ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s +ifeq ($(silent-make),no) # if not -s verbose := v else # -s verbose := diff --git a/elf/rtld-Rules b/elf/rtld-Rules index ca00dd1fe2..3c5e273f2b 100644 --- a/elf/rtld-Rules +++ b/elf/rtld-Rules @@ -52,7 +52,7 @@ $(objpfx)rtld-libc.a: $(foreach dir,$(rtld-subdirs),\ mv -f $@T $@ # Use the verbose option of ar and tar when not running silently. -ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s +ifeq ($(silent-make),no) # if not -s verbose := v else # -s verbose := -- cgit 1.4.1 From 70410f2286cc36c9ccb133878811c728ae51725f Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 8 Sep 2022 20:08:32 -0500 Subject: mktime: improve heuristic for ca-1986 Indiana DST This patch syncs mktime.c from Gnulib, fixing a problem reported by Mark Krenz , and it should fix BZ#29035 too. * time/mktime.c (__mktime_internal): Be more generous about accepting arguments with the wrong value of tm_isdst, by falling back to a one-hour DST difference if we find no nearby DST that is unusual. This fixes a problem where "1986-04-28 00:00 EDT" was rejected when TZ="America/Indianapolis" because the nearest DST timestamp occurred in 1970, a temporal distance too great for the old heuristic. This also also narrows the search a bit, which is a minor performance win. (cherry picked from commit 83859e1115269cf56d21669361d4ddbe2687831c) --- time/mktime.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/time/mktime.c b/time/mktime.c index 494c89bf54..e9a6006710 100644 --- a/time/mktime.c +++ b/time/mktime.c @@ -429,8 +429,13 @@ __mktime_internal (struct tm *tp, time with the right value, and use its UTC offset. Heuristic: probe the adjacent timestamps in both directions, - looking for the desired isdst. This should work for all real - time zone histories in the tz database. */ + looking for the desired isdst. If none is found within a + reasonable duration bound, assume a one-hour DST difference. + This should work for all real time zone histories in the tz + database. */ + + /* +1 if we wanted standard time but got DST, -1 if the reverse. */ + int dst_difference = (isdst == 0) - (tm.tm_isdst == 0); /* Distance between probes when looking for a DST boundary. In tzdata2003a, the shortest period of DST is 601200 seconds @@ -441,12 +446,14 @@ __mktime_internal (struct tm *tp, periods when probing. */ int stride = 601200; - /* The longest period of DST in tzdata2003a is 536454000 seconds - (e.g., America/Jujuy starting 1946-10-01 01:00). The longest - period of non-DST is much longer, but it makes no real sense - to search for more than a year of non-DST, so use the DST - max. */ - int duration_max = 536454000; + /* In TZDB 2021e, the longest period of DST (or of non-DST), in + which the DST (or adjacent DST) difference is not one hour, + is 457243209 seconds: e.g., America/Cambridge_Bay with leap + seconds, starting 1965-10-31 00:00 in a switch from + double-daylight time (-05) to standard time (-07), and + continuing to 1980-04-27 02:00 in a switch from standard time + (-07) to daylight time (-06). */ + int duration_max = 457243209; /* Search in both directions, so the maximum distance is half the duration; add the stride to avoid off-by-1 problems. */ @@ -483,6 +490,11 @@ __mktime_internal (struct tm *tp, } } + /* No unusual DST offset was found nearby. Assume one-hour DST. */ + t += 60 * 60 * dst_difference; + if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm)) + goto offset_found; + __set_errno (EOVERFLOW); return -1; } -- cgit 1.4.1 From 0f90d6204d79223fd32248c774df0cb7f0e604de Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 8 Nov 2022 14:15:02 +0100 Subject: Linux: Support __IPC_64 in sysvctl *ctl command arguments (bug 29771) Old applications pass __IPC_64 as part of the command argument because old glibc did not check for unknown commands, and passed through the arguments directly to the kernel, without adding __IPC_64. Applications need to continue doing that for old glibc compatibility, so this commit enables this approach in current glibc. For msgctl and shmctl, if no translation is required, make direct system calls, as we did before the time64 changes. If translation is required, mask __IPC_64 from the command argument. For semctl, the union-in-vararg argument handling means that translation is needed on all architectures. Reviewed-by: Adhemerval Zanella (cherry picked from commit 22a46dee24351fd5f4f188ad80554cad79c82524) --- NEWS | 1 + sysdeps/unix/sysv/linux/ipc_priv.h | 6 ++++++ sysdeps/unix/sysv/linux/msgctl.c | 38 +++++++++++++++++++++++++------------- sysdeps/unix/sysv/linux/semctl.c | 7 +++++++ sysdeps/unix/sysv/linux/shmctl.c | 38 +++++++++++++++++++++++++------------- 5 files changed, 64 insertions(+), 26 deletions(-) diff --git a/NEWS b/NEWS index e92d547e2c..9f8edea5db 100644 --- a/NEWS +++ b/NEWS @@ -46,6 +46,7 @@ The following bugs are resolved with this release: [29657] libc: Incorrect struct stat for 64-bit time on linux/generic platforms [29730] broken y2038 support in fstatat on MIPS N64 + [29771] Restore IPC_64 support in sysvipc *ctl functions Version 2.36 diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h index 87893a6757..2f50c31a8e 100644 --- a/sysdeps/unix/sysv/linux/ipc_priv.h +++ b/sysdeps/unix/sysv/linux/ipc_priv.h @@ -63,4 +63,10 @@ struct __old_ipc_perm # define __IPC_TIME64 0 #endif +#if __IPC_TIME64 || defined __ASSUME_SYSVIPC_BROKEN_MODE_T +# define IPC_CTL_NEED_TRANSLATION 1 +#else +# define IPC_CTL_NEED_TRANSLATION 0 +#endif + #include diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c index e824ebb095..2072205252 100644 --- a/sysdeps/unix/sysv/linux/msgctl.c +++ b/sysdeps/unix/sysv/linux/msgctl.c @@ -85,11 +85,19 @@ msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf) int __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) { -#if __IPC_TIME64 +#if IPC_CTL_NEED_TRANSLATION +# if __IPC_TIME64 struct kernel_msqid64_ds ksemid, *arg = NULL; -#else +# else msgctl_arg_t *arg; -#endif +# endif + + /* Some applications pass the __IPC_64 flag in cmd, to invoke + previously unsupported commands back when there was no EINVAL + error checking in glibc. Mask the flag for the switch statements + below. msgctl_syscall adds back the __IPC_64 flag for the actual + system call. */ + cmd &= ~__IPC_64; switch (cmd) { @@ -101,19 +109,19 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) case IPC_STAT: case MSG_STAT: case MSG_STAT_ANY: -#if __IPC_TIME64 +# if __IPC_TIME64 if (buf != NULL) { msqid64_to_kmsqid64 (buf, &ksemid); arg = &ksemid; } -# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T if (cmd == IPC_SET) arg->msg_perm.mode *= 0x10000U; -# endif -#else +# endif +# else arg = buf; -#endif +# endif break; case IPC_INFO: @@ -137,21 +145,25 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) case IPC_STAT: case MSG_STAT: case MSG_STAT_ANY: -#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T arg->msg_perm.mode >>= 16; -#else +# else /* Old Linux kernel versions might not clear the mode padding. */ if (sizeof ((struct msqid_ds){0}.msg_perm.mode) != sizeof (__kernel_mode_t)) arg->msg_perm.mode &= 0xFFFF; -#endif +# endif -#if __IPC_TIME64 +# if __IPC_TIME64 kmsqid64_to_msqid64 (arg, buf); -#endif +# endif } return ret; + +#else /* !IPC_CTL_NEED_TRANSLATION */ + return msgctl_syscall (msqid, cmd, buf); +#endif } #if __TIMESIZE != 64 libc_hidden_def (__msgctl64) diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c index 77a8130c18..3458b018bc 100644 --- a/sysdeps/unix/sysv/linux/semctl.c +++ b/sysdeps/unix/sysv/linux/semctl.c @@ -140,6 +140,13 @@ __semctl64 (int semid, int semnum, int cmd, ...) union semun64 arg64 = { 0 }; va_list ap; + /* Some applications pass the __IPC_64 flag in cmd, to invoke + previously unsupported commands back when there was no EINVAL + error checking in glibc. Mask the flag for the switch statements + below. semctl_syscall adds back the __IPC_64 flag for the actual + system call. */ + cmd &= ~__IPC_64; + /* Get the argument only if required. */ switch (cmd) { diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c index ea38935497..f00817a6f6 100644 --- a/sysdeps/unix/sysv/linux/shmctl.c +++ b/sysdeps/unix/sysv/linux/shmctl.c @@ -85,11 +85,19 @@ shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf) int __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) { -#if __IPC_TIME64 +#if IPC_CTL_NEED_TRANSLATION +# if __IPC_TIME64 struct kernel_shmid64_ds kshmid, *arg = NULL; -#else +# else shmctl_arg_t *arg; -#endif +# endif + + /* Some applications pass the __IPC_64 flag in cmd, to invoke + previously unsupported commands back when there was no EINVAL + error checking in glibc. Mask the flag for the switch statements + below. shmctl_syscall adds back the __IPC_64 flag for the actual + system call. */ + cmd &= ~__IPC_64; switch (cmd) { @@ -103,19 +111,19 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) case IPC_STAT: case SHM_STAT: case SHM_STAT_ANY: -#if __IPC_TIME64 +# if __IPC_TIME64 if (buf != NULL) { shmid64_to_kshmid64 (buf, &kshmid); arg = &kshmid; } -# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T if (cmd == IPC_SET) arg->shm_perm.mode *= 0x10000U; -# endif -#else +# endif +# else arg = buf; -#endif +# endif break; case IPC_INFO: @@ -140,21 +148,25 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) case IPC_STAT: case SHM_STAT: case SHM_STAT_ANY: -#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T arg->shm_perm.mode >>= 16; -#else +# else /* Old Linux kernel versions might not clear the mode padding. */ if (sizeof ((struct shmid_ds){0}.shm_perm.mode) != sizeof (__kernel_mode_t)) arg->shm_perm.mode &= 0xFFFF; -#endif +# endif -#if __IPC_TIME64 +# if __IPC_TIME64 kshmid64_to_shmid64 (arg, buf); -#endif +# endif } return ret; + +#else /* !IPC_CTL_NEED_TRANSLATION */ + return shmctl_syscall (shmid, cmd, buf); +#endif } #if __TIMESIZE != 64 libc_hidden_def (__shmctl64) -- cgit 1.4.1 From 2ba9801d9f222de9fe1f5f04dcd1c276e56b4245 Mon Sep 17 00:00:00 2001 From: Vladislav Khmelevsky Date: Thu, 17 Nov 2022 12:47:29 +0400 Subject: elf: Fix rtld-audit trampoline for aarch64 This patch fixes two problems with audit: 1. The DL_OFFSET_RV_VPCS offset was mixed up with DL_OFFSET_RG_VPCS, resulting in x2 register value nulling in RG structure. 2. We need to preserve the x8 register before function call, but don't have to save it's new value and restore it before return. Anyway the final restore was using OFFSET_RV instead of OFFSET_RG value which is wrong (althoug doesn't affect anything). Reviewed-by: Adhemerval Zanella (cherry picked from commit eb4181e9f4a512de37dad4ba623c921671584dea) --- sysdeps/aarch64/dl-trampoline.S | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S index 909b208578..d66f0b9c45 100644 --- a/sysdeps/aarch64/dl-trampoline.S +++ b/sysdeps/aarch64/dl-trampoline.S @@ -298,12 +298,11 @@ _dl_runtime_profile: stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] - str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] - str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS] + str xzr, [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS] /* Setup call to pltexit */ ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] @@ -315,7 +314,6 @@ _dl_runtime_profile: ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] - ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4] ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] -- cgit 1.4.1 From fa196d06d392f9bb2eae2f41613c6b0710f26293 Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Tue, 20 Sep 2022 17:58:04 -0700 Subject: x86: Fix wcsnlen-avx2 page cross length comparison [BZ #29591] Previous implementation was adjusting length (rsi) to match bytes (eax), but since there is no bound to length this can cause overflow. Fix is to just convert the byte-count (eax) to length by dividing by sizeof (wchar_t) before the comparison. Full check passes on x86-64 and build succeeds w/ and w/o multiarch. (cherry picked from commit b0969fa53a28b4ab2159806bf6c99a98999502ee) --- string/test-strnlen.c | 70 ++++++++++++++++++++-------------- sysdeps/x86_64/multiarch/strlen-avx2.S | 7 +--- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/string/test-strnlen.c b/string/test-strnlen.c index 4a9375112a..5cbaf4b734 100644 --- a/string/test-strnlen.c +++ b/string/test-strnlen.c @@ -73,7 +73,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char) { size_t i; - align &= 63; + align &= (getpagesize () / sizeof (CHAR) - 1); if ((align + len) * sizeof (CHAR) >= page_size) return; @@ -90,38 +90,50 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char) static void do_overflow_tests (void) { - size_t i, j, len; + size_t i, j, al_idx, repeats, len; const size_t one = 1; uintptr_t buf_addr = (uintptr_t) buf1; + const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 }; - for (i = 0; i < 750; ++i) + for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]); + al_idx++) { - do_test (1, i, SIZE_MAX, BIG_CHAR); - - do_test (0, i, SIZE_MAX - i, BIG_CHAR); - do_test (0, i, i - buf_addr, BIG_CHAR); - do_test (0, i, -buf_addr - i, BIG_CHAR); - do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR); - do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR); - - len = 0; - for (j = 8 * sizeof(size_t) - 1; j ; --j) - { - len |= one << j; - do_test (0, i, len - i, BIG_CHAR); - do_test (0, i, len + i, BIG_CHAR); - do_test (0, i, len - buf_addr - i, BIG_CHAR); - do_test (0, i, len - buf_addr + i, BIG_CHAR); - - do_test (0, i, ~len - i, BIG_CHAR); - do_test (0, i, ~len + i, BIG_CHAR); - do_test (0, i, ~len - buf_addr - i, BIG_CHAR); - do_test (0, i, ~len - buf_addr + i, BIG_CHAR); - - do_test (0, i, -buf_addr, BIG_CHAR); - do_test (0, i, j - buf_addr, BIG_CHAR); - do_test (0, i, -buf_addr - j, BIG_CHAR); - } + for (repeats = 0; repeats < 2; ++repeats) + { + size_t align = repeats ? (getpagesize () - alignments[al_idx]) + : alignments[al_idx]; + align /= sizeof (CHAR); + for (i = 0; i < 750; ++i) + { + do_test (align, i, SIZE_MAX, BIG_CHAR); + + do_test (align, i, SIZE_MAX - i, BIG_CHAR); + do_test (align, i, i - buf_addr, BIG_CHAR); + do_test (align, i, -buf_addr - i, BIG_CHAR); + do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR); + do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR); + + len = 0; + for (j = 8 * sizeof (size_t) - 1; j; --j) + { + len |= one << j; + do_test (align, i, len, BIG_CHAR); + do_test (align, i, len - i, BIG_CHAR); + do_test (align, i, len + i, BIG_CHAR); + do_test (align, i, len - buf_addr - i, BIG_CHAR); + do_test (align, i, len - buf_addr + i, BIG_CHAR); + + do_test (align, i, ~len - i, BIG_CHAR); + do_test (align, i, ~len + i, BIG_CHAR); + do_test (align, i, ~len - buf_addr - i, BIG_CHAR); + do_test (align, i, ~len - buf_addr + i, BIG_CHAR); + + do_test (align, i, -buf_addr, BIG_CHAR); + do_test (align, i, j - buf_addr, BIG_CHAR); + do_test (align, i, -buf_addr - j, BIG_CHAR); + } + } + } } } diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S index 0593fb303b..b9b58ef599 100644 --- a/sysdeps/x86_64/multiarch/strlen-avx2.S +++ b/sysdeps/x86_64/multiarch/strlen-avx2.S @@ -544,14 +544,11 @@ L(return_vzeroupper): L(cross_page_less_vec): tzcntl %eax, %eax # ifdef USE_AS_WCSLEN - /* NB: Multiply length by 4 to get byte count. */ - sall $2, %esi + /* NB: Divide by 4 to convert from byte-count to length. */ + shrl $2, %eax # endif cmpq %rax, %rsi cmovb %esi, %eax -# ifdef USE_AS_WCSLEN - shrl $2, %eax -# endif VZEROUPPER_RETURN # endif -- cgit 1.4.1 From 3aae843e9e9e6a2502e98ff44d2671b20a023f8e Mon Sep 17 00:00:00 2001 From: Tulio Magno Quites Machado Filho Date: Fri, 11 Nov 2022 17:00:15 -0300 Subject: Apply asm redirections in syslog.h before first use [BZ #27087] Similar to d0fa09a770, but for syslog.h when _FORTIFY_SOURCE > 0. Fixes [BZ #27087] by applying long double-related asm redirections before using functions in bits/syslog.h. Tested with build-many-glibcs.py. Reviewed-by: Adhemerval Zanella (cherry picked from commit 227df6243a2b5b4d70d11772d12c02eb9cb666ca) --- misc/bits/syslog.h | 18 ++++++++++++++---- misc/sys/syslog.h | 10 +++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h index fd30dd3114..916d2b6f12 100644 --- a/misc/bits/syslog.h +++ b/misc/bits/syslog.h @@ -24,6 +24,20 @@ extern void __syslog_chk (int __pri, int __flag, const char *__fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); +#ifdef __USE_MISC +extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt, + __gnuc_va_list __ap) + __attribute__ ((__format__ (__printf__, 3, 0))); +#endif + +#include +#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 +# include +#endif + +/* The following functions must be used only after applying all asm + redirections, e.g. long double asm redirections. */ + #ifdef __va_arg_pack __fortify_function void syslog (int __pri, const char *__fmt, ...) @@ -37,10 +51,6 @@ syslog (int __pri, const char *__fmt, ...) #ifdef __USE_MISC -extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt, - __gnuc_va_list __ap) - __attribute__ ((__format__ (__printf__, 3, 0))); - __fortify_function void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap) { diff --git a/misc/sys/syslog.h b/misc/sys/syslog.h index d933fea104..3888153ed2 100644 --- a/misc/sys/syslog.h +++ b/misc/sys/syslog.h @@ -205,11 +205,11 @@ extern void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap) /* Define some macros helping to catch buffer overflows. */ #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function # include -#endif - -#include -#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 -# include +#else +# include +# if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 +# include +# endif #endif __END_DECLS -- cgit 1.4.1 From fdcd20a55bf88f79f6457d36a93aee69f9bed971 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Netto Date: Wed, 26 Oct 2022 16:04:23 -0300 Subject: nis: Build libnsl with 64 bit time_t And remove the usage of glibc reserved names. Reviewed-by: DJ Delorie (cherry picked from commit 545eefc2f5da61801ba82b7a32ca2589b769ec90) --- Makeconfig | 2 +- nis/nis_call.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makeconfig b/Makeconfig index 2bbcabd8f9..9dd058e04b 100644 --- a/Makeconfig +++ b/Makeconfig @@ -884,7 +884,7 @@ endif # Use 64 bit time_t support for installed programs installed-modules = nonlib nscd lddlibc4 ldconfig locale_programs \ iconvprogs libnss_files libnss_compat libnss_db libnss_hesiod \ - libutil libpcprofile libSegFault + libutil libpcprofile libSegFault libnsl +extra-time-flags = $(if $(filter $(installed-modules),\ $(in-module)),-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64) diff --git a/nis/nis_call.c b/nis/nis_call.c index 90187e30b1..5b9dd50151 100644 --- a/nis/nis_call.c +++ b/nis/nis_call.c @@ -574,7 +574,7 @@ static struct nis_server_cache unsigned int size; unsigned int server_used; unsigned int current_ep; - __time64_t expires; + time_t expires; char name[]; } *nis_server_cache[16]; static time_t nis_cold_start_mtime; @@ -583,7 +583,7 @@ __libc_lock_define_initialized (static, nis_server_cache_lock) static directory_obj * nis_server_cache_search (const_nis_name name, int search_parent, unsigned int *server_used, unsigned int *current_ep, - struct __timespec64 *now) + struct timespec *now) { directory_obj *ret = NULL; int i; @@ -641,7 +641,7 @@ nis_server_cache_search (const_nis_name name, int search_parent, static void nis_server_cache_add (const_nis_name name, int search_parent, directory_obj *dir, unsigned int server_used, - unsigned int current_ep, struct __timespec64 *now) + unsigned int current_ep, struct timespec *now) { struct nis_server_cache **loc; struct nis_server_cache *new; @@ -707,7 +707,7 @@ __nisfind_server (const_nis_name name, int search_parent, nis_error result = NIS_SUCCESS; nis_error status; directory_obj *obj; - struct __timespec64 ts; + struct timespec ts; unsigned int server_used = ~0; unsigned int current_ep = ~0; @@ -717,7 +717,7 @@ __nisfind_server (const_nis_name name, int search_parent, if (*dir != NULL) return NIS_SUCCESS; - __clock_gettime64 (CLOCK_REALTIME, &ts); + clock_gettime (CLOCK_REALTIME, &ts); if ((flags & NO_CACHE) == 0) *dir = nis_server_cache_search (name, search_parent, &server_used, -- cgit 1.4.1 From c1e080bc9521d2282a1f60c2ee19d80adae672ee Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Netto Date: Wed, 26 Oct 2022 16:04:24 -0300 Subject: nscd: Use 64 bit time_t on libc nscd routines (BZ# 29402) Although the nscd module is built with 64 bit time_t, the routines linked direct to libc.so need to use the internal symbols. Reviewed-by: DJ Delorie (cherry picked from commit fa4a19277842fd09a4815a986f70e0fe0903836f) --- NEWS | 1 + nscd/nscd.h | 2 +- nscd/nscd_gethst_r.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 9f8edea5db..c3df0c007d 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,7 @@ The following bugs are resolved with this release: [24816] Fix tst-nss-files-hosts-long on single-stack hosts [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning [29305] Conserve NSS buffer space during DNS packet parsing + [29402] nscd: nscd: No such file or directory [29415] nscd: Fix netlink cache invalidation if epoll is used [28937] New DSO dependency sorter does not put new map first if in a cycle [29446] _dlopen now ignores dl_caller argument in static mode diff --git a/nscd/nscd.h b/nscd/nscd.h index 368091aef8..f15321585b 100644 --- a/nscd/nscd.h +++ b/nscd/nscd.h @@ -65,7 +65,7 @@ typedef enum struct traced_file { /* Tracks the last modified time of the traced file. */ - time_t mtime; + __time64_t mtime; /* Support multiple registered files per database. */ struct traced_file *next; int call_res_init; diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c index 9becb62033..31c64275f0 100644 --- a/nscd/nscd_gethst_r.c +++ b/nscd/nscd_gethst_r.c @@ -112,7 +112,7 @@ __nscd_get_nl_timestamp (void) if (map == NULL || (map != NO_MAPPING && map->head->nscd_certainly_running == 0 - && map->head->timestamp + MAPPING_TIMEOUT < time_now ())) + && map->head->timestamp + MAPPING_TIMEOUT < time64_now ())) map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped); if (map == NO_MAPPING) -- cgit 1.4.1 From 4321cbc2af788827e56e5581f56d7da2876b48f1 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Netto Date: Wed, 26 Oct 2022 16:04:25 -0300 Subject: time: Use 64 bit time on tzfile The tzfile_mtime is already compared to 64 bit time_t stat call. Reviewed-by: DJ Delorie (cherry picked from commit 4e21c2075193e406a92c0d1cb091a7c804fda4d9) --- time/tzfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/time/tzfile.c b/time/tzfile.c index dd75848ba9..394b098856 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -32,7 +32,7 @@ int __use_tzfile; static dev_t tzfile_dev; static ino64_t tzfile_ino; -static time_t tzfile_mtime; +static __time64_t tzfile_mtime; struct ttinfo { -- cgit 1.4.1 From 4444be051cae74fed390d4bc1a15ed730cc07b02 Mon Sep 17 00:00:00 2001 From: Martin Jansa Date: Wed, 21 Sep 2022 10:51:03 -0300 Subject: locale: prevent maybe-uninitialized errors with -Os [BZ #19444] Fixes following error when building with -Os: | In file included from strcoll_l.c:43: | strcoll_l.c: In function '__strcoll_l': | ../locale/weight.h:31:26: error: 'seq2.back_us' may be used uninitialized in this function [-Werror=maybe-uninitialized] | int_fast32_t i = table[*(*cpp)++]; | ^~~~~~~~~ | strcoll_l.c:304:18: note: 'seq2.back_us' was declared here | coll_seq seq1, seq2; | ^~~~ | In file included from strcoll_l.c:43: | ../locale/weight.h:31:26: error: 'seq1.back_us' may be used uninitialized in this function [-Werror=maybe-uninitialized] | int_fast32_t i = table[*(*cpp)++]; | ^~~~~~~~~ | strcoll_l.c:304:12: note: 'seq1.back_us' was declared here | coll_seq seq1, seq2; | ^~~~ Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit c651f9da530320e9939e6cbad57b87695eeba41c) --- locale/weight.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/locale/weight.h b/locale/weight.h index 8be2d220f8..4a4d5aa6b2 100644 --- a/locale/weight.h +++ b/locale/weight.h @@ -27,7 +27,14 @@ findidx (const int32_t *table, const unsigned char *extra, const unsigned char **cpp, size_t len) { + /* With GCC 8 when compiling with -Os the compiler warns that + seq1.back_us and seq2.back_us might be used uninitialized. + This uninitialized use is impossible for the same reason + as described in comments in locale/weightwc.h. */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized"); int32_t i = table[*(*cpp)++]; + DIAG_POP_NEEDS_COMMENT; const unsigned char *cp; const unsigned char *usrc; -- cgit 1.4.1 From 997d844a97b0478a3a7f9e7d7027c7431edbb51d Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Netto Date: Wed, 21 Sep 2022 10:51:07 -0300 Subject: sunrpc: Suppress GCC -Os warning on user2netname MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC with -Os warns that sprint might overflow: netname.c: In function ‘user2netname’: netname.c:51:28: error: ‘%s’ directive writing up to 255 bytes into a region of size between 239 and 249 [-Werror=format-overflow=] 51 | sprintf (netname, "%s.%d@%s", OPSYS, uid, dfltdom); | ^~ ~~~~~~~ netname.c:51:3: note: ‘sprintf’ output between 8 and 273 bytes into a destination of size 256 51 | sprintf (netname, "%s.%d@%s", OPSYS, uid, dfltdom); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors However the code does test prior the sprintf call that dfltdom plus the required extra space for OPSYS, uid, and extra character will not overflow and return 0 instead. Checked on x86_64-linux-gnu and i686-linux-gnu. Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit 6128e82ebe973163d2dd614d31753c88c0c4d645) --- sunrpc/netname.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sunrpc/netname.c b/sunrpc/netname.c index bf7f0b81c4..c1d1c43e50 100644 --- a/sunrpc/netname.c +++ b/sunrpc/netname.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "nsswitch.h" @@ -48,7 +49,12 @@ user2netname (char netname[MAXNETNAMELEN + 1], const uid_t uid, if ((strlen (dfltdom) + OPSYS_LEN + 3 + MAXIPRINT) > (size_t) MAXNETNAMELEN) return 0; + /* GCC with -Os warns that sprint might overflow while handling dfltdom, + however the above test does check if an overflow would happen. */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wformat-overflow"); sprintf (netname, "%s.%d@%s", OPSYS, uid, dfltdom); + DIAG_POP_NEEDS_COMMENT; i = strlen (netname); if (netname[i - 1] == '.') netname[i - 1] = '\0'; -- cgit 1.4.1 From 4f4d7a13edfd2fdc57c9d76e1fd6d017fb47550c Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Netto Date: Wed, 21 Sep 2022 10:51:08 -0300 Subject: x86: Fix -Os build (BZ #29576) The compiler might transform __stpcpy calls (which are routed to __builtin_stpcpy as an optimization) to strcpy and x86_64 strcpy multiarch implementation does not build any working symbol due ISA_SHOULD_BUILD not being evaluated for IS_IN(rtld). Checked on x86_64-linux-gnu. Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit 9dc4e29f630c6ef8299120b275e503321dc0c8c7) --- NEWS | 2 ++ sysdeps/x86_64/multiarch/rtld-strcpy.S | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 sysdeps/x86_64/multiarch/rtld-strcpy.S diff --git a/NEWS b/NEWS index c3df0c007d..fb2d73a6be 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,8 @@ The following bugs are resolved with this release: [29528] elf: Call __libc_early_init for reused namespaces [29537] libc: [2.34 regression]: Alignment issue on m68k when using [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are + [29576] build: librtld.os: in function `_dl_start_profile': + (.text+0x9444): undefined reference to `strcpy' [29583] Use 64-bit interfaces in gconv_parseconfdir [29600] Do not completely clear reused namespace in dlmopen [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is diff --git a/sysdeps/x86_64/multiarch/rtld-strcpy.S b/sysdeps/x86_64/multiarch/rtld-strcpy.S new file mode 100644 index 0000000000..19439c553d --- /dev/null +++ b/sysdeps/x86_64/multiarch/rtld-strcpy.S @@ -0,0 +1,18 @@ +/* Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include "../strcpy.S" -- cgit 1.4.1 From dbd23eaca95eb0264b6325c7286a4b370a67404d Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 12 Nov 2022 11:20:31 +1030 Subject: elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 (BZ# 29776) Supports pcrel addressing of TLS GOT entry. Also tweak the non-pcrel asm constraint to better reflect how the reg is used. (cherry picked from commit 94628de77888c3292fc103840731ff85f283368e) --- NEWS | 1 + sysdeps/powerpc/mod-tlsopt-powerpc.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index fb2d73a6be..dbe2b2e301 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,7 @@ The following bugs are resolved with this release: platforms [29730] broken y2038 support in fstatat on MIPS N64 [29771] Restore IPC_64 support in sysvipc *ctl functions + [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 Version 2.36 diff --git a/sysdeps/powerpc/mod-tlsopt-powerpc.c b/sysdeps/powerpc/mod-tlsopt-powerpc.c index 2a82e53baf..d941024963 100644 --- a/sysdeps/powerpc/mod-tlsopt-powerpc.c +++ b/sysdeps/powerpc/mod-tlsopt-powerpc.c @@ -22,7 +22,11 @@ tls_get_addr_opt_test (void) tls_index *tls_arg; #ifdef __powerpc64__ register unsigned long thread_pointer __asm__ ("r13"); - asm ("addi %0,2,foo@got@tlsgd" : "=r" (tls_arg)); +# ifdef __PCREL__ + asm ("paddi %0,0,foo@got@tlsgd@pcrel,1" : "=b" (tls_arg)); +# else + asm ("addi %0,2,foo@got@tlsgd" : "=b" (tls_arg)); +# endif #else register unsigned long thread_pointer __asm__ ("r2"); asm ("bcl 20,31,1f\n1:\t" -- cgit 1.4.1 From e05036b194559cbfcdfcfb1b920d37b939e3e35c Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 5 Jan 2023 18:21:25 +0100 Subject: time: Set daylight to 1 for matching DST/offset change (bug 29951) The daylight variable is supposed to be set to 1 if DST is ever in use for the current time zone. But __tzfile_read used to do this: __daylight = rule_stdoff != rule_dstoff; This check can fail to set __daylight to 1 if the DST and non-DST offsets happen to be the same. (cherry picked from commit 35141f304e319109c322f797ae71c0b9420ccb05) --- NEWS | 1 + time/tzfile.c | 41 +++++++++++++++-------------- timezone/Makefile | 4 ++- timezone/testdata/XT6 | Bin 0 -> 625 bytes timezone/tst-bz29951.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 timezone/testdata/XT6 create mode 100644 timezone/tst-bz29951.c diff --git a/NEWS b/NEWS index dbe2b2e301..8c79e83b77 100644 --- a/NEWS +++ b/NEWS @@ -51,6 +51,7 @@ The following bugs are resolved with this release: [29730] broken y2038 support in fstatat on MIPS N64 [29771] Restore IPC_64 support in sysvipc *ctl functions [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 + [29951] time: Set daylight to 1 for matching DST/offset change Version 2.36 diff --git a/time/tzfile.c b/time/tzfile.c index 394b098856..8bba4e5b8d 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -61,6 +61,10 @@ static size_t num_leaps; static struct leap *leaps; static char *tzspec; +/* Used to restore the daylight variable during time conversion, as if + tzset had been called. */ +static int daylight_saved; + #include #include @@ -438,36 +442,35 @@ __tzfile_read (const char *file, size_t extra, char **extrap) if (__tzname[1] == NULL) __tzname[1] = __tzname[0]; + daylight_saved = 0; if (num_transitions == 0) /* Use the first rule (which should also be the only one). */ rule_stdoff = rule_dstoff = types[0].offset; else { - int stdoff_set = 0, dstoff_set = 0; - rule_stdoff = rule_dstoff = 0; + rule_stdoff = 0; + + /* Search for the last rule with a standard time offset. This + will be used for the global timezone variable. */ i = num_transitions - 1; do - { - if (!stdoff_set && !types[type_idxs[i]].isdst) - { - stdoff_set = 1; - rule_stdoff = types[type_idxs[i]].offset; - } - else if (!dstoff_set && types[type_idxs[i]].isdst) - { - dstoff_set = 1; - rule_dstoff = types[type_idxs[i]].offset; - } - if (stdoff_set && dstoff_set) + if (!types[type_idxs[i]].isdst) + { + rule_stdoff = types[type_idxs[i]].offset; break; - } + } + else + daylight_saved = 1; while (i-- > 0); - if (!dstoff_set) - rule_dstoff = rule_stdoff; + /* Keep searching to see if there is a DST rule. This + information will be used to set the global daylight + variable. */ + while (i-- > 0 && !daylight_saved) + daylight_saved = types[type_idxs[i]].isdst; } - __daylight = rule_stdoff != rule_dstoff; + __daylight = daylight_saved; __timezone = -rule_stdoff; done: @@ -731,7 +734,7 @@ __tzfile_compute (__time64_t timer, int use_localtime, } struct ttinfo *info = &types[i]; - __daylight = rule_stdoff != rule_dstoff; + __daylight = daylight_saved; __timezone = -rule_stdoff; if (__tzname[0] == NULL) diff --git a/timezone/Makefile b/timezone/Makefile index a789c22d26..5002de39ad 100644 --- a/timezone/Makefile +++ b/timezone/Makefile @@ -23,7 +23,7 @@ subdir := timezone include ../Makeconfig others := zdump zic -tests := test-tz tst-timezone tst-tzset tst-bz28707 +tests := test-tz tst-timezone tst-tzset tst-bz28707 tst-bz29951 generated-dirs += testdata @@ -86,11 +86,13 @@ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \ Europe/London) $(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4) $(objpfx)tst-bz28707.out: $(testdata)/XT5 +$(objpfx)tst-bz29951.out: $(testdata)/XT6 test-tz-ENV = TZDIR=$(testdata) tst-timezone-ENV = TZDIR=$(testdata) tst-tzset-ENV = TZDIR=$(testdata) tst-bz28707-ENV = TZDIR=$(testdata) +tst-bz29951-ENV = TZDIR=$(testdata) # Note this must come second in the deps list for $(built-program-cmd) to work. zic-deps = $(objpfx)zic $(leapseconds) yearistype diff --git a/timezone/testdata/XT6 b/timezone/testdata/XT6 new file mode 100644 index 0000000000..07b393bb7d Binary files /dev/null and b/timezone/testdata/XT6 differ diff --git a/timezone/tst-bz29951.c b/timezone/tst-bz29951.c new file mode 100644 index 0000000000..abd334683b --- /dev/null +++ b/timezone/tst-bz29951.c @@ -0,0 +1,68 @@ +/* Check that daylight is set if the last DST transition did not change offset. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +/* Set the specified time zone with error checking. */ +static void +set_timezone (const char *name) +{ + TEST_VERIFY (setenv ("TZ", name, 1) == 0); + errno = 0; + tzset (); + TEST_COMPARE (errno, 0); +} + +static int +do_test (void) +{ + /* Test zone based on tz-2022g version of Africa/Tripoli. The last + DST transition coincided with a change in the standard time + offset, effectively making it a no-op. + + Africa/Tripoli Thu Oct 24 23:59:59 2013 UT + = Fri Oct 25 01:59:59 2013 CEST isdst=1 gmtoff=7200 + Africa/Tripoli Fri Oct 25 00:00:00 2013 UT + = Fri Oct 25 02:00:00 2013 EET isdst=0 gmtoff=7200 + */ + set_timezone ("XT6"); + TEST_VERIFY (daylight != 0); + TEST_COMPARE (timezone, -7200); + + /* Check that localtime re-initializes the two variables. */ + daylight = timezone = 17; + time_t t = 844034401; + struct tm *tm = localtime (&t); + TEST_VERIFY (daylight != 0); + TEST_COMPARE (timezone, -7200); + TEST_COMPARE (tm->tm_year, 96); + TEST_COMPARE (tm->tm_mon, 8); + TEST_COMPARE (tm->tm_mday, 29); + TEST_COMPARE (tm->tm_hour, 23); + TEST_COMPARE (tm->tm_min, 0); + TEST_COMPARE (tm->tm_sec, 1); + TEST_COMPARE (tm->tm_gmtoff, 3600); + TEST_COMPARE (tm->tm_isdst, 0); + + return 0; +} + +#include -- cgit 1.4.1 From 93967a2a7bbdcedb73e0b246713580c7c84d001e Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Wed, 14 Dec 2022 10:52:10 -0800 Subject: x86: Prevent SIGSEGV in memcmp-sse2 when data is concurrently modified [BZ #29863] In the case of INCORRECT usage of `memcmp(a, b, N)` where `a` and `b` are concurrently modified as `memcmp` runs, there can be a SIGSEGV in `L(ret_nonzero_vec_end_0)` because the sequential logic assumes that `(rdx - 32 + rax)` is a positive 32-bit integer. To be clear, this change does not mean the usage of `memcmp` is supported. The program behaviour is undefined (UB) in the presence of data races, and `memcmp` is incorrect when the values of `a` and/or `b` are modified concurrently (data race). This UB may manifest itself as a SIGSEGV. That being said, if we can allow the idiomatic use cases, like those in yottadb with opportunistic concurrency control (OCC), to execute without a SIGSEGV, at no cost to regular use cases, then we can aim to minimize harm to those existing users. The fix replaces a 32-bit `addl %edx, %eax` with the 64-bit variant `addq %rdx, %rax`. The 1-extra byte of code size from using the 64-bit instruction doesn't contribute to overall code size as the next target is aligned and has multiple bytes of `nop` padding before it. As well all the logic between the add and `ret` still fits in the same fetch block, so the cost of this change is basically zero. The relevant sequential logic can be seen in the following pseudo-code: ``` /* * rsi = a * rdi = b * rdx = len - 32 */ /* cmp a[0:15] and b[0:15]. Since length is known to be [17, 32] in this case, this check is also assumed to cover a[0:(31 - len)] and b[0:(31 - len)]. */ movups (%rsi), %xmm0 movups (%rdi), %xmm1 PCMPEQ %xmm0, %xmm1 pmovmskb %xmm1, %eax subl %ecx, %eax jnz L(END_NEQ) /* cmp a[len-16:len-1] and b[len-16:len-1]. */ movups 16(%rsi, %rdx), %xmm0 movups 16(%rdi, %rdx), %xmm1 PCMPEQ %xmm0, %xmm1 pmovmskb %xmm1, %eax subl %ecx, %eax jnz L(END_NEQ2) ret L(END2): /* Position first mismatch. */ bsfl %eax, %eax /* The sequential version is able to assume this value is a positive 32-bit value because the first check included bytes in range a[0:(31 - len)] and b[0:(31 - len)] so `eax` must be greater than `31 - len` so the minimum value of `edx` + `eax` is `(len - 32) + (32 - len) >= 0`. In the concurrent case, however, `a` or `b` could have been changed so a mismatch in `eax` less or equal than `(31 - len)` is possible (the new low bound is `(16 - len)`. This can result in a negative 32-bit signed integer, which when zero extended to 64-bits is a random large value this out out of bounds. */ addl %edx, %eax /* Crash here because 32-bit negative number in `eax` zero extends to out of bounds 64-bit offset. */ movzbl 16(%rdi, %rax), %ecx movzbl 16(%rsi, %rax), %eax ``` This fix is quite simple, just make the `addl %edx, %eax` 64 bit (i.e `addq %rdx, %rax`). This prevents the 32-bit zero extension and since `eax` is still a low bound of `16 - len` the `rdx + rax` is bound by `(len - 32) - (16 - len) >= -16`. Since we have a fixed offset of `16` in the memory access this must be in bounds. (cherry picked from commit b712be52645282c706a5faa038242504feb06db5) --- sysdeps/x86_64/multiarch/memcmp-sse2.S | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sysdeps/x86_64/multiarch/memcmp-sse2.S b/sysdeps/x86_64/multiarch/memcmp-sse2.S index afd450d020..51bc9344f0 100644 --- a/sysdeps/x86_64/multiarch/memcmp-sse2.S +++ b/sysdeps/x86_64/multiarch/memcmp-sse2.S @@ -308,7 +308,17 @@ L(ret_nonzero_vec_end_0): setg %dl leal -1(%rdx, %rdx), %eax # else - addl %edx, %eax + /* Use `addq` instead of `addl` here so that even if `rax` + `rdx` + is negative value of the sum will be usable as a 64-bit offset + (negative 32-bit numbers zero-extend to a large and often + out-of-bounds 64-bit offsets). Note that `rax` + `rdx` >= 0 is + an invariant when `memcmp` is used correctly, but if the input + strings `rsi`/`rdi` are concurrently modified as the function + runs (there is a Data-Race) it is possible for `rax` + `rdx` to + be negative. Given that there is virtually no extra to cost + using `addq` instead of `addl` we may as well protect the + data-race case. */ + addq %rdx, %rax movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rsi, %rax), %ecx movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rdi, %rax), %eax subl %ecx, %eax -- cgit 1.4.1 From 56e00c585420af63fc4df9e28ff9e12bb2a3274f Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Thu, 2 Feb 2023 07:49:02 -0500 Subject: cdefs: Limit definition of fortification macros Define the __glibc_fortify and other macros only when __FORTIFY_LEVEL > 0. This has the effect of not defining these macros on older C90 compilers that do not have support for variable length argument lists. Also trim off the trailing backslashes from the definition of __glibc_fortify and __glibc_fortify_n macros. Signed-off-by: Siddhesh Poyarekar Reviewed-by: Florian Weimer (cherry picked from commit 2337e04e21ba6040926ec871e403533f77043c40) --- misc/sys/cdefs.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h index f525f67547..294e633335 100644 --- a/misc/sys/cdefs.h +++ b/misc/sys/cdefs.h @@ -152,6 +152,7 @@ # define __glibc_objsize(__o) __bos (__o) #endif +#if __USE_FORTIFY_LEVEL > 0 /* Compile time conditions to choose between the regular, _chk and _chk_warn variants. These conditions should get evaluated to constant and optimized away. */ @@ -187,7 +188,7 @@ ? __ ## f ## _alias (__VA_ARGS__) \ : (__glibc_unsafe_len (__l, __s, __osz) \ ? __ ## f ## _chk_warn (__VA_ARGS__, __osz) \ - : __ ## f ## _chk (__VA_ARGS__, __osz))) \ + : __ ## f ## _chk (__VA_ARGS__, __osz))) /* Fortify function f, where object size argument passed to f is the number of elements and not total size. */ @@ -197,7 +198,8 @@ ? __ ## f ## _alias (__VA_ARGS__) \ : (__glibc_unsafe_len (__l, __s, __osz) \ ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \ - : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \ + : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) +#endif #if __GNUC_PREREQ (4,3) # define __warnattr(msg) __attribute__((__warning__ (msg))) -- cgit 1.4.1 From d5aaece8a3528ff5f9cc0ceeb067da0e47436669 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 3 Jan 2023 09:56:28 -0300 Subject: elf: Fix GL(dl_phdr) and GL(dl_phnum) for static builds [BZ #29864] The 73fc4e28b9464f0e refactor did not add the GL(dl_phdr) and GL(dl_phnum) for static build, relying on the __ehdr_start symbol, which is always added by the static linker, to get the correct values. This is problematic in some ways: - The segment may see its in-memory size differ from its in-file size (or the binary may have holes). The Linux has fixed is to provide concise values for both AT_PHDR and AT_PHNUM (commit 0da1d5002745c - "fs/binfmt_elf: Fix AT_PHDR for unusual ELF files") - Some archs (alpha for instance) the hidden weak reference is not correctly pulled by the static linker and __ehdr_start address end up being 0, which makes GL(dl_phdr) and GL(dl_phnum) have both invalid values (and triggering a segfault later on libc.so while accessing TLS variables). The safer fix is to just restore the previous behavior to setup GL(dl_phdr) and GL(dl_phnum) for static based on kernel auxv. The __ehdr_start fallback can also be simplified by not assuming weak linkage (as for PIE). The libc-static.c auxv init logic is moved to dl-support.c, since the later is build without SHARED and then GLRO macro is defined to access the variables directly. The _dl_phdr is also assumed to be always non NULL, since an invalid NULL values does not trigger TLS initialization (which is used in various libc systems). Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. Reviewed-by: Florian Weimer (cherry picked from commit 7e31d166510ac4adbf53d5e8144c709a37dd8c7a) --- NEWS | 2 ++ csu/libc-start.c | 21 --------------------- csu/libc-tls.c | 25 ++++++++++++------------- elf/dl-support.c | 46 ++++++++++++++++++++++++++++++++-------------- 4 files changed, 46 insertions(+), 48 deletions(-) diff --git a/NEWS b/NEWS index 8c79e83b77..c5e142eb3a 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,8 @@ The following bugs are resolved with this release: [12154] Do not fail DNS resolution for CNAMEs which are not host names [24816] Fix tst-nss-files-hosts-long on single-stack hosts [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning + [29864] libc: __libc_start_main() should obtain program headers + address (_dl_phdr) from the auxv, not the ELF header. [29305] Conserve NSS buffer space during DNS packet parsing [29402] nscd: nscd: No such file or directory [29415] nscd: Fix netlink cache invalidation if epoll is used diff --git a/csu/libc-start.c b/csu/libc-start.c index 543560f36c..bfeee6d851 100644 --- a/csu/libc-start.c +++ b/csu/libc-start.c @@ -262,28 +262,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), } # endif _dl_aux_init (auxvec); - if (GL(dl_phdr) == NULL) # endif - { - /* Starting from binutils-2.23, the linker will define the - magic symbol __ehdr_start to point to our own ELF header - if it is visible in a segment that also includes the phdrs. - So we can set up _dl_phdr and _dl_phnum even without any - information from auxv. */ - - extern const ElfW(Ehdr) __ehdr_start -# if BUILD_PIE_DEFAULT - __attribute__ ((visibility ("hidden"))); -# else - __attribute__ ((weak, visibility ("hidden"))); - if (&__ehdr_start != NULL) -# endif - { - assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); - GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff; - GL(dl_phnum) = __ehdr_start.e_phnum; - } - } __tunables_init (__environ); diff --git a/csu/libc-tls.c b/csu/libc-tls.c index 0a216c5502..7fdf7cd7a8 100644 --- a/csu/libc-tls.c +++ b/csu/libc-tls.c @@ -118,19 +118,18 @@ __libc_setup_tls (void) __tls_pre_init_tp (); /* Look through the TLS segment if there is any. */ - if (_dl_phdr != NULL) - for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) - if (phdr->p_type == PT_TLS) - { - /* Remember the values we need. */ - memsz = phdr->p_memsz; - filesz = phdr->p_filesz; - initimage = (void *) phdr->p_vaddr + main_map->l_addr; - align = phdr->p_align; - if (phdr->p_align > max_align) - max_align = phdr->p_align; - break; - } + for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) + if (phdr->p_type == PT_TLS) + { + /* Remember the values we need. */ + memsz = phdr->p_memsz; + filesz = phdr->p_filesz; + initimage = (void *) phdr->p_vaddr + main_map->l_addr; + align = phdr->p_align; + if (phdr->p_align > max_align) + max_align = phdr->p_align; + break; + } /* Calculate the size of the static TLS surplus, with 0 auditors. */ _dl_tls_static_surplus_init (0); diff --git a/elf/dl-support.c b/elf/dl-support.c index 4af0b5b2ce..f45b630ba5 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -255,6 +255,25 @@ _dl_aux_init (ElfW(auxv_t) *av) for (int i = 0; i < array_length (auxv_values); ++i) auxv_values[i] = 0; _dl_parse_auxv (av, auxv_values); + + _dl_phdr = (void*) auxv_values[AT_PHDR]; + _dl_phnum = auxv_values[AT_PHNUM]; + + if (_dl_phdr == NULL) + { + /* Starting from binutils-2.23, the linker will define the + magic symbol __ehdr_start to point to our own ELF header + if it is visible in a segment that also includes the phdrs. + So we can set up _dl_phdr and _dl_phnum even without any + information from auxv. */ + + extern const ElfW(Ehdr) __ehdr_start attribute_hidden; + assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); + _dl_phdr = (const void *) &__ehdr_start + __ehdr_start.e_phoff; + _dl_phnum = __ehdr_start.e_phnum; + } + + assert (_dl_phdr != NULL); } #endif @@ -323,20 +342,19 @@ _dl_non_dynamic_init (void) if (_dl_platform != NULL) _dl_platformlen = strlen (_dl_platform); - if (_dl_phdr != NULL) - for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph) - switch (ph->p_type) - { - /* Check if the stack is nonexecutable. */ - case PT_GNU_STACK: - _dl_stack_flags = ph->p_flags; - break; - - case PT_GNU_RELRO: - _dl_main_map.l_relro_addr = ph->p_vaddr; - _dl_main_map.l_relro_size = ph->p_memsz; - break; - } + for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph) + switch (ph->p_type) + { + /* Check if the stack is nonexecutable. */ + case PT_GNU_STACK: + _dl_stack_flags = ph->p_flags; + break; + + case PT_GNU_RELRO: + _dl_main_map.l_relro_addr = ph->p_vaddr; + _dl_main_map.l_relro_size = ph->p_memsz; + break; + } call_function_static_weak (_dl_find_object_init); -- cgit 1.4.1 From faf065fc4c85a6cd8a1efa561b526a416f087e13 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 26 Jan 2023 14:25:05 +0100 Subject: Use 64-bit time_t interfaces in strftime and strptime (bug 30053) Both functions use time_t only internally, so the ABI is not affected. (cherry picked from commit 41349f6f67c83e7bafe49f985b56493d2c4c9c77) --- NEWS | 1 + time/Makefile | 3 ++- time/strftime_l.c | 4 ++++ time/strptime_l.c | 4 +++- time/tst-strftime4-time64.c | 1 + time/tst-strftime4.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 time/tst-strftime4-time64.c create mode 100644 time/tst-strftime4.c diff --git a/NEWS b/NEWS index c5e142eb3a..aff6951c1d 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,7 @@ The following bugs are resolved with this release: [29771] Restore IPC_64 support in sysvipc *ctl functions [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 [29951] time: Set daylight to 1 for matching DST/offset change + [30053] time: strftime %s returns -1 after 2038 on 32 bits systems Version 2.36 diff --git a/time/Makefile b/time/Makefile index 470275b90c..2f4aa2d528 100644 --- a/time/Makefile +++ b/time/Makefile @@ -50,7 +50,7 @@ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \ tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \ tst-settimeofday tst-itimer tst-gmtime tst-timegm \ - tst-timespec_get tst-timespec_getres + tst-timespec_get tst-timespec_getres tst-strftime4 tests-time64 := \ tst-adjtime-time64 \ @@ -65,6 +65,7 @@ tests-time64 := \ tst-itimer-time64 \ tst-mktime4-time64 \ tst-settimeofday-time64 \ + tst-strftime4-time64 \ tst-timegm-time64 \ tst-timespec_get-time64 \ tst-timespec_getres-time64 \ diff --git a/time/strftime_l.c b/time/strftime_l.c index 75554fee7c..4d7c4ea828 100644 --- a/time/strftime_l.c +++ b/time/strftime_l.c @@ -159,6 +159,10 @@ extern char *tzname[]; #ifdef _LIBC # define tzname __tzname # define tzset __tzset + +# define time_t __time64_t +# define __gmtime_r(t, tp) __gmtime64_r (t, tp) +# define mktime(tp) __mktime64 (tp) #endif #if !HAVE_TM_GMTOFF diff --git a/time/strptime_l.c b/time/strptime_l.c index a3c5681fc2..f927448204 100644 --- a/time/strptime_l.c +++ b/time/strptime_l.c @@ -30,8 +30,10 @@ #ifdef _LIBC # define HAVE_LOCALTIME_R 0 # include "../locale/localeinfo.h" -#endif +# define time_t __time64_t +# define __localtime_r(t, tp) __localtime64_r (t, tp) +#endif #if ! HAVE_LOCALTIME_R && ! defined localtime_r # ifdef _LIBC diff --git a/time/tst-strftime4-time64.c b/time/tst-strftime4-time64.c new file mode 100644 index 0000000000..4d47ee7d79 --- /dev/null +++ b/time/tst-strftime4-time64.c @@ -0,0 +1 @@ +#include "tst-strftime4.c" diff --git a/time/tst-strftime4.c b/time/tst-strftime4.c new file mode 100644 index 0000000000..659716d0fa --- /dev/null +++ b/time/tst-strftime4.c @@ -0,0 +1,52 @@ +/* Test strftime and strptime after 2038-01-19 03:14:07 UTC (bug 30053). + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + TEST_VERIFY_EXIT (setenv ("TZ", "UTC0", 1) == 0); + tzset (); + if (sizeof (time_t) > 4) + { + time_t wrap = (time_t) 2147483648LL; + char buf[80]; + struct tm *tm = gmtime (&wrap); + TEST_VERIFY_EXIT (tm != NULL); + TEST_VERIFY_EXIT (strftime (buf, sizeof buf, "%s", tm) > 0); + puts (buf); + TEST_VERIFY (strcmp (buf, "2147483648") == 0); + + struct tm tm2; + char *p = strptime (buf, "%s", &tm2); + TEST_VERIFY_EXIT (p != NULL && *p == '\0'); + time_t t = mktime (&tm2); + printf ("%lld\n", (long long) t); + TEST_VERIFY (t == wrap); + } + else + FAIL_UNSUPPORTED ("32-bit time_t"); + return 0; +} + +#include -- cgit 1.4.1 From 172f72e45e65b254cba52107af840d2eefdaf754 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 8 Feb 2023 18:11:04 +0100 Subject: elf: Smoke-test ldconfig -p against system /etc/ld.so.cache The test is sufficient to detect the ldconfig bug fixed in commit 9fe6f6363886aae6b2b210cae3ed1f5921299083 ("elf: Fix 64 time_t support for installed statically binaries"). Reviewed-by: Carlos O'Donell (cherry picked from commit 9fd63e35371b9939e9153907c6a753e6960b68ad) --- elf/Makefile | 6 ++++ elf/tst-ldconfig-p.sh | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 elf/tst-ldconfig-p.sh diff --git a/elf/Makefile b/elf/Makefile index 72178d33ff..48788fcdb8 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -634,6 +634,7 @@ ifeq ($(run-built-tests),yes) tests-special += \ $(objpfx)noload-mem.out \ $(objpfx)tst-ldconfig-X.out \ + $(objpfx)tst-ldconfig-p.out \ $(objpfx)tst-leaks1-mem.out \ $(objpfx)tst-rtld-help.out \ # tests-special @@ -2403,6 +2404,11 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig '$(run-program-env)' > $@; \ $(evaluate-test) +$(objpfx)tst-ldconfig-p.out : tst-ldconfig-p.sh $(objpfx)ldconfig + $(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' \ + '$(run-program-env)' > $@; \ + $(evaluate-test) + # Test static linking of all the libraries we can possibly link # together. Note that in some configurations this may be less than the # complete list of libraries we build but we try to maxmimize this list. diff --git a/elf/tst-ldconfig-p.sh b/elf/tst-ldconfig-p.sh new file mode 100644 index 0000000000..ec937bf4ec --- /dev/null +++ b/elf/tst-ldconfig-p.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# Test that ldconfig -p prints something useful. +# 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 +# . + +# Check that the newly built ldconfig -p can dump the system +# /etc/ld.so.cache file. This should always work even if the ABIs are +# not compatible, except in a cross-endian build (that presumably +# involves emulation when running ldconfig). + +common_objpfx=$1 +test_wrapper_env=$2 +run_program_env=$3 + +if ! test -r /etc/ld.so.cache; then + echo "warning: /etc/ld.so.cache does not exist, test skipped" + exit 77 +fi + +testout="${common_objpfx}elf/tst-ldconfig-p.out" +# Truncate file. +: > "$testout" + +${test_wrapper_env} \ +${run_program_env} \ +${common_objpfx}elf/ldconfig -p \ + $testroot/lib >>"$testout" 2>>"$testout" +status=$? +echo "info: ldconfig exit status: $status" >>"$testout" + +errors=0 +case $status in + (0) + if head -n 1 "$testout" | \ + grep -q "libs found in cache \`/etc/ld.so.cache'\$" ; then + echo "info: initial string found" >>"$testout" + else + echo "error: initial string not found" >>"$testout" + errors=1 + fi + if grep -q "^ libc\.so\..* => " "$testout"; then + echo "info: libc.so.* string found" >>"$testout" + else + echo "error: libc.so.* string not found" >>"$testout" + errors=1 + fi + ;; + (1) + if head -n 1 "$testout" | \ + grep -q ": Cache file has wrong endianness\.$" ; then + echo "info: cache file has wrong endianess" >> "$testout" + else + echo "error: unexpected ldconfig error message" >> "$testout" + errors=1 + fi + ;; + (*) + echo "error: unexpected exit status" >> "$testout" + errors=1 + ;; +esac + +exit $errors -- cgit 1.4.1 From fb1bd9f00337db9120e61d5a511766b68ea03e28 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 18 Feb 2023 12:53:41 -0800 Subject: stdlib: Undo post review change to 16adc58e73f3 [BZ #27749] Post review removal of "goto restart" from https://sourceware.org/pipermail/libc-alpha/2021-April/125470.html introduced a bug when some atexit handers skipped. Signed-off-by: Vitaly Buka Reviewed-by: Adhemerval Zanella (cherry picked from commit fd78cfa72ea2bab30fdb4e1e0672b34471426c05) --- stdlib/Makefile | 1 + stdlib/exit.c | 7 ++-- stdlib/test-atexit-recursive.c | 75 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 stdlib/test-atexit-recursive.c diff --git a/stdlib/Makefile b/stdlib/Makefile index f7b25c1981..3d49c4941a 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -171,6 +171,7 @@ tests := \ test-a64l \ test-at_quick_exit-race \ test-atexit-race \ + test-atexit-recursive \ test-bz22786 \ test-canon \ test-canon2 \ diff --git a/stdlib/exit.c b/stdlib/exit.c index bc46109f3e..dc12e212bc 100644 --- a/stdlib/exit.c +++ b/stdlib/exit.c @@ -53,7 +53,10 @@ __run_exit_handlers (int status, struct exit_function_list **listp, exit (). */ while (true) { - struct exit_function_list *cur = *listp; + struct exit_function_list *cur; + + restart: + cur = *listp; if (cur == NULL) { @@ -118,7 +121,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp, if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called)) /* The last exit function, or another thread, has registered more exit functions. Start the loop over. */ - continue; + goto restart; } *listp = cur->next; diff --git a/stdlib/test-atexit-recursive.c b/stdlib/test-atexit-recursive.c new file mode 100644 index 0000000000..0596b9763b --- /dev/null +++ b/stdlib/test-atexit-recursive.c @@ -0,0 +1,75 @@ +/* Support file for atexit/exit, etc. race tests (BZ #27749). + 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 + . */ + +/* Check that atexit handler registed from another handler still called. */ + +#include +#include +#include +#include +#include +#include + +static void +atexit_cb (void) +{ +} + +static void +atexit_last (void) +{ + _exit (1); +} + +static void +atexit_recursive (void) +{ + atexit (&atexit_cb); + atexit (&atexit_last); +} + +_Noreturn static void +test_and_exit (int count) +{ + for (int i = 0; i < count; ++i) + atexit (&atexit_cb); + atexit (&atexit_recursive); + exit (0); +} + +static int +do_test (void) +{ + for (int i = 0; i < 100; ++i) + if (xfork () == 0) + test_and_exit (i); + + for (int i = 0; i < 100; ++i) + { + int status; + xwaitpid (0, &status, 0); + if (!WIFEXITED (status)) + FAIL_EXIT1 ("Failed iterations %d", i); + TEST_COMPARE (WEXITSTATUS (status), 1); + } + + return 0; +} + +#define TEST_FUNCTION do_test +#include -- cgit 1.4.1 From f3991fec8071dbcf3ec9f13a91c738b66fcd4159 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Tue, 3 Jan 2023 13:06:48 -0800 Subject: x86: Check minimum/maximum of non_temporal_threshold [BZ #29953] The minimum non_temporal_threshold is 0x4040. non_temporal_threshold may be set to less than the minimum value when the shared cache size isn't available (e.g., in an emulator) or by the tunable. Add checks for minimum and maximum of non_temporal_threshold. This fixes BZ #29953. (cherry picked from commit 48b74865c63840b288bd85b4d8743533b73b339b) --- sysdeps/x86/dl-cacheinfo.h | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h index e9f3382108..637b5a022d 100644 --- a/sysdeps/x86/dl-cacheinfo.h +++ b/sysdeps/x86/dl-cacheinfo.h @@ -861,6 +861,18 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) share of the cache, it has a substantial risk of negatively impacting the performance of other threads running on the chip. */ unsigned long int non_temporal_threshold = shared * 3 / 4; + /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of + 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best + if that operation cannot overflow. Minimum of 0x4040 (16448) because the + L(large_memset_4x) loops need 64-byte to cache align and enough space for + at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are + reflected in the manual. */ + unsigned long int maximum_non_temporal_threshold = SIZE_MAX >> 4; + unsigned long int minimum_non_temporal_threshold = 0x4040; + if (non_temporal_threshold < minimum_non_temporal_threshold) + non_temporal_threshold = minimum_non_temporal_threshold; + else if (non_temporal_threshold > maximum_non_temporal_threshold) + non_temporal_threshold = maximum_non_temporal_threshold; #if HAVE_TUNABLES /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ @@ -915,8 +927,8 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) shared = tunable_size; tunable_size = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL); - /* NB: Ignore the default value 0. */ - if (tunable_size != 0) + if (tunable_size > minimum_non_temporal_threshold + && tunable_size <= maximum_non_temporal_threshold) non_temporal_threshold = tunable_size; tunable_size = TUNABLE_GET (x86_rep_movsb_threshold, long int, NULL); @@ -931,14 +943,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX); TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX); - /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of - 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best - if that operation cannot overflow. Minimum of 0x4040 (16448) because the - L(large_memset_4x) loops need 64-byte to cache align and enough space for - at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are - reflected in the manual. */ TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, non_temporal_threshold, - 0x4040, SIZE_MAX >> 4); + minimum_non_temporal_threshold, + maximum_non_temporal_threshold); TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, rep_movsb_threshold, minimum_rep_movsb_threshold, SIZE_MAX); TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1, -- cgit 1.4.1 From 6d42a86ad3861d6ec67058eb32f5150e7b734951 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 21 Feb 2023 09:20:28 +0100 Subject: gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling (bug 30151) Before this change, sgetsgent_r did not set errno to ERANGE, but sgetsgent only check errno, not the return value from sgetsgent_r. Consequently, sgetsgent did not detect any error, and reported success to the caller, without initializing the struct sgrp object whose address was returned. This commit changes sgetsgent_r to set errno as well. This avoids similar issues in applications which only change errno. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 969e9733c7d17edf1e239a73fa172f357561f440) --- NEWS | 1 + gshadow/Makefile | 2 +- gshadow/sgetsgent_r.c | 5 +++- gshadow/tst-sgetsgent.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 gshadow/tst-sgetsgent.c diff --git a/NEWS b/NEWS index aff6951c1d..bbe611c500 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,7 @@ The following bugs are resolved with this release: [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 [29951] time: Set daylight to 1 for matching DST/offset change [30053] time: strftime %s returns -1 after 2038 on 32 bits systems + [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling Version 2.36 diff --git a/gshadow/Makefile b/gshadow/Makefile index eff303f538..5b3fa7e387 100644 --- a/gshadow/Makefile +++ b/gshadow/Makefile @@ -26,7 +26,7 @@ headers = gshadow.h routines = getsgent getsgnam sgetsgent fgetsgent putsgent \ getsgent_r getsgnam_r sgetsgent_r fgetsgent_r -tests = tst-gshadow tst-putsgent tst-fgetsgent_r +tests = tst-gshadow tst-putsgent tst-fgetsgent_r tst-sgetsgent CFLAGS-getsgent_r.c += -fexceptions CFLAGS-getsgent.c += -fexceptions diff --git a/gshadow/sgetsgent_r.c b/gshadow/sgetsgent_r.c index 28c826c9b5..a767a643d4 100644 --- a/gshadow/sgetsgent_r.c +++ b/gshadow/sgetsgent_r.c @@ -61,7 +61,10 @@ __sgetsgent_r (const char *string, struct sgrp *resbuf, char *buffer, buffer[buflen - 1] = '\0'; sp = strncpy (buffer, string, buflen); if (buffer[buflen - 1] != '\0') - return ERANGE; + { + __set_errno (ERANGE); + return ERANGE; + } } else sp = (char *) string; diff --git a/gshadow/tst-sgetsgent.c b/gshadow/tst-sgetsgent.c new file mode 100644 index 0000000000..0370c10fd0 --- /dev/null +++ b/gshadow/tst-sgetsgent.c @@ -0,0 +1,69 @@ +/* Test large input for sgetsgent (bug 30151). + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + /* Create a shadow group with 1000 members. */ + struct xmemstream mem; + xopen_memstream (&mem); + const char *passwd = "k+zD0nucwfxAo3sw1NXUj6K5vt5M16+X0TVGdE1uFvq5R8V7efJ"; + fprintf (mem.out, "group-name:%s::m0", passwd); + for (int i = 1; i < 1000; ++i) + fprintf (mem.out, ",m%d", i); + xfclose_memstream (&mem); + + /* Call sgetsgent. */ + char *input = mem.buffer; + struct sgrp *e = sgetsgent (input); + TEST_VERIFY_EXIT (e != NULL); + TEST_COMPARE_STRING (e->sg_namp, "group-name"); + TEST_COMPARE_STRING (e->sg_passwd, passwd); + /* No administrators. */ + TEST_COMPARE_STRING (e->sg_adm[0], NULL); + /* Check the members list. */ + for (int i = 0; i < 1000; ++i) + { + char *member = xasprintf ("m%d", i); + TEST_COMPARE_STRING (e->sg_mem[i], member); + free (member); + } + TEST_COMPARE_STRING (e->sg_mem[1000], NULL); + + /* Check that putsgent brings back the input string. */ + xopen_memstream (&mem); + TEST_COMPARE (putsgent (e, mem.out), 0); + xfclose_memstream (&mem); + /* Compare without the trailing '\n' that putsgent added. */ + TEST_COMPARE (mem.buffer[mem.length - 1], '\n'); + mem.buffer[mem.length - 1] = '\0'; + TEST_COMPARE_STRING (mem.buffer, input); + + free (mem.buffer); + free (input); + return 0; +} + +#include -- cgit 1.4.1 From 95c5bddc9fbfda12220124dbf13750f97bae4e1d Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 3 Apr 2023 17:23:11 +0200 Subject: x86_64: Fix asm constraints in feraiseexcept (bug 30305) The divss instruction clobbers its first argument, and the constraints need to reflect that. Fortunately, with GCC 12, generated code does not actually change, so there is no externally visible bug. Suggested-by: Jakub Jelinek Reviewed-by: Noah Goldstein (cherry picked from commit 5d1ccdda7b0c625751661d50977f3dfbc73f8eae) --- NEWS | 1 + sysdeps/x86_64/fpu/fraiseexcpt.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index bbe611c500..47690c3912 100644 --- a/NEWS +++ b/NEWS @@ -56,6 +56,7 @@ The following bugs are resolved with this release: [29951] time: Set daylight to 1 for matching DST/offset change [30053] time: strftime %s returns -1 after 2038 on 32 bits systems [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling + [30305] x86_64: Fix asm constraints in feraiseexcept Version 2.36 diff --git a/sysdeps/x86_64/fpu/fraiseexcpt.c b/sysdeps/x86_64/fpu/fraiseexcpt.c index 864f4777a2..23446ff4ac 100644 --- a/sysdeps/x86_64/fpu/fraiseexcpt.c +++ b/sysdeps/x86_64/fpu/fraiseexcpt.c @@ -33,7 +33,7 @@ __feraiseexcept (int excepts) /* One example of an invalid operation is 0.0 / 0.0. */ float f = 0.0; - __asm__ __volatile__ ("divss %0, %0 " : : "x" (f)); + __asm__ __volatile__ ("divss %0, %0 " : "+x" (f)); (void) &f; } @@ -43,7 +43,7 @@ __feraiseexcept (int excepts) float f = 1.0; float g = 0.0; - __asm__ __volatile__ ("divss %1, %0" : : "x" (f), "x" (g)); + __asm__ __volatile__ ("divss %1, %0" : "+x" (f) : "x" (g)); (void) &f; } -- cgit 1.4.1 From 48af2676a7c56ecc2511ce48a7550edbc48ff1d4 Mon Sep 17 00:00:00 2001 From: Adam Yi Date: Tue, 7 Mar 2023 07:30:02 -0500 Subject: posix: Fix system blocks SIGCHLD erroneously [BZ #30163] Fix bug that SIGCHLD is erroneously blocked forever in the following scenario: 1. Thread A calls system but hasn't returned yet 2. Thread B calls another system but returns SIGCHLD would be blocked forever in thread B after its system() returns, even after the system() in thread A returns. Although POSIX does not require, glibc system implementation aims to be thread and cancellation safe. This bug was introduced in 5fb7fc96350575c9adb1316833e48ca11553be49 when we moved reverting signal mask to happen when the last concurrently running system returns, despite that signal mask is per thread. This commit reverts this logic and adds a test. Signed-off-by: Adam Yi Reviewed-by: Adhemerval Zanella (cherry picked from commit 436a604b7dc741fc76b5a6704c6cd8bb178518e7) --- NEWS | 1 + stdlib/tst-system.c | 26 +++++++++++++++++++++++ support/Makefile | 2 ++ support/dtotimespec-time64.c | 27 ++++++++++++++++++++++++ support/dtotimespec.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ support/shell-container.c | 28 +++++++++++++++++++++++++ support/timespec.h | 4 ++++ sysdeps/posix/system.c | 6 +++--- 8 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 support/dtotimespec-time64.c create mode 100644 support/dtotimespec.c diff --git a/NEWS b/NEWS index 47690c3912..f3c2249098 100644 --- a/NEWS +++ b/NEWS @@ -56,6 +56,7 @@ The following bugs are resolved with this release: [29951] time: Set daylight to 1 for matching DST/offset change [30053] time: strftime %s returns -1 after 2038 on 32 bits systems [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling + [30163] posix: Fix system blocks SIGCHLD erroneously [30305] x86_64: Fix asm constraints in feraiseexcept Version 2.36 diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c index f7fa74b2a6..5e0c79475f 100644 --- a/stdlib/tst-system.c +++ b/stdlib/tst-system.c @@ -25,6 +25,7 @@ #include #include #include +#include #include static char *tmpdir; @@ -71,6 +72,20 @@ call_system (void *closure) } } +static void * +sleep_and_check_sigchld (void *closure) +{ + double *seconds = (double *) closure; + char cmd[namemax]; + sprintf (cmd, "sleep %lf" , *seconds); + TEST_COMPARE (system (cmd), 0); + + sigset_t blocked = {0}; + TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0); + TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0); + return NULL; +} + static int do_test (void) { @@ -154,6 +169,17 @@ do_test (void) xchmod (_PATH_BSHELL, st.st_mode); } + { + pthread_t long_sleep_thread = xpthread_create (NULL, + sleep_and_check_sigchld, + &(double) { 0.2 }); + pthread_t short_sleep_thread = xpthread_create (NULL, + sleep_and_check_sigchld, + &(double) { 0.1 }); + xpthread_join (short_sleep_thread); + xpthread_join (long_sleep_thread); + } + TEST_COMPARE (system (""), 0); return 0; diff --git a/support/Makefile b/support/Makefile index 9b50eac117..2b661a7eb8 100644 --- a/support/Makefile +++ b/support/Makefile @@ -32,6 +32,8 @@ libsupport-routines = \ check_hostent \ check_netent \ delayed_exit \ + dtotimespec \ + dtotimespec-time64 \ ignore_stderr \ next_to_fault \ oom_error \ diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c new file mode 100644 index 0000000000..b3d5e351e3 --- /dev/null +++ b/support/dtotimespec-time64.c @@ -0,0 +1,27 @@ +/* Convert double to timespec. 64-bit time support. + Copyright (C) 2011-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library and is also part of gnulib. + Patches to this file should be submitted to both projects. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#if __TIMESIZE != 64 +# define timespec __timespec64 +# define time_t __time64_t +# define dtotimespec dtotimespec_time64 +# include "dtotimespec.c" +#endif diff --git a/support/dtotimespec.c b/support/dtotimespec.c new file mode 100644 index 0000000000..cde5b4d74c --- /dev/null +++ b/support/dtotimespec.c @@ -0,0 +1,50 @@ +/* Convert double to timespec. + Copyright (C) 2011-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library and is also part of gnulib. + Patches to this file should be submitted to both projects. + + 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 + . */ + +/* Convert the double value SEC to a struct timespec. Round toward + positive infinity. On overflow, return an extremal value. */ + +#include +#include + +struct timespec +dtotimespec (double sec) +{ + if (sec <= TYPE_MINIMUM (time_t)) + return make_timespec (TYPE_MINIMUM (time_t), 0); + else if (sec >= 1.0 + TYPE_MAXIMUM (time_t)) + return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1); + else + { + time_t s = sec; + double frac = TIMESPEC_HZ * (sec - s); + long ns = frac; + ns += ns < frac; + s += ns / TIMESPEC_HZ; + ns %= TIMESPEC_HZ; + + if (ns < 0) + { + s--; + ns += TIMESPEC_HZ; + } + + return make_timespec (s, ns); + } +} diff --git a/support/shell-container.c b/support/shell-container.c index 1c73666f0a..6698061b9b 100644 --- a/support/shell-container.c +++ b/support/shell-container.c @@ -39,6 +39,7 @@ #include #include +#include /* Design considerations @@ -171,6 +172,32 @@ kill_func (char **argv) return 0; } +/* Emulate the "/bin/sleep" command. No suffix support. Options are + ignored. */ +static int +sleep_func (char **argv) +{ + if (argv[0] == NULL) + { + fprintf (stderr, "sleep: missing operand\n"); + return 1; + } + char *endptr = NULL; + double sec = strtod (argv[0], &endptr); + if (endptr == argv[0] || errno == ERANGE || sec < 0) + { + fprintf (stderr, "sleep: invalid time interval '%s'\n", argv[0]); + return 1; + } + struct timespec ts = dtotimespec (sec); + if (nanosleep (&ts, NULL) < 0) + { + fprintf (stderr, "sleep: failed to nanosleep: %s\n", strerror (errno)); + return 1; + } + return 0; +} + /* This is a list of all the built-in commands we understand. */ static struct { const char *name; @@ -181,6 +208,7 @@ static struct { { "cp", copy_func }, { "exit", exit_func }, { "kill", kill_func }, + { "sleep", sleep_func }, { NULL, NULL } }; diff --git a/support/timespec.h b/support/timespec.h index 4d2ac2737d..1bba3a6837 100644 --- a/support/timespec.h +++ b/support/timespec.h @@ -57,6 +57,8 @@ int support_timespec_check_in_range (struct timespec expected, struct timespec observed, double lower_bound, double upper_bound); +struct timespec dtotimespec (double sec) __attribute__((const)); + #else struct timespec __REDIRECT (timespec_add, (struct timespec, struct timespec), timespec_add_time64); @@ -82,6 +84,8 @@ int __REDIRECT (support_timespec_check_in_range, (struct timespec expected, double lower_bound, double upper_bound), support_timespec_check_in_range_time64); + +struct timespec __REDIRECT (dtotimespec, (double sec), dtotimespec_time64); #endif /* Check that the timespec on the left represents a time before the diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c index 8014f63355..20c9420dd4 100644 --- a/sysdeps/posix/system.c +++ b/sysdeps/posix/system.c @@ -179,16 +179,16 @@ do_system (const char *line) as if the shell had terminated using _exit(127). */ status = W_EXITCODE (127, 0); + /* sigaction can not fail with SIGINT/SIGQUIT used with old + disposition. Same applies for sigprocmask. */ DO_LOCK (); if (SUB_REF () == 0) { - /* sigaction can not fail with SIGINT/SIGQUIT used with old - disposition. Same applies for sigprocmask. */ __sigaction (SIGINT, &intr, NULL); __sigaction (SIGQUIT, &quit, NULL); - __sigprocmask (SIG_SETMASK, &omask, NULL); } DO_UNLOCK (); + __sigprocmask (SIG_SETMASK, &omask, NULL); if (ret != 0) __set_errno (ret); -- cgit 1.4.1 From 33909e5abc8ad24c52d48bd005e102b6b56537c4 Mon Sep 17 00:00:00 2001 From: "Леонид Юрьев (Leonid Yuriev)" Date: Sat, 4 Feb 2023 14:41:38 +0300 Subject: gmon: Fix allocated buffer overflow (bug 29444) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `__monstartup()` allocates a buffer used to store all the data accumulated by the monitor. The size of this buffer depends on the size of the internal structures used and the address range for which the monitor is activated, as well as on the maximum density of call instructions and/or callable functions that could be potentially on a segment of executable code. In particular a hash table of arcs is placed at the end of this buffer. The size of this hash table is calculated in bytes as p->fromssize = p->textsize / HASHFRACTION; but actually should be p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); This results in writing beyond the end of the allocated buffer when an added arc corresponds to a call near from the end of the monitored address range, since `_mcount()` check the incoming caller address for monitored range but not the intermediate result hash-like index that uses to write into the table. It should be noted that when the results are output to `gmon.out`, the table is read to the last element calculated from the allocated size in bytes, so the arcs stored outside the buffer boundary did not fall into `gprof` for analysis. Thus this "feature" help me to found this bug during working with https://sourceware.org/bugzilla/show_bug.cgi?id=29438 Just in case, I will explicitly note that the problem breaks the `make test t=gmon/tst-gmon-dso` added for Bug 29438. There, the arc of the `f3()` call disappears from the output, since in the DSO case, the call to `f3` is located close to the end of the monitored range. Signed-off-by: Леонид Юрьев (Leonid Yuriev) Another minor error seems a related typo in the calculation of `kcountsize`, but since kcounts are smaller than froms, this is actually to align the p->froms data. Co-authored-by: DJ Delorie Reviewed-by: Carlos O'Donell (cherry picked from commit 801af9fafd4689337ebf27260aa115335a0cb2bc) --- NEWS | 1 + gmon/gmon.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index f3c2249098..52b0ba91d5 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,7 @@ The following bugs are resolved with this release: [12154] Do not fail DNS resolution for CNAMEs which are not host names [24816] Fix tst-nss-files-hosts-long on single-stack hosts [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning + [29444] gmon: Fix allocated buffer overflow (bug 29444) [29864] libc: __libc_start_main() should obtain program headers address (_dl_phdr) from the auxv, not the ELF header. [29305] Conserve NSS buffer space during DNS packet parsing diff --git a/gmon/gmon.c b/gmon/gmon.c index dee64803ad..bf76358d5b 100644 --- a/gmon/gmon.c +++ b/gmon/gmon.c @@ -132,6 +132,8 @@ __monstartup (u_long lowpc, u_long highpc) p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); p->textsize = p->highpc - p->lowpc; + /* This looks like a typo, but it's here to align the p->froms + section. */ p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms)); p->hashfraction = HASHFRACTION; p->log_hashfraction = -1; @@ -142,7 +144,7 @@ __monstartup (u_long lowpc, u_long highpc) instead of integer division. Precompute shift amount. */ p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1; } - p->fromssize = p->textsize / HASHFRACTION; + p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); p->tolimit = p->textsize * ARCDENSITY / 100; if (p->tolimit < MINARCS) p->tolimit = MINARCS; -- cgit 1.4.1 From 8920855c4568fa99c67cb1c7d6b29465c25f51c2 Mon Sep 17 00:00:00 2001 From: Simon Kissane Date: Sat, 11 Feb 2023 20:12:13 +1100 Subject: gmon: improve mcount overflow handling [BZ# 27576] When mcount overflows, no gmon.out file is generated, but no message is printed to the user, leaving the user with no idea why, and thinking maybe there is some bug - which is how BZ 27576 ended up being logged. Print a message to stderr in this case so the user knows what is going on. As a comment in sys/gmon.h acknowledges, the hardcoded MAXARCS value is too small for some large applications, including the test case in that BZ. Rather than increase it, add tunables to enable MINARCS and MAXARCS to be overridden at runtime (glibc.gmon.minarcs and glibc.gmon.maxarcs). So if a user gets the mcount overflow error, they can try increasing maxarcs (they might need to increase minarcs too if the heuristic is wrong in their case.) Note setting minarcs/maxarcs too large can cause monstartup to fail with an out of memory error. If you set them large enough, it can cause an integer overflow in calculating the buffer size. I haven't done anything to defend against that - it would not generally be a security vulnerability, since these tunables will be ignored in suid/sgid programs (due to the SXID_ERASE default), and if you can set GLIBC_TUNABLES in the environment of a process, you can take it over anyway (LD_PRELOAD, LD_LIBRARY_PATH, etc). I thought about modifying the code of monstartup to defend against integer overflows, but doing so is complicated, and I realise the existing code is susceptible to them even prior to this change (e.g. try passing a pathologically large highpc argument to monstartup), so I decided just to leave that possibility in-place. Add a test case which demonstrates mcount overflow and the tunables. Document the new tunables in the manual. Signed-off-by: Simon Kissane Reviewed-by: DJ Delorie (cherry picked from commit 31be941e4367c001b2009308839db5c67bf9dcbc) --- NEWS | 1 + elf/dl-tunables.list | 13 +++++++ gmon/Makefile | 22 +++++++++++- gmon/gmon.c | 29 +++++++++++++--- gmon/mcount.c | 5 +++ gmon/sys/gmon.h | 6 ++-- gmon/tst-mcount-overflow-check.sh | 45 ++++++++++++++++++++++++ gmon/tst-mcount-overflow.c | 72 +++++++++++++++++++++++++++++++++++++++ manual/tunables.texi | 59 ++++++++++++++++++++++++++++++++ 9 files changed, 245 insertions(+), 7 deletions(-) create mode 100644 gmon/tst-mcount-overflow-check.sh create mode 100644 gmon/tst-mcount-overflow.c diff --git a/NEWS b/NEWS index 52b0ba91d5..850f9f7802 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,7 @@ The following bugs are resolved with this release: [12154] Do not fail DNS resolution for CNAMEs which are not host names [24816] Fix tst-nss-files-hosts-long on single-stack hosts + [27576] gmon: improve mcount overflow handling [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning [29444] gmon: Fix allocated buffer overflow (bug 29444) [29864] libc: __libc_start_main() should obtain program headers diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list index e6a56b3070..9fa3b484cf 100644 --- a/elf/dl-tunables.list +++ b/elf/dl-tunables.list @@ -169,4 +169,17 @@ glibc { default: 2 } } + + gmon { + minarcs { + type: INT_32 + minval: 50 + default: 50 + } + maxarcs { + type: INT_32 + minval: 50 + default: 1048576 + } + } } diff --git a/gmon/Makefile b/gmon/Makefile index 552b7d7751..58ea34aa7e 100644 --- a/gmon/Makefile +++ b/gmon/Makefile @@ -25,7 +25,7 @@ include ../Makeconfig headers := sys/gmon.h sys/gmon_out.h sys/profil.h routines := gmon mcount profil sprofil prof-freq -tests = tst-sprofil tst-gmon +tests = tst-sprofil tst-gmon tst-mcount-overflow ifeq ($(build-profile),yes) tests += tst-profile-static tests-static += tst-profile-static @@ -56,6 +56,18 @@ ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-gmon-gprof.out endif +CFLAGS-tst-mcount-overflow.c := -fno-omit-frame-pointer -pg +tst-mcount-overflow-no-pie = yes +CRT-tst-mcount-overflow := $(csu-objpfx)g$(start-installed-name) +# Intentionally use invalid config where maxarcs&1 1>/dev/null | cat +ifeq ($(run-built-tests),yes) +tests-special += $(objpfx)tst-mcount-overflow-check.out +endif + CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg CRT-tst-gmon-static := $(csu-objpfx)g$(static-start-installed-name) tst-gmon-static-no-pie = yes @@ -103,6 +115,14 @@ $(objpfx)tst-gmon.out: clean-tst-gmon-data clean-tst-gmon-data: rm -f $(objpfx)tst-gmon.data.* +$(objpfx)tst-mcount-overflow.o: clean-tst-mcount-overflow-data +clean-tst-mcount-overflow-data: + rm -f $(objpfx)tst-mcount-overflow.data.* + +$(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)tst-mcount-overflow.out + $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ + $(evaluate-test) + $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ $(evaluate-test) diff --git a/gmon/gmon.c b/gmon/gmon.c index bf76358d5b..689bf80141 100644 --- a/gmon/gmon.c +++ b/gmon/gmon.c @@ -46,6 +46,11 @@ #include #include +#if HAVE_TUNABLES +# define TUNABLE_NAMESPACE gmon +# include +#endif + #ifdef PIC # include @@ -124,6 +129,22 @@ __monstartup (u_long lowpc, u_long highpc) int o; char *cp; struct gmonparam *p = &_gmonparam; + long int minarcs, maxarcs; + +#if HAVE_TUNABLES + /* Read minarcs/maxarcs tunables. */ + minarcs = TUNABLE_GET (minarcs, int32_t, NULL); + maxarcs = TUNABLE_GET (maxarcs, int32_t, NULL); + if (maxarcs < minarcs) + { + ERR("monstartup: maxarcs < minarcs, setting maxarcs = minarcs\n"); + maxarcs = minarcs; + } +#else + /* No tunables, we use hardcoded defaults */ + minarcs = MINARCS; + maxarcs = MAXARCS; +#endif /* * round lowpc and highpc to multiples of the density we're using @@ -146,10 +167,10 @@ __monstartup (u_long lowpc, u_long highpc) } p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); p->tolimit = p->textsize * ARCDENSITY / 100; - if (p->tolimit < MINARCS) - p->tolimit = MINARCS; - else if (p->tolimit > MAXARCS) - p->tolimit = MAXARCS; + if (p->tolimit < minarcs) + p->tolimit = minarcs; + else if (p->tolimit > maxarcs) + p->tolimit = maxarcs; p->tossize = p->tolimit * sizeof(struct tostruct); cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1); diff --git a/gmon/mcount.c b/gmon/mcount.c index 9d4a1a50fa..f7180fdb83 100644 --- a/gmon/mcount.c +++ b/gmon/mcount.c @@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; #include +#include +#include +#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1) + /* * mcount is called on entry to each function compiled with the profiling * switch set. _mcount(), which is declared in a machine-dependent way @@ -170,6 +174,7 @@ done: return; overflow: p->state = GMON_PROF_ERROR; + ERR("mcount: call graph buffer size limit exceeded, gmon.out will not be generated\n"); return; } diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h index b4cc3b043a..af0582a371 100644 --- a/gmon/sys/gmon.h +++ b/gmon/sys/gmon.h @@ -111,6 +111,8 @@ extern struct __bb *__bb_head; * Always allocate at least this many tostructs. This * hides the inadequacy of the ARCDENSITY heuristic, at least * for small programs. + * + * Value can be overridden at runtime by glibc.gmon.minarcs tunable. */ #define MINARCS 50 @@ -124,8 +126,8 @@ extern struct __bb *__bb_head; * Used to be max representable value of ARCINDEX minus 2, but now * that ARCINDEX is a long, that's too large; we don't really want * to allow a 48 gigabyte table. - * The old value of 1<<16 wasn't high enough in practice for large C++ - * programs; will 1<<20 be adequate for long? FIXME + * + * Value can be overridden at runtime by glibc.gmon.maxarcs tunable. */ #define MAXARCS (1 << 20) diff --git a/gmon/tst-mcount-overflow-check.sh b/gmon/tst-mcount-overflow-check.sh new file mode 100644 index 0000000000..27eb5538fd --- /dev/null +++ b/gmon/tst-mcount-overflow-check.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Test expected messages generated when mcount overflows +# Copyright (C) 2017-2023 Free Software Foundation, Inc. +# 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 +# . + +LC_ALL=C +export LC_ALL +set -e +exec 2>&1 + +program="$1" + +check_msg() { + if ! grep -q "$1" "$program.out"; then + echo "FAIL: expected message not in output: $1" + exit 1 + fi +} + +check_msg 'monstartup: maxarcs < minarcs, setting maxarcs = minarcs' +check_msg 'mcount: call graph buffer size limit exceeded, gmon.out will not be generated' + +for data_file in $1.data.*; do + if [ -f "$data_file" ]; then + echo "FAIL: expected no data files, but found $data_file" + exit 1 + fi +done + +echo PASS diff --git a/gmon/tst-mcount-overflow.c b/gmon/tst-mcount-overflow.c new file mode 100644 index 0000000000..06cc93ef87 --- /dev/null +++ b/gmon/tst-mcount-overflow.c @@ -0,0 +1,72 @@ +/* Test program to trigger mcount overflow in profiling collection. + 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 + . */ + +/* Program with sufficiently complex, yet pointless, call graph + that it will trigger an mcount overflow, when you set the + minarcs/maxarcs tunables to very low values. */ + +#define PREVENT_TAIL_CALL asm volatile ("") + +/* Calls REP(n) macro 16 times, for n=0..15. + * You need to define REP(n) before using this. + */ +#define REPS \ + REP(0) REP(1) REP(2) REP(3) REP(4) REP(5) REP(6) REP(7) \ + REP(8) REP(9) REP(10) REP(11) REP(12) REP(13) REP(14) REP(15) + +/* Defines 16 leaf functions named f1_0 to f1_15 */ +#define REP(n) \ + __attribute__ ((noinline, noclone, weak)) void f1_##n (void) {}; +REPS +#undef REP + +/* Calls all 16 leaf functions f1_* in succession */ +__attribute__ ((noinline, noclone, weak)) void +f2 (void) +{ +# define REP(n) f1_##n(); + REPS +# undef REP + PREVENT_TAIL_CALL; +} + +/* Defines 16 functions named f2_0 to f2_15, which all just call f2 */ +#define REP(n) \ + __attribute__ ((noinline, noclone, weak)) void \ + f2_##n (void) { f2(); PREVENT_TAIL_CALL; }; +REPS +#undef REP + +__attribute__ ((noinline, noclone, weak)) void +f3 (int count) +{ + for (int i = 0; i < count; ++i) + { + /* Calls f1_0(), f2_0(), f1_1(), f2_1(), f3_0(), etc */ +# define REP(n) f1_##n(); f2_##n(); + REPS +# undef REP + } +} + +int +main (void) +{ + f3 (1000); + return 0; +} diff --git a/manual/tunables.texi b/manual/tunables.texi index 83cdcdac6d..8bb2f29ea5 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -77,6 +77,9 @@ glibc.malloc.check: 0 (min: 0, max: 3) capabilities seen by @theglibc{} * Memory Related Tunables:: Tunables that control the use of memory by @theglibc{}. +* gmon Tunables:: Tunables that control the gmon profiler, used in + conjunction with gprof + @end menu @node Tunable names @@ -612,3 +615,59 @@ support in the kernel if this tunable has any non-zero value. The default value is @samp{0}, which disables all memory tagging. @end deftp + +@node gmon Tunables +@section gmon Tunables +@cindex gmon tunables + +@deftp {Tunable namespace} glibc.gmon +This tunable namespace affects the behaviour of the gmon profiler. +gmon is a component of @theglibc{} which is normally used in +conjunction with gprof. + +When GCC compiles a program with the @code{-pg} option, it instruments +the program with calls to the @code{mcount} function, to record the +program's call graph. At program startup, a memory buffer is allocated +to store this call graph; the size of the buffer is calculated using a +heuristic based on code size. If during execution, the buffer is found +to be too small, profiling will be aborted and no @file{gmon.out} file +will be produced. In that case, you will see the following message +printed to standard error: + +@example +mcount: call graph buffer size limit exceeded, gmon.out will not be generated +@end example + +Most of the symbols discussed in this section are defined in the header +@code{sys/gmon.h}. However, some symbols (for example @code{mcount}) +are not defined in any header file, since they are only intended to be +called from code generated by the compiler. +@end deftp + +@deftp Tunable glibc.mem.minarcs +The heuristic for sizing the call graph buffer is known to be +insufficient for small programs; hence, the calculated value is clamped +to be at least a minimum size. The default minimum (in units of +call graph entries, @code{struct tostruct}), is given by the macro +@code{MINARCS}. If you have some program with an unusually complex +call graph, for which the heuristic fails to allocate enough space, +you can use this tunable to increase the minimum to a larger value. +@end deftp + +@deftp Tunable glibc.mem.maxarcs +To prevent excessive memory consumption when profiling very large +programs, the call graph buffer is allowed to have a maximum of +@code{MAXARCS} entries. For some very large programs, the default +value of @code{MAXARCS} defined in @file{sys/gmon.h} is too small; in +that case, you can use this tunable to increase it. + +Note the value of the @code{maxarcs} tunable must be greater or equal +to that of the @code{minarcs} tunable; if this constraint is violated, +a warning will printed to standard error at program startup, and +the @code{minarcs} value will be used as the maximum as well. + +Setting either tunable too high may result in a call graph buffer +whose size exceeds the available memory; in that case, an out of memory +error will be printed at program startup, the profiler will be +disabled, and no @file{gmon.out} file will be generated. +@end deftp -- cgit 1.4.1 From 3c98431da5d628074882e37287667c7e99560996 Mon Sep 17 00:00:00 2001 From: Simon Kissane Date: Sat, 11 Feb 2023 08:58:02 +1100 Subject: gmon: fix memory corruption issues [BZ# 30101] V2 of this patch fixes an issue in V1, where the state was changed to ON not OFF at end of _mcleanup. I hadn't noticed that (counterintuitively) ON=0 and OFF=3, hence zeroing the buffer turned it back on. So set the state to OFF after the memset. 1. Prevent double free, and reads from unallocated memory, when _mcleanup is (incorrectly) called two or more times in a row, without an intervening call to __monstartup; with this patch, the second and subsequent calls effectively become no-ops instead. While setting tos=NULL is minimal fix, safest action is to zero the whole gmonparam buffer. 2. Prevent memory leak when __monstartup is (incorrectly) called two or more times in a row, without an intervening call to _mcleanup; with this patch, the second and subsequent calls effectively become no-ops instead. 3. After _mcleanup, treat __moncontrol(1) as __moncontrol(0) instead. With zeroing of gmonparam buffer in _mcleanup, this stops the state incorrectly being changed to GMON_PROF_ON despite profiling actually being off. If we'd just done the minimal fix to _mcleanup of setting tos=NULL, there is risk of far worse memory corruption: kcount would point to deallocated memory, and the __profil syscall would make the kernel write profiling data into that memory, which could have since been reallocated to something unrelated. 4. Ensure __moncontrol(0) still turns off profiling even in error state. Otherwise, if mcount overflows and sets state to GMON_PROF_ERROR, when _mcleanup calls __moncontrol(0), the __profil syscall to disable profiling will not be invoked. _mcleanup will free the buffer, but the kernel will still be writing profiling data into it, potentially corrupted arbitrary memory. Also adds a test case for (1). Issues (2)-(4) are not feasible to test. Signed-off-by: Simon Kissane Reviewed-by: DJ Delorie (cherry picked from commit bde121872001d8f3224eeafa5b7effb871c3fbca) --- NEWS | 1 + gmon/Makefile | 17 +++++++++++++++-- gmon/gmon.c | 26 +++++++++++++++++++------- gmon/tst-mcleanup.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 gmon/tst-mcleanup.c diff --git a/NEWS b/NEWS index 850f9f7802..0b3ee2ad14 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,7 @@ The following bugs are resolved with this release: [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 [29951] time: Set daylight to 1 for matching DST/offset change [30053] time: strftime %s returns -1 after 2038 on 32 bits systems + [30101] gmon: fix memory corruption issues [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling [30163] posix: Fix system blocks SIGCHLD erroneously [30305] x86_64: Fix asm constraints in feraiseexcept diff --git a/gmon/Makefile b/gmon/Makefile index 58ea34aa7e..213622a7ad 100644 --- a/gmon/Makefile +++ b/gmon/Makefile @@ -1,4 +1,5 @@ -# Copyright (C) 1995-2022 Free Software Foundation, Inc. +# Copyright (C) 1995-2023 Free Software Foundation, Inc. +# 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 @@ -25,7 +26,7 @@ include ../Makeconfig headers := sys/gmon.h sys/gmon_out.h sys/profil.h routines := gmon mcount profil sprofil prof-freq -tests = tst-sprofil tst-gmon tst-mcount-overflow +tests = tst-sprofil tst-gmon tst-mcount-overflow tst-mcleanup ifeq ($(build-profile),yes) tests += tst-profile-static tests-static += tst-profile-static @@ -68,6 +69,14 @@ ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-mcount-overflow-check.out endif +CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg +tst-mcleanup-no-pie = yes +CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name) +tst-mcleanup-ENV := GMON_OUT_PREFIX=$(objpfx)tst-mcleanup.data +ifeq ($(run-built-tests),yes) +tests-special += $(objpfx)tst-mcleanup.out +endif + CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg CRT-tst-gmon-static := $(csu-objpfx)g$(static-start-installed-name) tst-gmon-static-no-pie = yes @@ -123,6 +132,10 @@ $(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)ts $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ $(evaluate-test) +$(objpfx)tst-mcleanup.out: clean-tst-mcleanup-data +clean-tst-mcleanup-data: + rm -f $(objpfx)tst-mcleanup.data.* + $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ $(evaluate-test) diff --git a/gmon/gmon.c b/gmon/gmon.c index 689bf80141..5e99a7351d 100644 --- a/gmon/gmon.c +++ b/gmon/gmon.c @@ -102,11 +102,8 @@ __moncontrol (int mode) { struct gmonparam *p = &_gmonparam; - /* Don't change the state if we ran into an error. */ - if (p->state == GMON_PROF_ERROR) - return; - - if (mode) + /* Treat start request as stop if error or gmon not initialized. */ + if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL) { /* start */ __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale); @@ -116,7 +113,9 @@ __moncontrol (int mode) { /* stop */ __profil(NULL, 0, 0, 0); - p->state = GMON_PROF_OFF; + /* Don't change the state if we ran into an error. */ + if (p->state != GMON_PROF_ERROR) + p->state = GMON_PROF_OFF; } } libc_hidden_def (__moncontrol) @@ -146,6 +145,14 @@ __monstartup (u_long lowpc, u_long highpc) maxarcs = MAXARCS; #endif + /* + * If we are incorrectly called twice in a row (without an + * intervening call to _mcleanup), ignore the second call to + * prevent leaking memory. + */ + if (p->tos != NULL) + return; + /* * round lowpc and highpc to multiples of the density we're using * so the rest of the scaling (here and in gprof) stays in ints. @@ -463,9 +470,14 @@ _mcleanup (void) { __moncontrol (0); - if (_gmonparam.state != GMON_PROF_ERROR) + if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL) write_gmon (); /* free the memory. */ free (_gmonparam.tos); + + /* reset buffer to initial state for safety */ + memset(&_gmonparam, 0, sizeof _gmonparam); + /* somewhat confusingly, ON=0, OFF=3 */ + _gmonparam.state = GMON_PROF_OFF; } diff --git a/gmon/tst-mcleanup.c b/gmon/tst-mcleanup.c new file mode 100644 index 0000000000..b259653ec8 --- /dev/null +++ b/gmon/tst-mcleanup.c @@ -0,0 +1,31 @@ +/* Test program for repeated invocation of _mcleanup + 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 + . */ + +/* Intentionally calls _mcleanup() twice: once manually, it will be + called again as an atexit handler. This is incorrect use of the API, + but the point of the test is to make sure we don't crash when the + API is misused in this way. */ + +#include + +int +main (void) +{ + _mcleanup(); + return 0; +} -- cgit 1.4.1 From dee43b346059ca677e6810569e44aa0b9b6dc05e Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 28 Apr 2023 17:07:38 +0200 Subject: gmon: Revert addition of tunables to preserve GLIBC_PRIVATE ABI Otherwise, processes are likely to crash during concurrent updates to a new glibc version on the stable release branch. The test gmon/tst-mcount-overflow depends on those tunables, so it has to be removed as well. --- gmon/Makefile | 14 +------------- gmon/gmon.c | 16 ---------------- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/gmon/Makefile b/gmon/Makefile index 213622a7ad..fbe2b0ba5c 100644 --- a/gmon/Makefile +++ b/gmon/Makefile @@ -26,7 +26,7 @@ include ../Makeconfig headers := sys/gmon.h sys/gmon_out.h sys/profil.h routines := gmon mcount profil sprofil prof-freq -tests = tst-sprofil tst-gmon tst-mcount-overflow tst-mcleanup +tests = tst-sprofil tst-gmon tst-mcleanup ifeq ($(build-profile),yes) tests += tst-profile-static tests-static += tst-profile-static @@ -57,18 +57,6 @@ ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-gmon-gprof.out endif -CFLAGS-tst-mcount-overflow.c := -fno-omit-frame-pointer -pg -tst-mcount-overflow-no-pie = yes -CRT-tst-mcount-overflow := $(csu-objpfx)g$(start-installed-name) -# Intentionally use invalid config where maxarcs&1 1>/dev/null | cat -ifeq ($(run-built-tests),yes) -tests-special += $(objpfx)tst-mcount-overflow-check.out -endif - CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg tst-mcleanup-no-pie = yes CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name) diff --git a/gmon/gmon.c b/gmon/gmon.c index 5e99a7351d..97be1f72ca 100644 --- a/gmon/gmon.c +++ b/gmon/gmon.c @@ -46,11 +46,6 @@ #include #include -#if HAVE_TUNABLES -# define TUNABLE_NAMESPACE gmon -# include -#endif - #ifdef PIC # include @@ -130,20 +125,9 @@ __monstartup (u_long lowpc, u_long highpc) struct gmonparam *p = &_gmonparam; long int minarcs, maxarcs; -#if HAVE_TUNABLES - /* Read minarcs/maxarcs tunables. */ - minarcs = TUNABLE_GET (minarcs, int32_t, NULL); - maxarcs = TUNABLE_GET (maxarcs, int32_t, NULL); - if (maxarcs < minarcs) - { - ERR("monstartup: maxarcs < minarcs, setting maxarcs = minarcs\n"); - maxarcs = minarcs; - } -#else /* No tunables, we use hardcoded defaults */ minarcs = MINARCS; maxarcs = MAXARCS; -#endif /* * If we are incorrectly called twice in a row (without an -- cgit 1.4.1 From b7008a92f505632f32b313d1033d6d15c99a0b31 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 28 Apr 2023 17:55:39 +0200 Subject: gmon: Revert addition of tunables to the manual These tunables had to be removed over GLIBC_PRIVATE ABI stability concerns. --- manual/tunables.texi | 59 ---------------------------------------------------- 1 file changed, 59 deletions(-) diff --git a/manual/tunables.texi b/manual/tunables.texi index 8bb2f29ea5..83cdcdac6d 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -77,9 +77,6 @@ glibc.malloc.check: 0 (min: 0, max: 3) capabilities seen by @theglibc{} * Memory Related Tunables:: Tunables that control the use of memory by @theglibc{}. -* gmon Tunables:: Tunables that control the gmon profiler, used in - conjunction with gprof - @end menu @node Tunable names @@ -615,59 +612,3 @@ support in the kernel if this tunable has any non-zero value. The default value is @samp{0}, which disables all memory tagging. @end deftp - -@node gmon Tunables -@section gmon Tunables -@cindex gmon tunables - -@deftp {Tunable namespace} glibc.gmon -This tunable namespace affects the behaviour of the gmon profiler. -gmon is a component of @theglibc{} which is normally used in -conjunction with gprof. - -When GCC compiles a program with the @code{-pg} option, it instruments -the program with calls to the @code{mcount} function, to record the -program's call graph. At program startup, a memory buffer is allocated -to store this call graph; the size of the buffer is calculated using a -heuristic based on code size. If during execution, the buffer is found -to be too small, profiling will be aborted and no @file{gmon.out} file -will be produced. In that case, you will see the following message -printed to standard error: - -@example -mcount: call graph buffer size limit exceeded, gmon.out will not be generated -@end example - -Most of the symbols discussed in this section are defined in the header -@code{sys/gmon.h}. However, some symbols (for example @code{mcount}) -are not defined in any header file, since they are only intended to be -called from code generated by the compiler. -@end deftp - -@deftp Tunable glibc.mem.minarcs -The heuristic for sizing the call graph buffer is known to be -insufficient for small programs; hence, the calculated value is clamped -to be at least a minimum size. The default minimum (in units of -call graph entries, @code{struct tostruct}), is given by the macro -@code{MINARCS}. If you have some program with an unusually complex -call graph, for which the heuristic fails to allocate enough space, -you can use this tunable to increase the minimum to a larger value. -@end deftp - -@deftp Tunable glibc.mem.maxarcs -To prevent excessive memory consumption when profiling very large -programs, the call graph buffer is allowed to have a maximum of -@code{MAXARCS} entries. For some very large programs, the default -value of @code{MAXARCS} defined in @file{sys/gmon.h} is too small; in -that case, you can use this tunable to increase it. - -Note the value of the @code{maxarcs} tunable must be greater or equal -to that of the @code{minarcs} tunable; if this constraint is violated, -a warning will printed to standard error at program startup, and -the @code{minarcs} value will be used as the maximum as well. - -Setting either tunable too high may result in a call graph buffer -whose size exceeds the available memory; in that case, an out of memory -error will be printed at program startup, the profiler will be -disabled, and no @file{gmon.out} file will be generated. -@end deftp -- cgit 1.4.1 From 7df9a276563e201fd5680c46f0d8c6f719ce1fc9 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 27 Apr 2023 13:06:15 -0700 Subject: __check_pf: Add a cancellation cleanup handler [BZ #20975] There are reports for hang in __check_pf: https://github.com/JoeDog/siege/issues/4 It is reproducible only under specific configurations: 1. Large number of cores (>= 64) and large number of threads (> 3X of the number of cores) with long lived socket connection. 2. Low power (frequency) mode. 3. Power management is enabled. While holding lock, __check_pf calls make_request which calls __sendto and __recvmsg. Since __sendto and __recvmsg are cancellation points, lock held by __check_pf won't be released and can cause deadlock when thread cancellation happens in __sendto or __recvmsg. Add a cancellation cleanup handler for __check_pf to unlock the lock when cancelled by another thread. This fixes BZ #20975 and the siege hang issue. (cherry picked from commit a443bd3fb233186038b8b483959ecb7978d1abea) --- sysdeps/unix/sysv/linux/Makefile | 2 ++ sysdeps/unix/sysv/linux/check_pf.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 3ceda9fdbf..d5d9af4de2 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -362,6 +362,8 @@ sysdep_headers += netinet/if_fddi.h netinet/if_tr.h \ netrom/netrom.h netpacket/packet.h netrose/rose.h \ neteconet/ec.h netiucv/iucv.h sysdep_routines += netlink_assert_response + +CFLAGS-check_pf.c += -fexceptions endif # Don't compile the ctype glue code, since there is no old non-GNU C library. diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c index fe73fe3ba8..ca20043408 100644 --- a/sysdeps/unix/sysv/linux/check_pf.c +++ b/sysdeps/unix/sysv/linux/check_pf.c @@ -292,6 +292,14 @@ make_request (int fd, pid_t pid) return NULL; } +#ifdef __EXCEPTIONS +static void +cancel_handler (void *arg __attribute__((unused))) +{ + /* Release the lock. */ + __libc_lock_unlock (lock); +} +#endif void attribute_hidden @@ -304,6 +312,10 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6, struct cached_data *olddata = NULL; struct cached_data *data = NULL; +#ifdef __EXCEPTIONS + /* Make sure that lock is released when the thread is cancelled. */ + __libc_cleanup_push (cancel_handler, NULL); +#endif __libc_lock_lock (lock); if (cache_valid_p ()) @@ -338,6 +350,9 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6, } } +#ifdef __EXCEPTIONS + __libc_cleanup_pop (0); +#endif __libc_lock_unlock (lock); if (data != NULL) -- cgit 1.4.1 From 93bd77104cdd7380823d80c778776d2eafb69a91 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Tue, 23 May 2023 16:45:03 -0700 Subject: Document BZ #20975 fix --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index 0b3ee2ad14..43f2deb49d 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ Security related changes: The following bugs are resolved with this release: [12154] Do not fail DNS resolution for CNAMEs which are not host names + [20975] Deferred cancellation triggers in __check_pf and looses lock leading to deadlock [24816] Fix tst-nss-files-hosts-long on single-stack hosts [27576] gmon: improve mcount overflow handling [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning -- cgit 1.4.1 From 53b58a681d62ec3eadae331326ddcc71fdf1e32a Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 24 May 2023 16:24:19 -0300 Subject: io: Fix record locking contants on 32 bit arch with 64 bit default time_t (BZ#30477) For architecture with default 64 bit time_t support, the kernel does not provide LFS and non-LFS values for F_GETLK, F_GETLK, and F_GETLK (the default value used for 64 bit architecture are used). This is might be considered an ABI break, but the currenct exported values is bogus anyway. The POSIX lockf is not affected since it is aliased to lockf64, which already uses the LFS values. Checked on i686-linux-gnu and the new tests on a riscv32. Reviewed-by: Carlos O'Donell (cherry picked from commit 4d0fe291aed3a476a3b59c4ecfae9d35ac0f15e8) --- NEWS | 1 + io/Makefile | 3 +- io/tst-fcntl-lock.c | 97 ++++++++++++++++++++++++++++++ io/tst-lockf.c | 58 ++++++++++-------- sysdeps/unix/sysv/linux/bits/fcntl-linux.h | 2 +- 5 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 io/tst-fcntl-lock.c diff --git a/NEWS b/NEWS index 43f2deb49d..9f6b48b63d 100644 --- a/NEWS +++ b/NEWS @@ -62,6 +62,7 @@ The following bugs are resolved with this release: [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling [30163] posix: Fix system blocks SIGCHLD erroneously [30305] x86_64: Fix asm constraints in feraiseexcept + [30477] libc: [RISCV]: time64 does not work on riscv32 Version 2.36 diff --git a/io/Makefile b/io/Makefile index b1710407d0..fb363c612c 100644 --- a/io/Makefile +++ b/io/Makefile @@ -80,7 +80,8 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ tst-utimensat \ tst-closefrom \ tst-close_range \ - tst-ftw-bz28126 + tst-ftw-bz28126 \ + tst-fcntl-lock tests-time64 := \ tst-fcntl-time64 \ diff --git a/io/tst-fcntl-lock.c b/io/tst-fcntl-lock.c new file mode 100644 index 0000000000..357c4b7b56 --- /dev/null +++ b/io/tst-fcntl-lock.c @@ -0,0 +1,97 @@ +/* Test for advisory record locking. + Copyright (C) 2023 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include +#include + +/* This is essentially the POSIX lockf. */ + +static int +fcntl_lockf (int fd, int cmd, off_t len) +{ + struct flock fl = { + .l_type = F_WRLCK, + .l_whence = SEEK_CUR, + .l_len = len + }; + + switch (cmd) + { + case F_TEST: + fl.l_type = F_RDLCK; + if (fcntl (fd, F_GETLK, &fl) < 0) + return -1; + if (fl.l_type == F_UNLCK || fl.l_pid == getpid ()) + return 0; + errno = EACCES; + return -1; + + case F_ULOCK: + fl.l_type = F_UNLCK; + return fcntl (fd, F_SETLK, &fl); + + case F_LOCK: + return fcntl (fd, F_SETLKW, &fl); + + case F_TLOCK: + return fcntl (fd, F_SETLK, &fl); + } + + errno = EINVAL; + return -1; +} + +static int +fcntl64_lockf (int fd, int cmd, off64_t len64) + { + struct flock64 fl64 = { + .l_type = F_WRLCK, + .l_whence = SEEK_CUR, + .l_len = len64 + }; + + switch (cmd) + { + case F_TEST: + fl64.l_type = F_RDLCK; + if (fcntl64 (fd, F_GETLK64, &fl64) < 0) + return -1; + if (fl64.l_type == F_UNLCK || fl64.l_pid == getpid ()) + return 0; + errno = EACCES; + return -1; + + case F_ULOCK: + fl64.l_type = F_UNLCK; + return fcntl64 (fd, F_SETLK64, &fl64); + + case F_LOCK: + return fcntl64 (fd, F_SETLKW64, &fl64); + + case F_TLOCK: + return fcntl64 (fd, F_SETLK64, &fl64); + } + + errno = EINVAL; + return -1; +} + +#define TST_LOCKFD "tst-fcntl-lock." +#define LOCKF fcntl_lockf +#define LOCKF64 fcntl64_lockf +#include "tst-lockf.c" diff --git a/io/tst-lockf.c b/io/tst-lockf.c index be92f33fd1..5e41dc19df 100644 --- a/io/tst-lockf.c +++ b/io/tst-lockf.c @@ -24,13 +24,23 @@ #include #include +#ifndef TST_LOCKFD +# define TST_LOCKFD "tst-lockfd." +#endif +#ifndef LOCKF +# define LOCKF lockf +#endif +#ifndef LOCKF64 +# define LOCKF64 lockf64 +#endif + static char *temp_filename; static int temp_fd; static void do_prepare (int argc, char **argv) { - temp_fd = create_temp_file ("tst-lockfd.", &temp_filename); + temp_fd = create_temp_file (TST_LOCKFD, &temp_filename); TEST_VERIFY_EXIT (temp_fd != -1); } #define PREPARE do_prepare @@ -40,22 +50,22 @@ do_test_child_lockf (void *closure) { /* Check if parent has [0, 1024) locked. */ TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); - TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), -1); TEST_COMPARE (errno, EAGAIN); - TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); TEST_COMPARE (errno, EACCES); /* Also Check if parent has last 1024 bytes locked. */ TEST_COMPARE (lseek (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); - TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); /* And try to lock [1024, 2048). */ TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); - TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0); + TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); /* Check if non-LFS interface cap access to 32-bif off_t. */ TEST_COMPARE (lseek64 (temp_fd, (off64_t)INT32_MAX, SEEK_SET), (off64_t)INT32_MAX); - TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0); + TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); } static void @@ -63,32 +73,32 @@ do_test_child_lockf64 (void *closure) { /* Check if parent has [0, 1024) locked. */ TEST_COMPARE (lseek64 (temp_fd, 0, SEEK_SET), 0); - TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); TEST_COMPARE (errno, EAGAIN); - TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); TEST_COMPARE (errno, EACCES); /* Also Check if parent has last 1024 bytes locked. */ TEST_COMPARE (lseek64 (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); - TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); /* And try to lock [1024, 2048). */ TEST_COMPARE (lseek64 (temp_fd, 1024, SEEK_SET), 1024); - TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); + TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); /* And also [INT32_MAX, INT32_MAX+1024). */ { off64_t off = (off64_t)INT32_MAX; TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); - TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); + TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); } /* Check if [INT32_MAX+1024, INT64_MAX) is locked. */ { off64_t off = (off64_t)INT32_MAX+1024; TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); - TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); TEST_COMPARE (errno, EAGAIN); - TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); TEST_COMPARE (errno, EACCES); } } @@ -97,38 +107,38 @@ static int do_test (void) { /* Basic tests to check if a lock can be obtained and checked. */ - TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0); - TEST_COMPARE (lockf (temp_fd, F_LOCK, INT32_MAX), 0); - TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), 0); - TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), 0); + TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); + TEST_COMPARE (LOCKF (temp_fd, F_LOCK, INT32_MAX), 0); + TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), 0); + TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), 0); TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); - TEST_COMPARE (lockf (temp_fd, F_ULOCK, 1024), 0); + TEST_COMPARE (LOCKF (temp_fd, F_ULOCK, 1024), 0); /* Parent process should have ([0, 1024), [2048, INT32_MAX)) ranges locked. */ { struct support_capture_subprocess result; result = support_capture_subprocess (do_test_child_lockf, NULL); - support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none); + support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none); } if (sizeof (off_t) != sizeof (off64_t)) { /* Check if previously locked regions with LFS symbol. */ TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); - TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); - TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), 0); - TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0); + TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); + TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), 0); + TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); /* Lock region [INT32_MAX+1024, INT64_MAX). */ off64_t off = (off64_t)INT32_MAX + 1024; TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); - TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); + TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); /* Parent process should have ([0, 1024), [2048, INT32_MAX), [INT32_MAX+1024, INT64_MAX)) ranges locked. */ { struct support_capture_subprocess result; result = support_capture_subprocess (do_test_child_lockf64, NULL); - support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none); + support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none); } } diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h index 33ff88ce59..bfc674235d 100644 --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h @@ -101,7 +101,7 @@ #endif #ifndef F_GETLK -# ifndef __USE_FILE_OFFSET64 +# if !defined __USE_FILE_OFFSET64 && __TIMESIZE != 64 # define F_GETLK 5 /* Get record locking info. */ # define F_SETLK 6 /* Set record locking info (non-blocking). */ # define F_SETLKW 7 /* Set record locking info (blocking). */ -- cgit 1.4.1 From 735cc668131e830d6d61820e06999505f29ed25c Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 30 May 2023 16:40:38 -0300 Subject: io: Fix F_GETLK, F_SETLK, and F_SETLKW for powerpc64 Different than other 64 bit architectures, powerpc64 defines the LFS POSIX lock constants with values similar to 32 ABI, which are meant to be used with fcntl64 syscall. Since powerpc64 kABI does not have fcntl, the constants are adjusted with the FCNTL_ADJUST_CMD macro. The 4d0fe291aed3a476a changed the logic of generic constants LFS value are equal to the default values; which is now wrong for powerpc64. Fix the value by explicit define the previous glibc constants (powerpc64 does not need to use the 32 kABI value, but it simplifies the FCNTL_ADJUST_CMD which should be kept as compatibility). Checked on powerpc64-linux-gnu and powerpc-linux-gnu. (cherry picked from commit 5f828ff824e3b7cd133ef905b8ae25ab8a8f3d66) --- sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h index d7cf158b33..49c8fac0fb 100644 --- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h +++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h @@ -33,6 +33,12 @@ # define __O_LARGEFILE 0200000 #endif +#if __WORDSIZE == 64 +# define F_GETLK 5 +# define F_SETLK 6 +# define F_SETLKW 7 +#endif + struct flock { short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ -- cgit 1.4.1 From c36912f08335ce28ccff963a60853a4035273b34 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 7 Jul 2023 10:11:26 +0200 Subject: elf: _dl_find_object may return 1 during early startup (bug 30515) Success is reported with a 0 return value, and failure is -1. Enhance the kitchen sink test elf/tst-audit28 to cover _dl_find_object as well. Fixes commit 5d28a8962dcb ("elf: Add _dl_find_object function") and bug 30515. Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit 1bcfe0f732066ae5336b252295591ebe7e51c301) --- NEWS | 1 + elf/dl-find_object.c | 2 +- elf/tst-auditmod28.c | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 9f6b48b63d..82e868d73b 100644 --- a/NEWS +++ b/NEWS @@ -63,6 +63,7 @@ The following bugs are resolved with this release: [30163] posix: Fix system blocks SIGCHLD erroneously [30305] x86_64: Fix asm constraints in feraiseexcept [30477] libc: [RISCV]: time64 does not work on riscv32 + [30515] _dl_find_object incorrectly returns 1 during early startup Version 2.36 diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c index 4d5831b6f4..2e5b456c11 100644 --- a/elf/dl-find_object.c +++ b/elf/dl-find_object.c @@ -46,7 +46,7 @@ _dl_find_object_slow (void *pc, struct dl_find_object *result) struct dl_find_object_internal internal; _dl_find_object_from_map (l, &internal); _dl_find_object_to_external (&internal, result); - return 1; + return 0; } /* Object not found. */ diff --git a/elf/tst-auditmod28.c b/elf/tst-auditmod28.c index db7ba95abe..9e0a122c38 100644 --- a/elf/tst-auditmod28.c +++ b/elf/tst-auditmod28.c @@ -71,6 +71,17 @@ la_version (unsigned int current) TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0); TEST_VERIFY (extra_info == handle); + /* Check _dl_find_object. */ + struct dl_find_object dlfo; + TEST_COMPARE (_dl_find_object (__builtin_return_address (0), &dlfo), 0); + /* "ld.so" is seen with --enable-hardcoded-path-in-tests. */ + if (strcmp (basename (dlfo.dlfo_link_map->l_name), "ld.so") != 0) + TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LD_SO); + TEST_COMPARE (_dl_find_object (dlsym (handle, "environ"), &dlfo), 0); + TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LIBC_SO); + TEST_COMPARE (_dl_find_object ((void *) 1, &dlfo), -1); + TEST_COMPARE (_dl_find_object ((void *) -1, &dlfo), -1); + /* Verify that dlmopen creates a new namespace. */ void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); TEST_VERIFY (dlmopen_handle != handle); -- cgit 1.4.1 From 2e74c9016724ce09512920b79485a87d75a00f59 Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Wed, 7 Jun 2023 13:18:01 -0500 Subject: x86: Increase `non_temporal_threshold` to roughly `sizeof_L3 / 4` Current `non_temporal_threshold` set to roughly '3/4 * sizeof_L3 / ncores_per_socket'. This patch updates that value to roughly 'sizeof_L3 / 4` The original value (specifically dividing the `ncores_per_socket`) was done to limit the amount of other threads' data a `memcpy`/`memset` could evict. Dividing by 'ncores_per_socket', however leads to exceedingly low non-temporal thresholds and leads to using non-temporal stores in cases where REP MOVSB is multiple times faster. Furthermore, non-temporal stores are written directly to main memory so using it at a size much smaller than L3 can place soon to be accessed data much further away than it otherwise could be. As well, modern machines are able to detect streaming patterns (especially if REP MOVSB is used) and provide LRU hints to the memory subsystem. This in affect caps the total amount of eviction at 1/cache_associativity, far below meaningfully thrashing the entire cache. As best I can tell, the benchmarks that lead this small threshold where done comparing non-temporal stores versus standard cacheable stores. A better comparison (linked below) is to be REP MOVSB which, on the measure systems, is nearly 2x faster than non-temporal stores at the low-end of the previous threshold, and within 10% for over 100MB copies (well past even the current threshold). In cases with a low number of threads competing for bandwidth, REP MOVSB is ~2x faster up to `sizeof_L3`. The divisor of `4` is a somewhat arbitrary value. From benchmarks it seems Skylake and Icelake both prefer a divisor of `2`, but older CPUs such as Broadwell prefer something closer to `8`. This patch is meant to be followed up by another one to make the divisor cpu-specific, but in the meantime (and for easier backporting), this patch settles on `4` as a middle-ground. Benchmarks comparing non-temporal stores, REP MOVSB, and cacheable stores where done using: https://github.com/goldsteinn/memcpy-nt-benchmarks Sheets results (also available in pdf on the github): https://docs.google.com/spreadsheets/d/e/2PACX-1vS183r0rW_jRX6tG_E90m9qVuFiMbRIJvi5VAE8yYOvEOIEEc3aSNuEsrFbuXw5c3nGboxMmrupZD7K/pubhtml Reviewed-by: DJ Delorie Reviewed-by: Carlos O'Donell (cherry picked from commit af992e7abdc9049714da76cae1e5e18bc4838fb8) --- sysdeps/x86/dl-cacheinfo.h | 79 ++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h index 637b5a022d..6e7d0197a7 100644 --- a/sysdeps/x86/dl-cacheinfo.h +++ b/sysdeps/x86/dl-cacheinfo.h @@ -478,7 +478,7 @@ handle_zhaoxin (int name) } static void -get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, +get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, unsigned int *threads_ptr, long int core) { unsigned int eax; @@ -497,6 +497,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, unsigned int family = cpu_features->basic.family; unsigned int model = cpu_features->basic.model; long int shared = *shared_ptr; + long int shared_per_thread = *shared_per_thread_ptr; unsigned int threads = *threads_ptr; bool inclusive_cache = true; bool support_count_mask = true; @@ -512,6 +513,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, /* Try L2 otherwise. */ level = 2; shared = core; + shared_per_thread = core; threads_l2 = 0; threads_l3 = -1; } @@ -668,29 +670,28 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, } else { -intel_bug_no_cache_info: - /* Assume that all logical threads share the highest cache - level. */ - threads - = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) - & 0xff); - } - - /* Cap usage of highest cache level to the number of supported - threads. */ - if (shared > 0 && threads > 0) - shared /= threads; + intel_bug_no_cache_info: + /* Assume that all logical threads share the highest cache + level. */ + threads = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) + & 0xff); + + /* Get per-thread size of highest level cache. */ + if (shared_per_thread > 0 && threads > 0) + shared_per_thread /= threads; + } } /* Account for non-inclusive L2 and L3 caches. */ if (!inclusive_cache) { if (threads_l2 > 0) - core /= threads_l2; + shared_per_thread += core / threads_l2; shared += core; } *shared_ptr = shared; + *shared_per_thread_ptr = shared_per_thread; *threads_ptr = threads; } @@ -704,6 +705,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) int max_cpuid_ex; long int data = -1; long int shared = -1; + long int shared_per_thread = -1; long int core = -1; unsigned int threads = 0; unsigned long int level1_icache_size = -1; @@ -724,6 +726,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); + shared_per_thread = shared; level1_icache_size = handle_intel (_SC_LEVEL1_ICACHE_SIZE, cpu_features); @@ -747,13 +750,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) level4_cache_size = handle_intel (_SC_LEVEL4_CACHE_SIZE, cpu_features); - get_common_cache_info (&shared, &threads, core); + get_common_cache_info (&shared, &shared_per_thread, &threads, core); } else if (cpu_features->basic.kind == arch_kind_zhaoxin) { data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); + shared_per_thread = shared; level1_icache_size = handle_zhaoxin (_SC_LEVEL1_ICACHE_SIZE); level1_icache_linesize = handle_zhaoxin (_SC_LEVEL1_ICACHE_LINESIZE); @@ -767,13 +771,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) level3_cache_assoc = handle_zhaoxin (_SC_LEVEL3_CACHE_ASSOC); level3_cache_linesize = handle_zhaoxin (_SC_LEVEL3_CACHE_LINESIZE); - get_common_cache_info (&shared, &threads, core); + get_common_cache_info (&shared, &shared_per_thread, &threads, core); } else if (cpu_features->basic.kind == arch_kind_amd) { data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); core = handle_amd (_SC_LEVEL2_CACHE_SIZE); shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); + shared_per_thread = shared; level1_icache_size = handle_amd (_SC_LEVEL1_ICACHE_SIZE); level1_icache_linesize = handle_amd (_SC_LEVEL1_ICACHE_LINESIZE); @@ -791,8 +796,11 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); if (shared <= 0) - /* No shared L3 cache. All we have is the L2 cache. */ - shared = core; + { + /* No shared L3 cache. All we have is the L2 cache. */ + shared = core; + shared_per_thread = core; + } else { /* Figure out the number of logical threads that share L3. */ @@ -816,7 +824,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) /* Cap usage of highest cache level to the number of supported threads. */ if (threads > 0) - shared /= threads; + shared_per_thread /= threads; /* Get shared cache per ccx for Zen architectures. */ if (cpu_features->basic.family >= 0x17) @@ -827,12 +835,13 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; - shared *= threads_per_ccx; + shared_per_thread *= threads_per_ccx; } else { /* Account for exclusive L2 and L3 caches. */ shared += core; + shared_per_thread += core; } } } @@ -850,17 +859,25 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) cpu_features->level3_cache_linesize = level3_cache_linesize; cpu_features->level4_cache_size = level4_cache_size; - /* The default setting for the non_temporal threshold is 3/4 of one - thread's share of the chip's cache. For most Intel and AMD processors - with an initial release date between 2017 and 2020, a thread's typical - share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 - threshold leaves 125 KBytes to 500 KBytes of the thread's data - in cache after a maximum temporal copy, which will maintain - in cache a reasonable portion of the thread's stack and other - active data. If the threshold is set higher than one thread's - share of the cache, it has a substantial risk of negatively - impacting the performance of other threads running on the chip. */ - unsigned long int non_temporal_threshold = shared * 3 / 4; + /* The default setting for the non_temporal threshold is 1/4 of size + of the chip's cache. For most Intel and AMD processors with an + initial release date between 2017 and 2023, a thread's typical + share of the cache is from 18-64MB. Using the 1/4 L3 is meant to + estimate the point where non-temporal stores begin out-competing + REP MOVSB. As well the point where the fact that non-temporal + stores are forced back to main memory would already occurred to the + majority of the lines in the copy. Note, concerns about the + entire L3 cache being evicted by the copy are mostly alleviated + by the fact that modern HW detects streaming patterns and + provides proper LRU hints so that the maximum thrashing + capped at 1/associativity. */ + unsigned long int non_temporal_threshold = shared / 4; + /* If no ERMS, we use the per-thread L3 chunking. Normal cacheable stores run + a higher risk of actually thrashing the cache as they don't have a HW LRU + hint. As well, their performance in highly parallel situations is + noticeably worse. */ + if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + non_temporal_threshold = shared_per_thread * 3 / 4; /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best if that operation cannot overflow. Minimum of 0x4040 (16448) because the -- cgit 1.4.1 From 42c266a18f1aa87813b138247f98d7b690c67f34 Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Mon, 17 Jul 2023 23:14:33 -0500 Subject: x86: Fix slight bug in `shared_per_thread` cache size calculation. After: ``` commit af992e7abdc9049714da76cae1e5e18bc4838fb8 Author: Noah Goldstein Date: Wed Jun 7 13:18:01 2023 -0500 x86: Increase `non_temporal_threshold` to roughly `sizeof_L3 / 4` ``` Split `shared` (cumulative cache size) from `shared_per_thread` (cache size per socket), the `shared_per_thread` *can* be slightly off from the previous calculation. Previously we added `core` even if `threads_l2` was invalid, and only used `threads_l2` to divide `core` if it was present. The changed version only included `core` if `threads_l2` was valid. This change restores the old behavior if `threads_l2` is invalid by adding the entire value of `core`. Reviewed-by: DJ Delorie (cherry picked from commit 47f747217811db35854ea06741be3685e8bbd44d) --- sysdeps/x86/dl-cacheinfo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h index 6e7d0197a7..79fb8cc5e3 100644 --- a/sysdeps/x86/dl-cacheinfo.h +++ b/sysdeps/x86/dl-cacheinfo.h @@ -685,8 +685,8 @@ get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, u /* Account for non-inclusive L2 and L3 caches. */ if (!inclusive_cache) { - if (threads_l2 > 0) - shared_per_thread += core / threads_l2; + long int core_per_thread = threads_l2 > 0 ? (core / threads_l2) : core; + shared_per_thread += core_per_thread; shared += core; } -- cgit 1.4.1 From 64b184fd80e4441b5fd97987fabecf0b54f20cae Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Tue, 18 Jul 2023 10:27:59 -0500 Subject: x86: Use `3/4*sizeof(per-thread-L3)` as low bound for NT threshold. On some machines we end up with incomplete cache information. This can make the new calculation of `sizeof(total-L3)/custom-divisor` end up lower than intended (and lower than the prior value). So reintroduce the old bound as a lower bound to avoid potentially regressing code where we don't have complete information to make the decision. Reviewed-by: DJ Delorie (cherry picked from commit 8b9a0af8ca012217bf90d1dc0694f85b49ae09da) --- sysdeps/x86/dl-cacheinfo.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h index 79fb8cc5e3..627cf57efe 100644 --- a/sysdeps/x86/dl-cacheinfo.h +++ b/sysdeps/x86/dl-cacheinfo.h @@ -872,12 +872,21 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) provides proper LRU hints so that the maximum thrashing capped at 1/associativity. */ unsigned long int non_temporal_threshold = shared / 4; + + /* If the computed non_temporal_threshold <= 3/4 * per-thread L3, we most + likely have incorrect/incomplete cache info in which case, default to + 3/4 * per-thread L3 to avoid regressions. */ + unsigned long int non_temporal_threshold_lowbound + = shared_per_thread * 3 / 4; + if (non_temporal_threshold < non_temporal_threshold_lowbound) + non_temporal_threshold = non_temporal_threshold_lowbound; + /* If no ERMS, we use the per-thread L3 chunking. Normal cacheable stores run a higher risk of actually thrashing the cache as they don't have a HW LRU hint. As well, their performance in highly parallel situations is noticeably worse. */ if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS)) - non_temporal_threshold = shared_per_thread * 3 / 4; + non_temporal_threshold = non_temporal_threshold_lowbound; /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best if that operation cannot overflow. Minimum of 0x4040 (16448) because the -- cgit 1.4.1 From eb8bf044bd725663fb8747dcf436cc7467ad4be1 Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Thu, 10 Aug 2023 19:28:24 -0500 Subject: x86: Fix incorrect scope of setting `shared_per_thread` [BZ# 30745] The: ``` if (shared_per_thread > 0 && threads > 0) shared_per_thread /= threads; ``` Code was accidentally moved to inside the else scope. This doesn't match how it was previously (before af992e7abd). This patch fixes that by putting the division after the `else` block. (cherry picked from commit 084fb31bc2c5f95ae0b9e6df4d3cf0ff43471ede) --- sysdeps/x86/dl-cacheinfo.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h index 627cf57efe..d95c1efa2c 100644 --- a/sysdeps/x86/dl-cacheinfo.h +++ b/sysdeps/x86/dl-cacheinfo.h @@ -675,11 +675,10 @@ get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, u level. */ threads = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) & 0xff); - - /* Get per-thread size of highest level cache. */ - if (shared_per_thread > 0 && threads > 0) - shared_per_thread /= threads; } + /* Get per-thread size of highest level cache. */ + if (shared_per_thread > 0 && threads > 0) + shared_per_thread /= threads; } /* Account for non-inclusive L2 and L3 caches. */ -- cgit 1.4.1 From b6c713557688bfb42c6279ec3d8dfab5884510fe Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 27 Oct 2022 11:36:44 +0200 Subject: elf: Introduce to _dl_call_fini This consolidates the destructor invocations from _dl_fini and dlclose. Remove the micro-optimization that avoids calling _dl_call_fini if they are no destructors (as dlclose is quite expensive anyway). The debug log message is now printed unconditionally. Reviewed-by: Adhemerval Zanella --- elf/Makefile | 1 + elf/dl-call_fini.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ elf/dl-close.c | 42 +------------------------------------- elf/dl-fini.c | 38 +---------------------------------- sysdeps/generic/ldsodefs.h | 8 ++++++++ 5 files changed, 61 insertions(+), 78 deletions(-) create mode 100644 elf/dl-call_fini.c diff --git a/elf/Makefile b/elf/Makefile index 48788fcdb8..30c9af1de9 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -53,6 +53,7 @@ routines = \ # profiled libraries. dl-routines = \ dl-call-libc-early-init \ + dl-call_fini \ dl-close \ dl-debug \ dl-debug-symbols \ diff --git a/elf/dl-call_fini.c b/elf/dl-call_fini.c new file mode 100644 index 0000000000..9e7ba10fa2 --- /dev/null +++ b/elf/dl-call_fini.c @@ -0,0 +1,50 @@ +/* Invoke DT_FINI and DT_FINI_ARRAY callbacks. + Copyright (C) 1996-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void +_dl_call_fini (void *closure_map) +{ + struct link_map *map = closure_map; + + /* When debugging print a message first. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS)) + _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", map->l_name, map->l_ns); + + /* Make sure nothing happens if we are called twice. */ + map->l_init_called = 0; + + ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY]; + if (fini_array != NULL) + { + ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr + + fini_array->d_un.d_ptr); + size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + + while (sz-- > 0) + ((fini_t) array[sz]) (); + } + + /* Next try the old-style destructor. */ + ElfW(Dyn) *fini = map->l_info[DT_FINI]; + if (fini != NULL) + DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr)); +} diff --git a/elf/dl-close.c b/elf/dl-close.c index bcd6e206e9..14deca2e2b 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -36,11 +36,6 @@ #include - -/* Type of the constructor functions. */ -typedef void (*fini_t) (void); - - /* Special l_idx value used to indicate which objects remain loaded. */ #define IDX_STILL_USED -1 @@ -110,31 +105,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, return false; } -/* Invoke dstructors for CLOSURE (a struct link_map *). Called with - exception handling temporarily disabled, to make errors fatal. */ -static void -call_destructors (void *closure) -{ - struct link_map *map = closure; - - if (map->l_info[DT_FINI_ARRAY] != NULL) - { - ElfW(Addr) *array = - (ElfW(Addr) *) (map->l_addr - + map->l_info[DT_FINI_ARRAY]->d_un.d_ptr); - unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val - / sizeof (ElfW(Addr))); - - while (sz-- > 0) - ((fini_t) array[sz]) (); - } - - /* Next try the old-style destructor. */ - if (map->l_info[DT_FINI] != NULL) - DL_CALL_DT_FINI (map, ((void *) map->l_addr - + map->l_info[DT_FINI]->d_un.d_ptr)); -} - void _dl_close_worker (struct link_map *map, bool force) { @@ -280,17 +250,7 @@ _dl_close_worker (struct link_map *map, bool force) half-cooked objects. Temporarily disable exception handling, so that errors are fatal. */ if (imap->l_init_called) - { - /* When debugging print a message first. */ - if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, - 0)) - _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", - imap->l_name, nsid); - - if (imap->l_info[DT_FINI_ARRAY] != NULL - || imap->l_info[DT_FINI] != NULL) - _dl_catch_exception (NULL, call_destructors, imap); - } + _dl_catch_exception (NULL, _dl_call_fini, imap); #ifdef SHARED /* Auditing checkpoint: we remove an object. */ diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 030b1fcbcd..50ff94db16 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -21,11 +21,6 @@ #include #include - -/* Type of the constructor functions. */ -typedef void (*fini_t) (void); - - void _dl_fini (void) { @@ -116,38 +111,7 @@ _dl_fini (void) if (l->l_init_called) { - /* Make sure nothing happens if we are called twice. */ - l->l_init_called = 0; - - /* Is there a destructor function? */ - if (l->l_info[DT_FINI_ARRAY] != NULL - || (ELF_INITFINI && l->l_info[DT_FINI] != NULL)) - { - /* When debugging print a message first. */ - if (__builtin_expect (GLRO(dl_debug_mask) - & DL_DEBUG_IMPCALLS, 0)) - _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", - DSO_FILENAME (l->l_name), - ns); - - /* First see whether an array is given. */ - if (l->l_info[DT_FINI_ARRAY] != NULL) - { - ElfW(Addr) *array = - (ElfW(Addr) *) (l->l_addr - + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); - unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val - / sizeof (ElfW(Addr))); - while (i-- > 0) - ((fini_t) array[i]) (); - } - - /* Next try the old-style destructor. */ - if (ELF_INITFINI && l->l_info[DT_FINI] != NULL) - DL_CALL_DT_FINI - (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr); - } - + _dl_call_fini (l); #ifdef SHARED /* Auditing checkpoint: another object closed. */ _dl_audit_objclose (l); diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 6b256b8388..c2627fced7 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -105,6 +105,9 @@ typedef struct link_map *lookup_t; DT_PREINIT_ARRAY. */ typedef void (*dl_init_t) (int, char **, char **); +/* Type of a constructor function, in DT_FINI, DT_FINI_ARRAY. */ +typedef void (*fini_t) (void); + /* On some architectures a pointer to a function is not just a pointer to the actual code of the function but rather an architecture specific descriptor. */ @@ -1048,6 +1051,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv, initializer functions have completed. */ extern void _dl_fini (void) attribute_hidden; +/* Invoke the DT_FINI_ARRAY and DT_FINI destructors for MAP, which + must be a struct link_map *. Can be used as an argument to + _dl_catch_exception. */ +void _dl_call_fini (void *map) attribute_hidden; + /* Sort array MAPS according to dependencies of the contained objects. If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies say otherwise. */ -- cgit 1.4.1 From f33ffef08983621c6a89a12771486c3beaf50d11 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 22 Aug 2023 13:56:25 +0200 Subject: elf: Do not run constructors for proxy objects Otherwise, the ld.so constructor runs for each audit namespace and each dlmopen namespace. (cherry picked from commit f6c8204fd7fabf0cf4162eaf10ccf23258e4d10e) --- elf/dl-init.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/elf/dl-init.c b/elf/dl-init.c index deefeb099a..fca8e3a05e 100644 --- a/elf/dl-init.c +++ b/elf/dl-init.c @@ -25,10 +25,14 @@ static void call_init (struct link_map *l, int argc, char **argv, char **env) { + /* Do not run constructors for proxy objects. */ + if (l != l->l_real) + return; + /* If the object has not been relocated, this is a bug. The function pointers are invalid in this case. (Executables do not - need relocation, and neither do proxy objects.) */ - assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable); + need relocation.) */ + assert (l->l_relocated || l->l_type == lt_executable); if (l->l_init_called) /* This object is all done. */ -- cgit 1.4.1 From 5d83a52a4905405792418d6a0f3afa3601a98c37 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 8 Sep 2023 12:32:14 +0200 Subject: elf: Always call destructors in reverse constructor order (bug 30785) The current implementation of dlclose (and process exit) re-sorts the link maps before calling ELF destructors. Destructor order is not the reverse of the constructor order as a result: The second sort takes relocation dependencies into account, and other differences can result from ambiguous inputs, such as cycles. (The force_first handling in _dl_sort_maps is not effective for dlclose.) After the changes in this commit, there is still a required difference due to dlopen/dlclose ordering by the application, but the previous discrepancies went beyond that. A new global (namespace-spanning) list of link maps, _dl_init_called_list, is updated right before ELF constructors are called from _dl_init. In dl_close_worker, the maps variable, an on-stack variable length array, is eliminated. (VLAs are problematic, and dlclose should not call malloc because it cannot readily deal with malloc failure.) Marking still-used objects uses the namespace list directly, with next and next_idx replacing the done_index variable. After marking, _dl_init_called_list is used to call the destructors of now-unused maps in reverse destructor order. These destructors can call dlopen. Previously, new objects do not have l_map_used set. This had to change: There is no copy of the link map list anymore, so processing would cover newly opened (and unmarked) mappings, unloading them. Now, _dl_init (indirectly) sets l_map_used, too. (dlclose is handled by the existing reentrancy guard.) After _dl_init_called_list traversal, two more loops follow. The processing order changes to the original link map order in the namespace. Previously, dependency order was used. The difference should not matter because relocation dependencies could already reorder link maps in the old code. The changes to _dl_fini remove the sorting step and replace it with a traversal of _dl_init_called_list. The l_direct_opencount decrement outside the loader lock is removed because it appears incorrect: the counter manipulation could race with other dynamic loader operations. tst-audit23 needs adjustments to the changes in LA_ACT_DELETE notifications. The new approach for checking la_activity should make it clearer that la_activty calls come in pairs around namespace updates. The dependency sorting test cases need updates because the destructor order is always the opposite order of constructor order, even with relocation dependencies or cycles present. There is a future cleanup opportunity to remove the now-constant force_first and for_fini arguments from the _dl_sort_maps function. Fixes commit 1df71d32fe5f5905ffd5d100e5e9ca8ad62 ("elf: Implement force_first handling in _dl_sort_maps_dfs (bug 28937)"). Reviewed-by: DJ Delorie (cherry picked from commit 6985865bc3ad5b23147ee73466583dd7fdf65892) --- NEWS | 1 + elf/dl-close.c | 113 +++++++++++++++++++++------------ elf/dl-fini.c | 152 ++++++++++++++++----------------------------- elf/dl-init.c | 16 +++++ elf/dso-sort-tests-1.def | 19 ++---- elf/tst-audit23.c | 44 +++++++------ include/link.h | 4 ++ sysdeps/generic/ldsodefs.h | 4 ++ 8 files changed, 180 insertions(+), 173 deletions(-) diff --git a/NEWS b/NEWS index 82e868d73b..fd9d34b9b4 100644 --- a/NEWS +++ b/NEWS @@ -64,6 +64,7 @@ The following bugs are resolved with this release: [30305] x86_64: Fix asm constraints in feraiseexcept [30477] libc: [RISCV]: time64 does not work on riscv32 [30515] _dl_find_object incorrectly returns 1 during early startup + [30785] Always call destructors in reverse constructor order Version 2.36 diff --git a/elf/dl-close.c b/elf/dl-close.c index 14deca2e2b..640bbd88c3 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -138,30 +138,31 @@ _dl_close_worker (struct link_map *map, bool force) bool any_tls = false; const unsigned int nloaded = ns->_ns_nloaded; - struct link_map *maps[nloaded]; - /* Run over the list and assign indexes to the link maps and enter - them into the MAPS array. */ + /* Run over the list and assign indexes to the link maps. */ int idx = 0; for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next) { l->l_map_used = 0; l->l_map_done = 0; l->l_idx = idx; - maps[idx] = l; ++idx; } assert (idx == nloaded); - /* Keep track of the lowest index link map we have covered already. */ - int done_index = -1; - while (++done_index < nloaded) + /* Keep marking link maps until no new link maps are found. */ + for (struct link_map *l = ns->_ns_loaded; l != NULL; ) { - struct link_map *l = maps[done_index]; + /* next is reset to earlier link maps for remarking. */ + struct link_map *next = l->l_next; + int next_idx = l->l_idx + 1; /* next->l_idx, but covers next == NULL. */ if (l->l_map_done) - /* Already handled. */ - continue; + { + /* Already handled. */ + l = next; + continue; + } /* Check whether this object is still used. */ if (l->l_type == lt_loaded @@ -171,7 +172,10 @@ _dl_close_worker (struct link_map *map, bool force) acquire is sufficient and correct. */ && atomic_load_acquire (&l->l_tls_dtor_count) == 0 && !l->l_map_used) - continue; + { + l = next; + continue; + } /* We need this object and we handle it now. */ l->l_map_used = 1; @@ -198,8 +202,11 @@ _dl_close_worker (struct link_map *map, bool force) already processed it, then we need to go back and process again from that point forward to ensure we keep all of its dependencies also. */ - if ((*lp)->l_idx - 1 < done_index) - done_index = (*lp)->l_idx - 1; + if ((*lp)->l_idx < next_idx) + { + next = *lp; + next_idx = next->l_idx; + } } } @@ -219,44 +226,65 @@ _dl_close_worker (struct link_map *map, bool force) if (!jmap->l_map_used) { jmap->l_map_used = 1; - if (jmap->l_idx - 1 < done_index) - done_index = jmap->l_idx - 1; + if (jmap->l_idx < next_idx) + { + next = jmap; + next_idx = next->l_idx; + } } } } - } - /* 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); + l = next; + } - /* Call all termination functions at once. */ - bool unload_any = false; - bool scope_mem_left = false; - unsigned int unload_global = 0; - unsigned int first_loaded = ~0; - for (unsigned int i = 0; i < nloaded; ++i) + /* Call the destructors in reverse constructor order, and remove the + closed link maps from the list. */ + for (struct link_map **init_called_head = &_dl_init_called_list; + *init_called_head != NULL; ) { - struct link_map *imap = maps[i]; + struct link_map *imap = *init_called_head; - /* All elements must be in the same namespace. */ - assert (imap->l_ns == nsid); - - if (!imap->l_map_used) + /* _dl_init_called_list is global, to produce a global odering. + Ignore the other namespaces (and link maps that are still used). */ + if (imap->l_ns != nsid || imap->l_map_used) + init_called_head = &imap->l_init_called_next; + else { assert (imap->l_type == lt_loaded && !imap->l_nodelete_active); - /* Call its termination function. Do not do it for - half-cooked objects. Temporarily disable exception - handling, so that errors are fatal. */ - if (imap->l_init_called) + /* _dl_init_called_list is updated at the same time as + l_init_called. */ + assert (imap->l_init_called); + + if (imap->l_info[DT_FINI_ARRAY] != NULL + || imap->l_info[DT_FINI] != NULL) _dl_catch_exception (NULL, _dl_call_fini, imap); #ifdef SHARED /* Auditing checkpoint: we remove an object. */ _dl_audit_objclose (imap); #endif + /* Unlink this link map. */ + *init_called_head = imap->l_init_called_next; + } + } + + + bool unload_any = false; + bool scope_mem_left = false; + unsigned int unload_global = 0; + + /* For skipping un-unloadable link maps in the second loop. */ + struct link_map *first_loaded = ns->_ns_loaded; + /* Iterate over the namespace to find objects to unload. Some + unloadable objects may not be on _dl_init_called_list due to + dlopen failure. */ + for (struct link_map *imap = first_loaded; imap != NULL; imap = imap->l_next) + { + if (!imap->l_map_used) + { /* This object must not be used anymore. */ imap->l_removed = 1; @@ -267,8 +295,8 @@ _dl_close_worker (struct link_map *map, bool force) ++unload_global; /* Remember where the first dynamically loaded object is. */ - if (i < first_loaded) - first_loaded = i; + if (first_loaded == NULL) + first_loaded = imap; } /* Else imap->l_map_used. */ else if (imap->l_type == lt_loaded) @@ -404,8 +432,8 @@ _dl_close_worker (struct link_map *map, bool force) imap->l_loader = NULL; /* Remember where the first dynamically loaded object is. */ - if (i < first_loaded) - first_loaded = i; + if (first_loaded == NULL) + first_loaded = imap; } } @@ -476,10 +504,11 @@ _dl_close_worker (struct link_map *map, bool force) /* Check each element of the search list to see if all references to it are gone. */ - for (unsigned int i = first_loaded; i < nloaded; ++i) + for (struct link_map *imap = first_loaded; imap != NULL; ) { - struct link_map *imap = maps[i]; - if (!imap->l_map_used) + if (imap->l_map_used) + imap = imap->l_next; + else { assert (imap->l_type == lt_loaded); @@ -690,7 +719,9 @@ _dl_close_worker (struct link_map *map, bool force) if (imap == GL(dl_initfirst)) GL(dl_initfirst) = NULL; + struct link_map *next = imap->l_next; free (imap); + imap = next; } } diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 50ff94db16..50087a1bfc 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -24,116 +24,68 @@ void _dl_fini (void) { - /* Lots of fun ahead. We have to call the destructors for all still - loaded objects, in all namespaces. The problem is that the ELF - specification now demands that dependencies between the modules - are taken into account. I.e., the destructor for a module is - called before the ones for any of its dependencies. - - To make things more complicated, we cannot simply use the reverse - order of the constructors. Since the user might have loaded objects - using `dlopen' there are possibly several other modules with its - dependencies to be taken into account. Therefore we have to start - determining the order of the modules once again from the beginning. */ - - /* We run the destructors of the main namespaces last. As for the - other namespaces, we pick run the destructors in them in reverse - order of the namespace ID. */ -#ifdef SHARED - int do_audit = 0; - again: -#endif - for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns) - { - /* Protect against concurrent loads and unloads. */ - __rtld_lock_lock_recursive (GL(dl_load_lock)); - - unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded; - /* No need to do anything for empty namespaces or those used for - auditing DSOs. */ - if (nloaded == 0 -#ifdef SHARED - || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit -#endif - ) - __rtld_lock_unlock_recursive (GL(dl_load_lock)); - else - { + /* Call destructors strictly in the reverse order of constructors. + This causes fewer surprises than some arbitrary reordering based + on new (relocation) dependencies. None of the objects are + unmapped, so applications can deal with this if their DSOs remain + in a consistent state after destructors have run. */ + + /* Protect against concurrent loads and unloads. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); + + /* Ignore objects which are opened during shutdown. */ + struct link_map *local_init_called_list = _dl_init_called_list; + + for (struct link_map *l = local_init_called_list; l != NULL; + l = l->l_init_called_next) + /* Bump l_direct_opencount of all objects so that they + are not dlclose()ed from underneath us. */ + ++l->l_direct_opencount; + + /* After this point, everything linked from local_init_called_list + cannot be unloaded because of the reference counter update. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + /* Perform two passes: One for non-audit modules, one for audit + modules. This way, audit modules receive unload notifications + for non-audit objects, and the destructors for audit modules + still run. */ #ifdef SHARED - _dl_audit_activity_nsid (ns, LA_ACT_DELETE); + int last_pass = GLRO(dl_naudit) > 0; + Lmid_t last_ns = -1; + for (int do_audit = 0; do_audit <= last_pass; ++do_audit) #endif - - /* Now we can allocate an array to hold all the pointers and - copy the pointers in. */ - struct link_map *maps[nloaded]; - - unsigned int i; - struct link_map *l; - assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL); - for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next) - /* Do not handle ld.so in secondary namespaces. */ - if (l == l->l_real) - { - assert (i < nloaded); - - maps[i] = l; - l->l_idx = i; - ++i; - - /* Bump l_direct_opencount of all objects so that they - are not dlclose()ed from underneath us. */ - ++l->l_direct_opencount; - } - assert (ns != LM_ID_BASE || i == nloaded); - assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1); - unsigned int nmaps = i; - - /* Now we have to do the sorting. 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, nmaps, (ns == LM_ID_BASE), true); - - /* We do not rely on the linked list of loaded object anymore - from this point on. We have our own list here (maps). The - various members of this list cannot vanish since the open - count is too high and will be decremented in this loop. So - we release the lock so that some code which might be called - from a destructor can directly or indirectly access the - lock. */ - __rtld_lock_unlock_recursive (GL(dl_load_lock)); - - /* 'maps' now contains the objects in the right order. Now - call the destructors. We have to process this array from - the front. */ - for (i = 0; i < nmaps; ++i) - { - struct link_map *l = maps[i]; - - if (l->l_init_called) - { - _dl_call_fini (l); + for (struct link_map *l = local_init_called_list; l != NULL; + l = l->l_init_called_next) + { #ifdef SHARED - /* Auditing checkpoint: another object closed. */ - _dl_audit_objclose (l); + if (GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing != do_audit) + continue; + + /* Avoid back-to-back calls of _dl_audit_activity_nsid for the + same namespace. */ + if (last_ns != l->l_ns) + { + if (last_ns >= 0) + _dl_audit_activity_nsid (last_ns, LA_ACT_CONSISTENT); + _dl_audit_activity_nsid (l->l_ns, LA_ACT_DELETE); + last_ns = l->l_ns; + } #endif - } - /* Correct the previous increment. */ - --l->l_direct_opencount; - } + /* There is no need to re-enable exceptions because _dl_fini + is not called from a context where exceptions are caught. */ + _dl_call_fini (l); #ifdef SHARED - _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT); + /* Auditing checkpoint: another object closed. */ + _dl_audit_objclose (l); #endif - } - } + } #ifdef SHARED - if (! do_audit && GLRO(dl_naudit) > 0) - { - do_audit = 1; - goto again; - } + if (last_ns >= 0) + _dl_audit_activity_nsid (last_ns, LA_ACT_CONSISTENT); if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS)) _dl_debug_printf ("\nruntime linker statistics:\n" diff --git a/elf/dl-init.c b/elf/dl-init.c index fca8e3a05e..77b2edd838 100644 --- a/elf/dl-init.c +++ b/elf/dl-init.c @@ -21,6 +21,7 @@ #include #include +struct link_map *_dl_init_called_list; static void call_init (struct link_map *l, int argc, char **argv, char **env) @@ -42,6 +43,21 @@ call_init (struct link_map *l, int argc, char **argv, char **env) dependency. */ l->l_init_called = 1; + /* Help an already-running dlclose: The just-loaded object must not + be removed during the current pass. (No effect if no dlclose in + progress.) */ + l->l_map_used = 1; + + /* Record execution before starting any initializers. This way, if + the initializers themselves call dlopen, their ELF destructors + will eventually be run before this object is destructed, matching + that their ELF constructors have run before this object was + constructed. _dl_fini uses this list for audit callbacks, so + register objects on the list even if they do not have a + constructor. */ + l->l_init_called_next = _dl_init_called_list; + _dl_init_called_list = l; + /* Check for object which constructors we do not run here. */ if (__builtin_expect (l->l_name[0], 'a') == '\0' && l->l_type == lt_executable) diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def index 4bf9052db1..61dc54f8ae 100644 --- a/elf/dso-sort-tests-1.def +++ b/elf/dso-sort-tests-1.def @@ -53,21 +53,14 @@ tst-dso-ordering10: {}->a->b->c;soname({})=c output: b>a>{}b->c->d order). -# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based -# dynamic_sort=2 algorithm does, although it is still arguable whether going -# beyond spec to do this is the right thing to do. -# The below expected outputs are what the two algorithms currently produce -# respectively, for regression testing purposes. +# relocation(dynamic) dependencies. For both sorting algorithms, the +# destruction order is the reverse of the construction order, and +# relocation dependencies are not taken into account. tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c -output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[a1;a->a2;a2->a;b->b1;c->a1;c=>a1 -output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());} Date: Fri, 8 Sep 2023 13:02:06 +0200 Subject: elf: Remove unused l_text_end field from struct link_map It is a left-over from commit 52a01100ad011293197637e42b5be1a479a2 ("elf: Remove ad-hoc restrictions on dlopen callers [BZ #22787]"). When backporting commmit 6985865bc3ad5b23147ee73466583dd7fdf65892 ("elf: Always call destructors in reverse constructor order (bug 30785)"), we can move the l_init_called_next field to this place, so that the internal GLIBC_PRIVATE ABI does not change. Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit 53df2ce6885da3d0e89e87dca7b095622296014f) --- elf/dl-load.c | 2 +- elf/dl-load.h | 7 ++----- elf/rtld.c | 6 ------ elf/setup-vdso.h | 4 ---- include/link.h | 2 -- 5 files changed, 3 insertions(+), 18 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index 1ad0868dad..cb59c21ce7 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1263,7 +1263,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, /* Now process the load commands and map segments into memory. This is responsible for filling in: - l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr + l_map_start, l_map_end, l_addr, l_contiguous, l_phdr */ errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, maplength, has_holes, loader); diff --git a/elf/dl-load.h b/elf/dl-load.h index f98d264e90..ebf7d74cd0 100644 --- a/elf/dl-load.h +++ b/elf/dl-load.h @@ -83,14 +83,11 @@ struct loadcmd /* This is a subroutine of _dl_map_segments. It should be called for each load command, some time after L->l_addr has been set correctly. It is - responsible for setting up the l_text_end and l_phdr fields. */ + responsible for setting the l_phdr fields */ static __always_inline void _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header, const struct loadcmd *c) { - if (c->prot & PROT_EXEC) - l->l_text_end = l->l_addr + c->mapend; - if (l->l_phdr == 0 && c->mapoff <= header->e_phoff && ((size_t) (c->mapend - c->mapstart + c->mapoff) @@ -103,7 +100,7 @@ _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header, /* This is a subroutine of _dl_map_object_from_fd. It is responsible for filling in several fields in *L: l_map_start, l_map_end, l_addr, - l_contiguous, l_text_end, l_phdr. On successful return, all the + l_contiguous, l_phdr. On successful return, all the segments are mapped (or copied, or whatever) from the file into their final places in the address space, with the correct page permissions, and any bss-like regions already zeroed. It returns a null pointer diff --git a/elf/rtld.c b/elf/rtld.c index 3e771a93d8..dd45930ff7 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -479,7 +479,6 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) GL(dl_rtld_map).l_real = &GL(dl_rtld_map); GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start; GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end; - GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext; /* Copy the TLS related data if necessary. */ #ifndef DONT_USE_BOOTSTRAP_MAP # if NO_TLS_OFFSET != 0 @@ -1124,7 +1123,6 @@ rtld_setup_main_map (struct link_map *main_map) bool has_interp = false; main_map->l_map_end = 0; - main_map->l_text_end = 0; /* Perhaps the executable has no PT_LOAD header entries at all. */ main_map->l_map_start = ~0; /* And it was opened directly. */ @@ -1216,8 +1214,6 @@ rtld_setup_main_map (struct link_map *main_map) allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz; if (main_map->l_map_end < allocend) main_map->l_map_end = allocend; - if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end) - main_map->l_text_end = allocend; /* The next expected address is the page following this load segment. */ @@ -1277,8 +1273,6 @@ rtld_setup_main_map (struct link_map *main_map) = (char *) main_map->l_tls_initimage + main_map->l_addr; if (! main_map->l_map_end) main_map->l_map_end = ~0; - if (! main_map->l_text_end) - main_map->l_text_end = ~0; if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name) { /* We were invoked directly, so the program might not have a diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h index c0807ea82b..415d5057c3 100644 --- a/elf/setup-vdso.h +++ b/elf/setup-vdso.h @@ -51,9 +51,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), l->l_addr = ph->p_vaddr; if (ph->p_vaddr + ph->p_memsz >= l->l_map_end) l->l_map_end = ph->p_vaddr + ph->p_memsz; - if ((ph->p_flags & PF_X) - && ph->p_vaddr + ph->p_memsz >= l->l_text_end) - l->l_text_end = ph->p_vaddr + ph->p_memsz; } else /* There must be no TLS segment. */ @@ -62,7 +59,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso); l->l_addr = l->l_map_start - l->l_addr; l->l_map_end += l->l_addr; - l->l_text_end += l->l_addr; l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr); elf_get_dynamic_info (l, false, false); _dl_setup_hash (l); diff --git a/include/link.h b/include/link.h index 87966e8397..81f5715db0 100644 --- a/include/link.h +++ b/include/link.h @@ -253,8 +253,6 @@ struct link_map /* Start and finish of memory map for this object. l_map_start need not be the same as l_addr. */ ElfW(Addr) l_map_start, l_map_end; - /* End of the executable part of the mapping. */ - ElfW(Addr) l_text_end; /* Default array for 'l_scope'. */ struct r_scope_elem *l_scope_mem[4]; -- cgit 1.4.1 From f441cb9a70fa3f55e9bbd615924879d692d21a6c Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 11 Sep 2023 09:17:52 +0200 Subject: elf: Move l_init_called_next to old place of l_text_end in link map This preserves all member offsets and the GLIBC_PRIVATE ABI for backporting. --- include/link.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/link.h b/include/link.h index 81f5715db0..4eb8fe0d96 100644 --- a/include/link.h +++ b/include/link.h @@ -254,6 +254,10 @@ struct link_map need not be the same as l_addr. */ ElfW(Addr) l_map_start, l_map_end; + /* Linked list of objects in reverse ELF constructor execution + order. Head of list is stored in _dl_init_called_list. */ + struct link_map *l_init_called_next; + /* Default array for 'l_scope'. */ struct r_scope_elem *l_scope_mem[4]; /* Size of array allocated for 'l_scope'. */ @@ -276,10 +280,6 @@ struct link_map /* List of object in order of the init and fini calls. */ struct link_map **l_initfini; - /* Linked list of objects in reverse ELF constructor execution - order. Head of list is stored in _dl_init_called_list. */ - struct link_map *l_init_called_next; - /* List of the dependencies introduced through symbol binding. */ struct link_map_reldeps { -- cgit 1.4.1 From 4ea972b7edd7e36610e8cde18bf7a8149d7bac4f Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 13 Sep 2023 14:10:56 +0200 Subject: CVE-2023-4527: Stack read overflow with large TCP responses in no-aaaa mode Without passing alt_dns_packet_buffer, __res_context_search can only store 2048 bytes (what fits into dns_packet_buffer). However, the function returns the total packet size, and the subsequent DNS parsing code in _nss_dns_gethostbyname4_r reads beyond the end of the stack-allocated buffer. Fixes commit f282cdbe7f436c75864e5640a4 ("resolv: Implement no-aaaa stub resolver option") and bug 30842. (cherry picked from commit bd77dd7e73e3530203be1c52c8a29d08270cb25d) --- NEWS | 7 +++ resolv/Makefile | 2 + resolv/nss_dns/dns-host.c | 2 +- resolv/tst-resolv-noaaaa-vc.c | 129 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 resolv/tst-resolv-noaaaa-vc.c diff --git a/NEWS b/NEWS index fd9d34b9b4..c1456869ad 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,12 @@ Security related changes: heap and prints it to the target log file, potentially revealing a portion of the contents of the heap. + CVE-2023-4527: If the system is configured in no-aaaa mode via + /etc/resolv.conf, getaddrinfo is called for the AF_UNSPEC address + family, and a DNS response is received over TCP that is larger than + 2048 bytes, getaddrinfo may potentially disclose stack contents via + the returned address data, or crash. + The following bugs are resolved with this release: [12154] Do not fail DNS resolution for CNAMEs which are not host names @@ -65,6 +71,7 @@ The following bugs are resolved with this release: [30477] libc: [RISCV]: time64 does not work on riscv32 [30515] _dl_find_object incorrectly returns 1 during early startup [30785] Always call destructors in reverse constructor order + [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) Version 2.36 diff --git a/resolv/Makefile b/resolv/Makefile index f8a92c6cff..28cedf49ee 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -101,6 +101,7 @@ tests += \ tst-resolv-invalid-cname \ tst-resolv-network \ tst-resolv-noaaaa \ + tst-resolv-noaaaa-vc \ tst-resolv-nondecimal \ tst-resolv-res_init-multi \ tst-resolv-search \ @@ -291,6 +292,7 @@ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \ $(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \ $(shared-thread-library) $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) +$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 9fa81f23c8..227734da5c 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -427,7 +427,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, { n = __res_context_search (ctx, name, C_IN, T_A, dns_packet_buffer, sizeof (dns_packet_buffer), - NULL, NULL, NULL, NULL, NULL); + &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); if (n >= 0) status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, &abuf, pat, errnop, herrnop, ttlp); diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c new file mode 100644 index 0000000000..9f5aebd99f --- /dev/null +++ b/resolv/tst-resolv-noaaaa-vc.c @@ -0,0 +1,129 @@ +/* Test the RES_NOAAAA resolver option with a large response. + Copyright (C) 2022-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Used to keep track of the number of queries. */ +static volatile unsigned int queries; + +/* If true, add a large TXT record at the start of the answer section. */ +static volatile bool stuff_txt; + +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + /* If not using TCP, just force its use. */ + if (!ctx->tcp) + { + struct resolv_response_flags flags = {.tc = true}; + resolv_response_init (b, flags); + resolv_response_add_question (b, qname, qclass, qtype); + return; + } + + /* The test needs to send four queries, the first three are used to + grow the NSS buffer via the ERANGE handshake. */ + ++queries; + TEST_VERIFY (queries <= 4); + + /* AAAA queries are supposed to be disabled. */ + TEST_COMPARE (qtype, T_A); + TEST_COMPARE (qclass, C_IN); + TEST_COMPARE_STRING (qname, "example.com"); + + struct resolv_response_flags flags = {}; + resolv_response_init (b, flags); + resolv_response_add_question (b, qname, qclass, qtype); + + resolv_response_section (b, ns_s_an); + + if (stuff_txt) + { + resolv_response_open_record (b, qname, qclass, T_TXT, 60); + int zero = 0; + for (int i = 0; i <= 15000; ++i) + resolv_response_add_data (b, &zero, sizeof (zero)); + resolv_response_close_record (b); + } + + for (int i = 0; i < 200; ++i) + { + resolv_response_open_record (b, qname, qclass, qtype, 60); + char ipv4[4] = {192, 0, 2, i + 1}; + resolv_response_add_data (b, &ipv4, sizeof (ipv4)); + resolv_response_close_record (b); + } +} + +static int +do_test (void) +{ + struct resolv_test *obj = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response + }); + + _res.options |= RES_NOAAAA; + + for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt) + { + queries = 0; + stuff_txt = do_stuff_txt; + + struct addrinfo *ai = NULL; + int ret; + ret = getaddrinfo ("example.com", "80", + &(struct addrinfo) + { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + }, &ai); + + char *expected_result; + { + struct xmemstream mem; + xopen_memstream (&mem); + for (int i = 0; i < 200; ++i) + fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1); + xfclose_memstream (&mem); + expected_result = mem.buffer; + } + + check_addrinfo ("example.com", ai, ret, expected_result); + + free (expected_result); + freeaddrinfo (ai); + } + + resolv_test_end (obj); + return 0; +} + +#include -- cgit 1.4.1 From 0ae2afe45ee0e88b37b89399b6a8cf0330f46937 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 28 Aug 2023 23:30:37 +0200 Subject: io: Fix record locking contants for powerpc64 with __USE_FILE_OFFSET64 Commit 5f828ff824e3b7cd1 ("io: Fix F_GETLK, F_SETLK, and F_SETLKW for powerpc64") fixed an issue with the value of the lock constants on powerpc64 when not using __USE_FILE_OFFSET64, but it ended-up also changing the value when using __USE_FILE_OFFSET64 causing an API change. Fix that by also checking that define, restoring the pre 4d0fe291aed3a476a commit values: Default values: - F_GETLK: 5 - F_SETLK: 6 - F_SETLKW: 7 With -D_FILE_OFFSET_BITS=64: - F_GETLK: 12 - F_SETLK: 13 - F_SETLKW: 14 At the same time, it has been noticed that there was no test for io lock with __USE_FILE_OFFSET64, so just add one. Tested on x86_64-linux-gnu, i686-linux-gnu and powerpc64le-unknown-linux-gnu. Resolves: BZ #30804. Co-authored-by: Adhemerval Zanella Signed-off-by: Aurelien Jarno (cherry picked from commit 434bf72a94de68f0cc7fbf3c44bf38c1911b70cb) --- NEWS | 2 ++ io/Makefile | 4 +++- io/tst-fcntl-lock-lfs.c | 2 ++ sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 io/tst-fcntl-lock-lfs.c diff --git a/NEWS b/NEWS index c1456869ad..8923c70820 100644 --- a/NEWS +++ b/NEWS @@ -71,6 +71,8 @@ The following bugs are resolved with this release: [30477] libc: [RISCV]: time64 does not work on riscv32 [30515] _dl_find_object incorrectly returns 1 during early startup [30785] Always call destructors in reverse constructor order + [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with + -D_FILE_OFFSET_BITS=64 [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) Version 2.36 diff --git a/io/Makefile b/io/Makefile index fb363c612c..b896484320 100644 --- a/io/Makefile +++ b/io/Makefile @@ -59,6 +59,7 @@ routines := \ ftw64-time64 \ closefrom close_range + others := pwd test-srcs := ftwtest ftwtest-time64 tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ @@ -81,7 +82,8 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ tst-closefrom \ tst-close_range \ tst-ftw-bz28126 \ - tst-fcntl-lock + tst-fcntl-lock \ + tst-fcntl-lock-lfs tests-time64 := \ tst-fcntl-time64 \ diff --git a/io/tst-fcntl-lock-lfs.c b/io/tst-fcntl-lock-lfs.c new file mode 100644 index 0000000000..f2a909fb02 --- /dev/null +++ b/io/tst-fcntl-lock-lfs.c @@ -0,0 +1,2 @@ +#define _FILE_OFFSET_BITS 64 +#include diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h index 49c8fac0fb..0ca6e69ee9 100644 --- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h +++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h @@ -33,7 +33,7 @@ # define __O_LARGEFILE 0200000 #endif -#if __WORDSIZE == 64 +#if __WORDSIZE == 64 && !defined __USE_FILE_OFFSET64 # define F_GETLK 5 # define F_SETLK 6 # define F_SETLKW 7 -- cgit 1.4.1 From a9728f798ec7f05454c95637ee6581afaa9b487d Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Fri, 15 Sep 2023 13:51:12 -0400 Subject: getaddrinfo: Fix use after free in getcanonname (CVE-2023-4806) When an NSS plugin only implements the _gethostbyname2_r and _getcanonname_r callbacks, getaddrinfo could use memory that was freed during tmpbuf resizing, through h_name in a previous query response. The backing store for res->at->name when doing a query with gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in gethosts during the query. For AF_INET6 lookup with AI_ALL | AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second for a v4 lookup. In this case, if the first call reallocates tmpbuf enough number of times, resulting in a malloc, th->h_name (that res->at->name refers to) ends up on a heap allocated storage in tmpbuf. Now if the second call to gethosts also causes the plugin callback to return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF reference in res->at->name. This then gets dereferenced in the getcanonname_r plugin call, resulting in the use after free. Fix this by copying h_name over and freeing it at the end. This resolves BZ #30843, which is assigned CVE-2023-4806. Signed-off-by: Siddhesh Poyarekar (cherry picked from commit 973fe93a5675c42798b2161c6f29c01b0e243994) --- nss/Makefile | 15 +++++- nss/nss_test_gai_hv2_canonname.c | 56 +++++++++++++++++++ nss/tst-nss-gai-hv2-canonname.c | 63 ++++++++++++++++++++++ nss/tst-nss-gai-hv2-canonname.h | 1 + nss/tst-nss-gai-hv2-canonname.root/postclean.req | 0 .../tst-nss-gai-hv2-canonname.script | 2 + sysdeps/posix/getaddrinfo.c | 25 ++++++--- 7 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 nss/nss_test_gai_hv2_canonname.c create mode 100644 nss/tst-nss-gai-hv2-canonname.c create mode 100644 nss/tst-nss-gai-hv2-canonname.h create mode 100644 nss/tst-nss-gai-hv2-canonname.root/postclean.req create mode 100644 nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script diff --git a/nss/Makefile b/nss/Makefile index a978e3927a..f0af87e6f1 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) @@ -214,3 +224,4 @@ LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags +LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c new file mode 100644 index 0000000000..4439c83c9f --- /dev/null +++ b/nss/nss_test_gai_hv2_canonname.c @@ -0,0 +1,56 @@ +/* NSS service provider that only provides gethostbyname2_r. + Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include "nss/tst-nss-gai-hv2-canonname.h" + +/* Catch misnamed and functions. */ +#pragma GCC diagnostic error "-Wmissing-prototypes" +NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname) + +extern enum nss_status _nss_files_gethostbyname2_r (const char *, int, + struct hostent *, char *, + size_t, int *, int *); + +enum nss_status +_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *herrnop) +{ + return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop, + herrnop); +} + +enum nss_status +_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer, + size_t buflen, char **result, + int *errnop, int *h_errnop) +{ + /* We expect QUERYNAME, which is a small enough string that it shouldn't fail + the test. */ + if (memcmp (QUERYNAME, name, sizeof (QUERYNAME)) + || buflen < sizeof (QUERYNAME)) + abort (); + + strncpy (buffer, name, buflen); + *result = buffer; + return NSS_STATUS_SUCCESS; +} diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c new file mode 100644 index 0000000000..d5f10c07d6 --- /dev/null +++ b/nss/tst-nss-gai-hv2-canonname.c @@ -0,0 +1,63 @@ +/* Test NSS query path for plugins that only implement gethostbyname2 + (#30843). + Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include "nss/tst-nss-gai-hv2-canonname.h" + +#define PREPARE do_prepare + +static void do_prepare (int a, char **av) +{ + FILE *hosts = xfopen ("/etc/hosts", "w"); + for (unsigned i = 2; i < 255; i++) + { + fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i); + fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i); + } + xfclose (hosts); +} + +static int +do_test (void) +{ + __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); + + struct addrinfo hints = {}; + struct addrinfo *result = NULL; + + hints.ai_family = AF_INET6; + hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME; + + int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result); + + if (ret != 0) + FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret)); + + TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME); + + freeaddrinfo(result); + return 0; +} + +#include diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h new file mode 100644 index 0000000000..14f2a9cb08 --- /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 0000000000..e69de29bb2 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 0000000000..31848b4a28 --- /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 5cda9bb072..7a43a3bf4c 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); -- cgit 1.4.1 From 856bac55f98dc840e7c27cfa82262b933385de90 Mon Sep 17 00:00:00 2001 From: Romain Geissler Date: Mon, 25 Sep 2023 01:21:51 +0100 Subject: Fix leak in getaddrinfo introduced by the fix for CVE-2023-4806 [BZ #30843] This patch fixes a very recently added leak in getaddrinfo. This was assigned CVE-2023-5156. Resolves: BZ #30884 Related: BZ #30842 Reviewed-by: Siddhesh Poyarekar (cherry picked from commit ec6b95c3303c700eb89eebeda2d7264cc184a796) --- nss/Makefile | 20 ++++++++++++++++++++ nss/tst-nss-gai-hv2-canonname.c | 3 +++ sysdeps/posix/getaddrinfo.c | 4 +--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/nss/Makefile b/nss/Makefile index f0af87e6f1..7a52c68791 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 d5f10c07d6..7db53cf09d 100644 --- a/nss/tst-nss-gai-hv2-canonname.c +++ b/nss/tst-nss-gai-hv2-canonname.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "nss/tst-nss-gai-hv2-canonname.h" @@ -41,6 +42,8 @@ static void do_prepare (int a, char **av) static int do_test (void) { + mtrace (); + __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); struct addrinfo hints = {}; diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index 7a43a3bf4c..f975dcd2bc 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; } -- cgit 1.4.1 From 32957eb6a86acdbeec9f38a60a7d5a0ff32db03d Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Tue, 26 Sep 2023 07:38:07 -0400 Subject: Document CVE-2023-4806 and CVE-2023-5156 in NEWS These are tracked in BZ #30884 and BZ #30843. Signed-off-by: Siddhesh Poyarekar (cherry picked from commit fd134feba35fa839018965733b34d28a09a075dd) --- NEWS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/NEWS b/NEWS index 8923c70820..ae55ffb53a 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,15 @@ Security related changes: 2048 bytes, getaddrinfo may potentially disclose stack contents via the returned address data, or crash. + CVE-2023-4806: When an NSS plugin only implements the + _gethostbyname2_r and _getcanonname_r callbacks, getaddrinfo could use + memory that was freed during buffer resizing, potentially causing a + crash or read or write to arbitrary memory. + + CVE-2023-5156: The fix for CVE-2023-4806 introduced a memory leak when + an application calls getaddrinfo for AF_INET6 with AI_CANONNAME, + AI_ALL and AI_V4MAPPED flags set. + The following bugs are resolved with this release: [12154] Do not fail DNS resolution for CNAMEs which are not host names -- cgit 1.4.1 From 22955ad85186ee05834e47e665056148ca07699c Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Tue, 19 Sep 2023 18:39:32 -0400 Subject: tunables: Terminate if end of input is reached (CVE-2023-4911) The string parsing routine may end up writing beyond bounds of tunestr if the input tunable string is malformed, of the form name=name=val. This gets processed twice, first as name=name=val and next as name=val, resulting in tunestr being name=name=val:name=val, thus overflowing tunestr. Terminate the parsing loop at the first instance itself so that tunestr does not overflow. This also fixes up tst-env-setuid-tunables to actually handle failures correct and add new tests to validate the fix for this CVE. Signed-off-by: Siddhesh Poyarekar Reviewed-by: Carlos O'Donell (cherry picked from commit 1056e5b4c3f2d90ed2b4a55f96add28da2f4c8fa) --- NEWS | 5 +++++ elf/dl-tunables.c | 17 ++++++++++------- elf/tst-env-setuid-tunables.c | 37 +++++++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index ae55ffb53a..5358e0cbe3 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,11 @@ Security related changes: an application calls getaddrinfo for AF_INET6 with AI_CANONNAME, AI_ALL and AI_V4MAPPED flags set. + CVE-2023-4911: If a tunable of the form NAME=NAME=VAL is passed in the + environment of a setuid program and NAME is valid, it may result in a + buffer overflow, which could be exploited to achieve escalated + privileges. This flaw was introduced in glibc 2.34. + The following bugs are resolved with this release: [12154] Do not fail DNS resolution for CNAMEs which are not host names diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c index 8e7ee9df10..76cf8b9da3 100644 --- a/elf/dl-tunables.c +++ b/elf/dl-tunables.c @@ -187,11 +187,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. */ @@ -251,9 +247,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 88182b7b25..5e9e4c5756 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; } } -- cgit 1.4.1 From ad96b5532570a6782f784b4f2c6aa2a52359144d Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 18 Oct 2023 14:30:00 +0200 Subject: Revert "elf: Remove unused l_text_end field from struct link_map" This reverts commit 9f0d3bb2e325dc30ae20e347cccbe10fa0b4ce9b. Reason for revert: Preserve ABI after revert of commit 5d83a52a4. --- elf/dl-load.c | 2 +- elf/dl-load.h | 7 +++++-- elf/rtld.c | 6 ++++++ elf/setup-vdso.h | 4 ++++ include/link.h | 2 ++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index cb59c21ce7..1ad0868dad 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1263,7 +1263,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, /* Now process the load commands and map segments into memory. This is responsible for filling in: - l_map_start, l_map_end, l_addr, l_contiguous, l_phdr + l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr */ errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, maplength, has_holes, loader); diff --git a/elf/dl-load.h b/elf/dl-load.h index ebf7d74cd0..f98d264e90 100644 --- a/elf/dl-load.h +++ b/elf/dl-load.h @@ -83,11 +83,14 @@ struct loadcmd /* This is a subroutine of _dl_map_segments. It should be called for each load command, some time after L->l_addr has been set correctly. It is - responsible for setting the l_phdr fields */ + responsible for setting up the l_text_end and l_phdr fields. */ static __always_inline void _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header, const struct loadcmd *c) { + if (c->prot & PROT_EXEC) + l->l_text_end = l->l_addr + c->mapend; + if (l->l_phdr == 0 && c->mapoff <= header->e_phoff && ((size_t) (c->mapend - c->mapstart + c->mapoff) @@ -100,7 +103,7 @@ _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header, /* This is a subroutine of _dl_map_object_from_fd. It is responsible for filling in several fields in *L: l_map_start, l_map_end, l_addr, - l_contiguous, l_phdr. On successful return, all the + l_contiguous, l_text_end, l_phdr. On successful return, all the segments are mapped (or copied, or whatever) from the file into their final places in the address space, with the correct page permissions, and any bss-like regions already zeroed. It returns a null pointer diff --git a/elf/rtld.c b/elf/rtld.c index dd45930ff7..3e771a93d8 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -479,6 +479,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) GL(dl_rtld_map).l_real = &GL(dl_rtld_map); GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start; GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end; + GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext; /* Copy the TLS related data if necessary. */ #ifndef DONT_USE_BOOTSTRAP_MAP # if NO_TLS_OFFSET != 0 @@ -1123,6 +1124,7 @@ rtld_setup_main_map (struct link_map *main_map) bool has_interp = false; main_map->l_map_end = 0; + main_map->l_text_end = 0; /* Perhaps the executable has no PT_LOAD header entries at all. */ main_map->l_map_start = ~0; /* And it was opened directly. */ @@ -1214,6 +1216,8 @@ rtld_setup_main_map (struct link_map *main_map) allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz; if (main_map->l_map_end < allocend) main_map->l_map_end = allocend; + if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end) + main_map->l_text_end = allocend; /* The next expected address is the page following this load segment. */ @@ -1273,6 +1277,8 @@ rtld_setup_main_map (struct link_map *main_map) = (char *) main_map->l_tls_initimage + main_map->l_addr; if (! main_map->l_map_end) main_map->l_map_end = ~0; + if (! main_map->l_text_end) + main_map->l_text_end = ~0; if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name) { /* We were invoked directly, so the program might not have a diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h index 415d5057c3..c0807ea82b 100644 --- a/elf/setup-vdso.h +++ b/elf/setup-vdso.h @@ -51,6 +51,9 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), l->l_addr = ph->p_vaddr; if (ph->p_vaddr + ph->p_memsz >= l->l_map_end) l->l_map_end = ph->p_vaddr + ph->p_memsz; + if ((ph->p_flags & PF_X) + && ph->p_vaddr + ph->p_memsz >= l->l_text_end) + l->l_text_end = ph->p_vaddr + ph->p_memsz; } else /* There must be no TLS segment. */ @@ -59,6 +62,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso); l->l_addr = l->l_map_start - l->l_addr; l->l_map_end += l->l_addr; + l->l_text_end += l->l_addr; l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr); elf_get_dynamic_info (l, false, false); _dl_setup_hash (l); diff --git a/include/link.h b/include/link.h index 4eb8fe0d96..8176e23da9 100644 --- a/include/link.h +++ b/include/link.h @@ -253,6 +253,8 @@ struct link_map /* Start and finish of memory map for this object. l_map_start need not be the same as l_addr. */ ElfW(Addr) l_map_start, l_map_end; + /* End of the executable part of the mapping. */ + ElfW(Addr) l_text_end; /* Linked list of objects in reverse ELF constructor execution order. Head of list is stored in _dl_init_called_list. */ -- cgit 1.4.1 From dc3b5b9048d342b5b779683dff018ac3bd14a17b Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 18 Oct 2023 14:31:02 +0200 Subject: Revert "elf: Always call destructors in reverse constructor order (bug 30785)" This reverts commit 5d83a52a4905405792418d6a0f3afa3601a98c37. Reason for revert: Incompatibility with existing applications. --- NEWS | 1 - elf/dl-close.c | 113 ++++++++++++--------------------- elf/dl-fini.c | 152 +++++++++++++++++++++++++++++---------------- elf/dl-init.c | 16 ----- elf/dso-sort-tests-1.def | 19 ++++-- elf/tst-audit23.c | 44 ++++++------- sysdeps/generic/ldsodefs.h | 4 -- 7 files changed, 173 insertions(+), 176 deletions(-) diff --git a/NEWS b/NEWS index 5358e0cbe3..ed72d2f2e6 100644 --- a/NEWS +++ b/NEWS @@ -84,7 +84,6 @@ The following bugs are resolved with this release: [30305] x86_64: Fix asm constraints in feraiseexcept [30477] libc: [RISCV]: time64 does not work on riscv32 [30515] _dl_find_object incorrectly returns 1 during early startup - [30785] Always call destructors in reverse constructor order [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with -D_FILE_OFFSET_BITS=64 [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) diff --git a/elf/dl-close.c b/elf/dl-close.c index 640bbd88c3..14deca2e2b 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -138,31 +138,30 @@ _dl_close_worker (struct link_map *map, bool force) bool any_tls = false; const unsigned int nloaded = ns->_ns_nloaded; + struct link_map *maps[nloaded]; - /* Run over the list and assign indexes to the link maps. */ + /* Run over the list and assign indexes to the link maps and enter + them into the MAPS array. */ int idx = 0; for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next) { l->l_map_used = 0; l->l_map_done = 0; l->l_idx = idx; + maps[idx] = l; ++idx; } assert (idx == nloaded); - /* Keep marking link maps until no new link maps are found. */ - for (struct link_map *l = ns->_ns_loaded; l != NULL; ) + /* Keep track of the lowest index link map we have covered already. */ + int done_index = -1; + while (++done_index < nloaded) { - /* next is reset to earlier link maps for remarking. */ - struct link_map *next = l->l_next; - int next_idx = l->l_idx + 1; /* next->l_idx, but covers next == NULL. */ + struct link_map *l = maps[done_index]; if (l->l_map_done) - { - /* Already handled. */ - l = next; - continue; - } + /* Already handled. */ + continue; /* Check whether this object is still used. */ if (l->l_type == lt_loaded @@ -172,10 +171,7 @@ _dl_close_worker (struct link_map *map, bool force) acquire is sufficient and correct. */ && atomic_load_acquire (&l->l_tls_dtor_count) == 0 && !l->l_map_used) - { - l = next; - continue; - } + continue; /* We need this object and we handle it now. */ l->l_map_used = 1; @@ -202,11 +198,8 @@ _dl_close_worker (struct link_map *map, bool force) already processed it, then we need to go back and process again from that point forward to ensure we keep all of its dependencies also. */ - if ((*lp)->l_idx < next_idx) - { - next = *lp; - next_idx = next->l_idx; - } + if ((*lp)->l_idx - 1 < done_index) + done_index = (*lp)->l_idx - 1; } } @@ -226,65 +219,44 @@ _dl_close_worker (struct link_map *map, bool force) if (!jmap->l_map_used) { jmap->l_map_used = 1; - if (jmap->l_idx < next_idx) - { - next = jmap; - next_idx = next->l_idx; - } + if (jmap->l_idx - 1 < done_index) + done_index = jmap->l_idx - 1; } } } - - l = next; } - /* Call the destructors in reverse constructor order, and remove the - closed link maps from the list. */ - for (struct link_map **init_called_head = &_dl_init_called_list; - *init_called_head != NULL; ) + /* 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); + + /* Call all termination functions at once. */ + bool unload_any = false; + bool scope_mem_left = false; + unsigned int unload_global = 0; + unsigned int first_loaded = ~0; + for (unsigned int i = 0; i < nloaded; ++i) { - struct link_map *imap = *init_called_head; + struct link_map *imap = maps[i]; - /* _dl_init_called_list is global, to produce a global odering. - Ignore the other namespaces (and link maps that are still used). */ - if (imap->l_ns != nsid || imap->l_map_used) - init_called_head = &imap->l_init_called_next; - else + /* All elements must be in the same namespace. */ + assert (imap->l_ns == nsid); + + if (!imap->l_map_used) { assert (imap->l_type == lt_loaded && !imap->l_nodelete_active); - /* _dl_init_called_list is updated at the same time as - l_init_called. */ - assert (imap->l_init_called); - - if (imap->l_info[DT_FINI_ARRAY] != NULL - || imap->l_info[DT_FINI] != NULL) + /* Call its termination function. Do not do it for + half-cooked objects. Temporarily disable exception + handling, so that errors are fatal. */ + if (imap->l_init_called) _dl_catch_exception (NULL, _dl_call_fini, imap); #ifdef SHARED /* Auditing checkpoint: we remove an object. */ _dl_audit_objclose (imap); #endif - /* Unlink this link map. */ - *init_called_head = imap->l_init_called_next; - } - } - - - bool unload_any = false; - bool scope_mem_left = false; - unsigned int unload_global = 0; - - /* For skipping un-unloadable link maps in the second loop. */ - struct link_map *first_loaded = ns->_ns_loaded; - /* Iterate over the namespace to find objects to unload. Some - unloadable objects may not be on _dl_init_called_list due to - dlopen failure. */ - for (struct link_map *imap = first_loaded; imap != NULL; imap = imap->l_next) - { - if (!imap->l_map_used) - { /* This object must not be used anymore. */ imap->l_removed = 1; @@ -295,8 +267,8 @@ _dl_close_worker (struct link_map *map, bool force) ++unload_global; /* Remember where the first dynamically loaded object is. */ - if (first_loaded == NULL) - first_loaded = imap; + if (i < first_loaded) + first_loaded = i; } /* Else imap->l_map_used. */ else if (imap->l_type == lt_loaded) @@ -432,8 +404,8 @@ _dl_close_worker (struct link_map *map, bool force) imap->l_loader = NULL; /* Remember where the first dynamically loaded object is. */ - if (first_loaded == NULL) - first_loaded = imap; + if (i < first_loaded) + first_loaded = i; } } @@ -504,11 +476,10 @@ _dl_close_worker (struct link_map *map, bool force) /* Check each element of the search list to see if all references to it are gone. */ - for (struct link_map *imap = first_loaded; imap != NULL; ) + for (unsigned int i = first_loaded; i < nloaded; ++i) { - if (imap->l_map_used) - imap = imap->l_next; - else + struct link_map *imap = maps[i]; + if (!imap->l_map_used) { assert (imap->l_type == lt_loaded); @@ -719,9 +690,7 @@ _dl_close_worker (struct link_map *map, bool force) if (imap == GL(dl_initfirst)) GL(dl_initfirst) = NULL; - struct link_map *next = imap->l_next; free (imap); - imap = next; } } diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 50087a1bfc..50ff94db16 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -24,68 +24,116 @@ void _dl_fini (void) { - /* Call destructors strictly in the reverse order of constructors. - This causes fewer surprises than some arbitrary reordering based - on new (relocation) dependencies. None of the objects are - unmapped, so applications can deal with this if their DSOs remain - in a consistent state after destructors have run. */ - - /* Protect against concurrent loads and unloads. */ - __rtld_lock_lock_recursive (GL(dl_load_lock)); - - /* Ignore objects which are opened during shutdown. */ - struct link_map *local_init_called_list = _dl_init_called_list; - - for (struct link_map *l = local_init_called_list; l != NULL; - l = l->l_init_called_next) - /* Bump l_direct_opencount of all objects so that they - are not dlclose()ed from underneath us. */ - ++l->l_direct_opencount; - - /* After this point, everything linked from local_init_called_list - cannot be unloaded because of the reference counter update. */ - __rtld_lock_unlock_recursive (GL(dl_load_lock)); - - /* Perform two passes: One for non-audit modules, one for audit - modules. This way, audit modules receive unload notifications - for non-audit objects, and the destructors for audit modules - still run. */ + /* Lots of fun ahead. We have to call the destructors for all still + loaded objects, in all namespaces. The problem is that the ELF + specification now demands that dependencies between the modules + are taken into account. I.e., the destructor for a module is + called before the ones for any of its dependencies. + + To make things more complicated, we cannot simply use the reverse + order of the constructors. Since the user might have loaded objects + using `dlopen' there are possibly several other modules with its + dependencies to be taken into account. Therefore we have to start + determining the order of the modules once again from the beginning. */ + + /* We run the destructors of the main namespaces last. As for the + other namespaces, we pick run the destructors in them in reverse + order of the namespace ID. */ +#ifdef SHARED + int do_audit = 0; + again: +#endif + for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns) + { + /* Protect against concurrent loads and unloads. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); + + unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded; + /* No need to do anything for empty namespaces or those used for + auditing DSOs. */ + if (nloaded == 0 +#ifdef SHARED + || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit +#endif + ) + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + else + { #ifdef SHARED - int last_pass = GLRO(dl_naudit) > 0; - Lmid_t last_ns = -1; - for (int do_audit = 0; do_audit <= last_pass; ++do_audit) + _dl_audit_activity_nsid (ns, LA_ACT_DELETE); #endif - for (struct link_map *l = local_init_called_list; l != NULL; - l = l->l_init_called_next) - { + + /* Now we can allocate an array to hold all the pointers and + copy the pointers in. */ + struct link_map *maps[nloaded]; + + unsigned int i; + struct link_map *l; + assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL); + for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next) + /* Do not handle ld.so in secondary namespaces. */ + if (l == l->l_real) + { + assert (i < nloaded); + + maps[i] = l; + l->l_idx = i; + ++i; + + /* Bump l_direct_opencount of all objects so that they + are not dlclose()ed from underneath us. */ + ++l->l_direct_opencount; + } + assert (ns != LM_ID_BASE || i == nloaded); + assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1); + unsigned int nmaps = i; + + /* Now we have to do the sorting. 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, nmaps, (ns == LM_ID_BASE), true); + + /* We do not rely on the linked list of loaded object anymore + from this point on. We have our own list here (maps). The + various members of this list cannot vanish since the open + count is too high and will be decremented in this loop. So + we release the lock so that some code which might be called + from a destructor can directly or indirectly access the + lock. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + /* 'maps' now contains the objects in the right order. Now + call the destructors. We have to process this array from + the front. */ + for (i = 0; i < nmaps; ++i) + { + struct link_map *l = maps[i]; + + if (l->l_init_called) + { + _dl_call_fini (l); #ifdef SHARED - if (GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing != do_audit) - continue; - - /* Avoid back-to-back calls of _dl_audit_activity_nsid for the - same namespace. */ - if (last_ns != l->l_ns) - { - if (last_ns >= 0) - _dl_audit_activity_nsid (last_ns, LA_ACT_CONSISTENT); - _dl_audit_activity_nsid (l->l_ns, LA_ACT_DELETE); - last_ns = l->l_ns; - } + /* Auditing checkpoint: another object closed. */ + _dl_audit_objclose (l); #endif + } - /* There is no need to re-enable exceptions because _dl_fini - is not called from a context where exceptions are caught. */ - _dl_call_fini (l); + /* Correct the previous increment. */ + --l->l_direct_opencount; + } #ifdef SHARED - /* Auditing checkpoint: another object closed. */ - _dl_audit_objclose (l); + _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT); #endif - } + } + } #ifdef SHARED - if (last_ns >= 0) - _dl_audit_activity_nsid (last_ns, LA_ACT_CONSISTENT); + if (! do_audit && GLRO(dl_naudit) > 0) + { + do_audit = 1; + goto again; + } if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS)) _dl_debug_printf ("\nruntime linker statistics:\n" diff --git a/elf/dl-init.c b/elf/dl-init.c index 77b2edd838..fca8e3a05e 100644 --- a/elf/dl-init.c +++ b/elf/dl-init.c @@ -21,7 +21,6 @@ #include #include -struct link_map *_dl_init_called_list; static void call_init (struct link_map *l, int argc, char **argv, char **env) @@ -43,21 +42,6 @@ call_init (struct link_map *l, int argc, char **argv, char **env) dependency. */ l->l_init_called = 1; - /* Help an already-running dlclose: The just-loaded object must not - be removed during the current pass. (No effect if no dlclose in - progress.) */ - l->l_map_used = 1; - - /* Record execution before starting any initializers. This way, if - the initializers themselves call dlopen, their ELF destructors - will eventually be run before this object is destructed, matching - that their ELF constructors have run before this object was - constructed. _dl_fini uses this list for audit callbacks, so - register objects on the list even if they do not have a - constructor. */ - l->l_init_called_next = _dl_init_called_list; - _dl_init_called_list = l; - /* Check for object which constructors we do not run here. */ if (__builtin_expect (l->l_name[0], 'a') == '\0' && l->l_type == lt_executable) diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def index 61dc54f8ae..4bf9052db1 100644 --- a/elf/dso-sort-tests-1.def +++ b/elf/dso-sort-tests-1.def @@ -53,14 +53,21 @@ tst-dso-ordering10: {}->a->b->c;soname({})=c output: b>a>{}b->c->d order). +# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based +# dynamic_sort=2 algorithm does, although it is still arguable whether going +# beyond spec to do this is the right thing to do. +# The 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: {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[a1;a->a2;a2->a;b->b1;c->a1;c=>a1 -output: {+a[a2>a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());} Date: Thu, 19 Oct 2023 09:29:42 +0200 Subject: Revert "elf: Move l_init_called_next to old place of l_text_end in link map" This reverts commit f441cb9a70fa3f55e9bbd615924879d692d21a6c. Reason for revert: Preserve internal ABI. --- include/link.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/link.h b/include/link.h index 8176e23da9..87966e8397 100644 --- a/include/link.h +++ b/include/link.h @@ -256,10 +256,6 @@ struct link_map /* End of the executable part of the mapping. */ ElfW(Addr) l_text_end; - /* Linked list of objects in reverse ELF constructor execution - order. Head of list is stored in _dl_init_called_list. */ - struct link_map *l_init_called_next; - /* Default array for 'l_scope'. */ struct r_scope_elem *l_scope_mem[4]; /* Size of array allocated for 'l_scope'. */ @@ -282,6 +278,10 @@ struct link_map /* List of object in order of the init and fini calls. */ struct link_map **l_initfini; + /* Linked list of objects in reverse ELF constructor execution + order. Head of list is stored in _dl_init_called_list. */ + struct link_map *l_init_called_next; + /* List of the dependencies introduced through symbol binding. */ struct link_map_reldeps { -- cgit 1.4.1 From 882a991620fcf2ecb3f623e2d29ac551b33bd6ee Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 28 Nov 2023 15:23:07 +0900 Subject: 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 (cherry picked from commit 3921c5b40f293c57cb326f58713c924b0662ef59) --- elf/dl-tls.c | 1 + 1 file changed, 1 insertion(+) diff --git a/elf/dl-tls.c b/elf/dl-tls.c index 093cdddb7e..bf0ff0d9e8 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; } -- cgit 1.4.1 From 6a1168279d770ee9631d8d0409768ac67c96be3c Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 20 Dec 2023 16:31:43 -0800 Subject: x86-64: Fix the dtv field load for x32 [BZ #31184] On x32, I got FAIL: elf/tst-tlsgap $ gdb elf/tst-tlsgap ... open tst-tlsgap-mod1.so Thread 2 "tst-tlsgap" received signal SIGSEGV, Segmentation fault. [Switching to LWP 2268754] _dl_tlsdesc_dynamic () at ../sysdeps/x86_64/dl-tlsdesc.S:108 108 movq (%rsi), %rax (gdb) p/x $rsi $4 = 0xf7dbf9005655fb18 (gdb) This is caused by _dl_tlsdesc_dynamic: _CET_ENDBR /* Preserve call-clobbered registers that we modify. We need two scratch regs anyway. */ movq %rsi, -16(%rsp) movq %fs:DTV_OFFSET, %rsi Since the dtv field in TCB is a pointer, %fs:DTV_OFFSET is a 32-bit location, not 64-bit. Load the dtv field to RSI_LP instead of rsi. This fixes BZ #31184. (cherry picked from commit 3502440397bbb840e2f7223734aa5cc2cc0e29b6) --- NEWS | 1 + sysdeps/x86_64/dl-tlsdesc.S | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ed72d2f2e6..377660ece0 100644 --- a/NEWS +++ b/NEWS @@ -87,6 +87,7 @@ The following bugs are resolved with this release: [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with -D_FILE_OFFSET_BITS=64 [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) + [31184] FAIL: elf/tst-tlsgap Version 2.36 diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S index 0db2cb4152..706856e095 100644 --- a/sysdeps/x86_64/dl-tlsdesc.S +++ b/sysdeps/x86_64/dl-tlsdesc.S @@ -102,7 +102,7 @@ _dl_tlsdesc_dynamic: /* Preserve call-clobbered registers that we modify. We need two scratch regs anyway. */ movq %rsi, -16(%rsp) - movq %fs:DTV_OFFSET, %rsi + mov %fs:DTV_OFFSET, %RSI_LP movq %rdi, -8(%rsp) movq TLSDESC_ARG(%rax), %rdi movq (%rsi), %rax -- cgit 1.4.1 From 5dfafca33cf5db5ca88af43f4f764c29a69aff18 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 20 Dec 2023 19:42:12 -0800 Subject: x86-64: Fix the tcb field load for x32 [BZ #31185] _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic access the thread pointer via the tcb field in TCB: _dl_tlsdesc_undefweak: _CET_ENDBR movq 8(%rax), %rax subq %fs:0, %rax ret _dl_tlsdesc_dynamic: ... subq %fs:0, %rax movq -8(%rsp), %rdi ret Since the tcb field in TCB is a pointer, %fs:0 is a 32-bit location, not 64-bit. It should use "sub %fs:0, %RAX_LP" instead. Since _dl_tlsdesc_undefweak returns ptrdiff_t and _dl_make_tlsdesc_dynamic returns void *, RAX_LP is appropriate here for x32 and x86-64. This fixes BZ #31185. (cherry picked from commit 81be2a61dafc168327c1639e97b6dae128c7ccf3) --- NEWS | 1 + sysdeps/x86_64/dl-tlsdesc.S | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 377660ece0..8ac1be6cb9 100644 --- a/NEWS +++ b/NEWS @@ -88,6 +88,7 @@ The following bugs are resolved with this release: -D_FILE_OFFSET_BITS=64 [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) [31184] FAIL: elf/tst-tlsgap + [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic Version 2.36 diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S index 706856e095..7619e743e1 100644 --- a/sysdeps/x86_64/dl-tlsdesc.S +++ b/sysdeps/x86_64/dl-tlsdesc.S @@ -61,7 +61,7 @@ _dl_tlsdesc_return: _dl_tlsdesc_undefweak: _CET_ENDBR movq 8(%rax), %rax - subq %fs:0, %rax + sub %fs:0, %RAX_LP ret cfi_endproc .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak @@ -116,7 +116,7 @@ _dl_tlsdesc_dynamic: addq TLSDESC_MODOFF(%rdi), %rax .Lret: movq -16(%rsp), %rsi - subq %fs:0, %rax + sub %fs:0, %RAX_LP movq -8(%rsp), %rdi ret .Lslow: -- cgit 1.4.1 From cc5b5da1353e9e4c1486c12befcce9f76ed1e34b Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sat, 23 Dec 2023 06:27:50 -0800 Subject: NEWS: Mention bug fixes for 29039/30745/30843 --- NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 8ac1be6cb9..0f0ebce3f0 100644 --- a/NEWS +++ b/NEWS @@ -48,6 +48,7 @@ The following bugs are resolved with this release: [24816] Fix tst-nss-files-hosts-long on single-stack hosts [27576] gmon: improve mcount overflow handling [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning + [29039] Corrupt DTV after reuse of a TLS module ID following dlclose with unused TLS [29444] gmon: Fix allocated buffer overflow (bug 29444) [29864] libc: __libc_start_main() should obtain program headers address (_dl_phdr) from the auxv, not the ELF header. @@ -84,9 +85,11 @@ The following bugs are resolved with this release: [30305] x86_64: Fix asm constraints in feraiseexcept [30477] libc: [RISCV]: time64 does not work on riscv32 [30515] _dl_find_object incorrectly returns 1 during early startup + [30745] Slight bug in cache info codes for x86 [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with -D_FILE_OFFSET_BITS=64 [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) + [30843] potential use-after-free in getcanonname (CVE-2023-4806) [31184] FAIL: elf/tst-tlsgap [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic -- cgit 1.4.1 From d1a83b6767f68b3cb5b4b4ea2617254acd040c82 Mon Sep 17 00:00:00 2001 From: Arjun Shankar Date: Mon, 15 Jan 2024 17:44:43 +0100 Subject: syslog: Fix heap buffer overflow in __vsyslog_internal (CVE-2023-6246) __vsyslog_internal did not handle a case where printing a SYSLOG_HEADER containing a long program name failed to update the required buffer size, leading to the allocation and overflow of a too-small buffer on the heap. This commit fixes that. It also adds a new regression test that uses glibc.malloc.check. Reviewed-by: Adhemerval Zanella Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit 6bd0e4efcc78f3c0115e5ea9739a1642807450da) --- misc/Makefile | 8 +++- misc/syslog.c | 50 +++++++++++++++++------- misc/tst-syslog-long-progname.c | 39 ++++++++++++++++++ misc/tst-syslog-long-progname.root/postclean.req | 0 4 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 misc/tst-syslog-long-progname.c create mode 100644 misc/tst-syslog-long-progname.root/postclean.req diff --git a/misc/Makefile b/misc/Makefile index ba8232a0e9..66e9ded8f9 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -115,7 +115,10 @@ tests-special += $(objpfx)tst-error1-mem.out \ $(objpfx)tst-allocate_once-mem.out endif -tests-container := tst-syslog +tests-container := \ + tst-syslog \ + tst-syslog-long-progname \ + # tests-container CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables CFLAGS-tsearch.c += $(uses-callbacks) @@ -175,6 +178,9 @@ $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \ $(evaluate-test) +tst-syslog-long-progname-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \ + LD_PRELOAD=libc_malloc_debug.so.0 + $(objpfx)tst-select: $(librt) $(objpfx)tst-select-time64: $(librt) $(objpfx)tst-pselect: $(librt) diff --git a/misc/syslog.c b/misc/syslog.c index f67d4b58a4..fe1daf988b 100644 --- a/misc/syslog.c +++ b/misc/syslog.c @@ -122,8 +122,9 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, { /* Try to use a static buffer as an optimization. */ char bufs[1024]; - char *buf = NULL; - size_t bufsize = 0; + char *buf = bufs; + size_t bufsize; + int msgoff; int saved_errno = errno; @@ -175,29 +176,50 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, #define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \ "<%d>: %n", __pri, __msgoff - int l; + int l, vl; if (has_ts) l = __snprintf (bufs, sizeof bufs, SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); else l = __snprintf (bufs, sizeof bufs, SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); + + char *pos; + size_t len; + if (0 <= l && l < sizeof bufs) { - va_list apc; - va_copy (apc, ap); + /* At this point, there is still a chance that we can print the + remaining part of the log into bufs and use that. */ + pos = bufs + l; + len = sizeof (bufs) - l; + } + else + { + buf = NULL; + /* We already know that bufs is too small to use for this log message. + The next vsnprintf into bufs is used only to calculate the total + required buffer length. We will discard bufs contents and allocate + an appropriately sized buffer later instead. */ + pos = bufs; + len = sizeof (bufs); + } - /* Restore errno for %m format. */ - __set_errno (saved_errno); + { + va_list apc; + va_copy (apc, ap); - int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc, - mode_flags); - if (0 <= vl && vl < sizeof bufs - l) - buf = bufs; - bufsize = l + vl; + /* Restore errno for %m format. */ + __set_errno (saved_errno); - va_end (apc); - } + vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); + + if (!(0 <= vl && vl < len)) + buf = NULL; + + bufsize = l + vl; + va_end (apc); + } if (buf == NULL) { diff --git a/misc/tst-syslog-long-progname.c b/misc/tst-syslog-long-progname.c new file mode 100644 index 0000000000..88f37a8a00 --- /dev/null +++ b/misc/tst-syslog-long-progname.c @@ -0,0 +1,39 @@ +/* Test heap buffer overflow in syslog with long __progname (CVE-2023-6246) + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +extern char * __progname; + +static int +do_test (void) +{ + char long_progname[2048]; + + memset (long_progname, 'X', sizeof (long_progname) - 1); + long_progname[sizeof (long_progname) - 1] = '\0'; + + __progname = long_progname; + + syslog (LOG_INFO, "Hello, World!"); + + return 0; +} + +#include diff --git a/misc/tst-syslog-long-progname.root/postclean.req b/misc/tst-syslog-long-progname.root/postclean.req new file mode 100644 index 0000000000..e69de29bb2 -- cgit 1.4.1 From 2bc9d7c002bdac38b5c2a3f11b78e309d7765b83 Mon Sep 17 00:00:00 2001 From: Arjun Shankar Date: Mon, 15 Jan 2024 17:44:44 +0100 Subject: syslog: Fix heap buffer overflow in __vsyslog_internal (CVE-2023-6779) __vsyslog_internal used the return value of snprintf/vsnprintf to calculate buffer sizes for memory allocation. If these functions (for any reason) failed and returned -1, the resulting buffer would be too small to hold output. This commit fixes that. All snprintf/vsnprintf calls are checked for negative return values and the function silently returns upon encountering them. Reviewed-by: Carlos O'Donell (cherry picked from commit 7e5a0c286da33159d47d0122007aac016f3e02cd) --- misc/syslog.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/misc/syslog.c b/misc/syslog.c index fe1daf988b..3108ae9134 100644 --- a/misc/syslog.c +++ b/misc/syslog.c @@ -183,11 +183,13 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, else l = __snprintf (bufs, sizeof bufs, SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); + if (l < 0) + goto out; char *pos; size_t len; - if (0 <= l && l < sizeof bufs) + if (l < sizeof bufs) { /* At this point, there is still a chance that we can print the remaining part of the log into bufs and use that. */ @@ -213,12 +215,15 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, __set_errno (saved_errno); vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); + va_end (apc); + + if (vl < 0) + goto out; - if (!(0 <= vl && vl < len)) + if (vl >= len) buf = NULL; bufsize = l + vl; - va_end (apc); } if (buf == NULL) @@ -229,25 +234,37 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, /* Tell the cancellation handler to free this buffer. */ clarg.buf = buf; + int cl; if (has_ts) - __snprintf (buf, l + 1, - SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); + cl = __snprintf (buf, l + 1, + SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); else - __snprintf (buf, l + 1, - SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); + cl = __snprintf (buf, l + 1, + SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); + if (cl != l) + goto out; va_list apc; va_copy (apc, ap); - __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, - mode_flags); + cl = __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, + mode_flags); va_end (apc); + + if (cl != vl) + goto out; } else { + int bl; /* Nothing much to do but emit an error message. */ - bufsize = __snprintf (bufs, sizeof bufs, - "out of memory[%d]", __getpid ()); + bl = __snprintf (bufs, sizeof bufs, + "out of memory[%d]", __getpid ()); + if (bl < 0 || bl >= sizeof bufs) + goto out; + + bufsize = bl; buf = bufs; + msgoff = 0; } } -- cgit 1.4.1 From b9b7d6a27aa0632f334352fa400771115b3c69b7 Mon Sep 17 00:00:00 2001 From: Arjun Shankar Date: Mon, 15 Jan 2024 17:44:45 +0100 Subject: syslog: Fix integer overflow in __vsyslog_internal (CVE-2023-6780) __vsyslog_internal calculated a buffer size by adding two integers, but did not first check if the addition would overflow. This commit fixes that. Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit ddf542da94caf97ff43cc2875c88749880b7259b) --- misc/syslog.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/misc/syslog.c b/misc/syslog.c index 3108ae9134..9336036666 100644 --- a/misc/syslog.c +++ b/misc/syslog.c @@ -41,6 +41,7 @@ static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94"; #include #include #include +#include static int LogType = SOCK_DGRAM; /* type of socket connection */ static int LogFile = -1; /* fd for log */ @@ -217,7 +218,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); va_end (apc); - if (vl < 0) + if (vl < 0 || vl >= INT_MAX - l) goto out; if (vl >= len) -- cgit 1.4.1 From c54d08756c052a744cef0be84621197e1a436f6d Mon Sep 17 00:00:00 2001 From: Sunil K Pandey Date: Wed, 26 Jul 2023 08:34:05 -0700 Subject: x86_64: Optimize ffsll function code size. Ffsll function randomly regress by ~20%, depending on how code gets aligned in memory. Ffsll function code size is 17 bytes. Since default function alignment is 16 bytes, it can load on 16, 32, 48 or 64 bytes aligned memory. When ffsll function load at 16, 32 or 64 bytes aligned memory, entire code fits in single 64 bytes cache line. When ffsll function load at 48 bytes aligned memory, it splits in two cache line, hence random regression. Ffsll function size reduction from 17 bytes to 12 bytes ensures that it will always fit in single 64 bytes cache line. This patch fixes ffsll function random performance regression. Reviewed-by: Carlos O'Donell (cherry picked from commit 9d94997b5f9445afd4f2bccc5fa60ff7c4361ec1) --- sysdeps/x86_64/ffsll.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sysdeps/x86_64/ffsll.c b/sysdeps/x86_64/ffsll.c index 842ebaeb4c..d352866d9f 100644 --- a/sysdeps/x86_64/ffsll.c +++ b/sysdeps/x86_64/ffsll.c @@ -26,13 +26,13 @@ int ffsll (long long int x) { long long int cnt; - long long int tmp; - asm ("bsfq %2,%0\n" /* Count low bits in X and store in %1. */ - "cmoveq %1,%0\n" /* If number was zero, use -1 as result. */ - : "=&r" (cnt), "=r" (tmp) : "rm" (x), "1" (-1)); + asm ("mov $-1,%k0\n" /* Initialize cnt to -1. */ + "bsf %1,%0\n" /* Count low bits in x and store in cnt. */ + "inc %k0\n" /* Increment cnt by 1. */ + : "=&r" (cnt) : "r" (x)); - return cnt + 1; + return cnt; } #ifndef __ILP32__ -- cgit 1.4.1 From d5e88bbf596206ae8f24be90c078f08ca479d596 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Wed, 15 Nov 2023 13:29:43 +0100 Subject: sparc: Fix broken memset for sparc32 [BZ #31068] Fixes commit a61933fe27df ("sparc: Remove bzero optimization") that after moving code jumped to the wrong label 4. Verfied by successfully running string/test-memset on sparc32. Signed-off-by: Andreas Larsson Signed-off-by: Ludwig Rydberg Reviewed-by: Adhemerval Zanella (cherry picked from commit 578190b7e43305141512dee777e4a3b3e8159393) --- sysdeps/sparc/sparc32/memset.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sysdeps/sparc/sparc32/memset.S b/sysdeps/sparc/sparc32/memset.S index b1b67cb2d1..5154263317 100644 --- a/sysdeps/sparc/sparc32/memset.S +++ b/sysdeps/sparc/sparc32/memset.S @@ -55,7 +55,7 @@ ENTRY(memset) andcc %o0, 3, %o2 bne 3f -4: andcc %o0, 4, %g0 +5: andcc %o0, 4, %g0 be 2f mov %g3, %g2 @@ -139,7 +139,7 @@ ENTRY(memset) stb %g3, [%o0 + 0x02] 2: sub %o2, 4, %o2 add %o1, %o2, %o1 - b 4b + b 5b sub %o0, %o2, %o0 END(memset) libc_hidden_builtin_def (memset) -- cgit 1.4.1 From b233c4496445f4cfe343ed2d3079a427511a14c8 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 17 Jan 2024 10:38:09 -0300 Subject: sparc64: Remove unwind information from signal return stubs [BZ#31244] Similar to sparc32 fix, remove the unwind information on the signal return stubs. This fixes the regressions: FAIL: nptl/tst-cancel24-static FAIL: nptl/tst-cond8-static FAIL: nptl/tst-mutex8-static FAIL: nptl/tst-mutexpi8-static FAIL: nptl/tst-mutexpi9 On sparc64-linux-gnu. (cherry picked from commit 369efd817780276dbe0ecf8be6e1f354bdbc9857) --- sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S b/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S index ac6af95e36..23b8b93f56 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S @@ -23,7 +23,10 @@ [1] https://lkml.org/lkml/2016/5/27/465 */ -ENTRY (__rt_sigreturn_stub) + nop + nop + +ENTRY_NOCFI (__rt_sigreturn_stub) mov __NR_rt_sigreturn, %g1 ta 0x6d -END (__rt_sigreturn_stub) +END_NOCFI (__rt_sigreturn_stub) -- cgit 1.4.1 From f4171ba5e5a772217ed0ebb80701fe1698407252 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Thu, 18 Jan 2024 10:52:18 -0300 Subject: sparc: Fix sparc64 memmove length comparison (BZ 31266) The small counts copy bytes comparsion should be unsigned (as the memmove size argument). It fixes string/tst-memmove-overflow on sparcv9, where the input size triggers an invalid code path. Checked on sparc64-linux-gnu and sparcv9-linux-gnu. (cherry picked from commit 926a4bdbb5fc8955570208b5571b2d04c6ffbd1d) --- sysdeps/sparc/sparc64/memmove.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysdeps/sparc/sparc64/memmove.S b/sysdeps/sparc/sparc64/memmove.S index 8d46f2cd4e..7746684160 100644 --- a/sysdeps/sparc/sparc64/memmove.S +++ b/sysdeps/sparc/sparc64/memmove.S @@ -38,7 +38,7 @@ ENTRY(memmove) /* * normal, copy forwards */ -2: ble %XCC, .Ldbytecp +2: bleu %XCC, .Ldbytecp andcc %o1, 3, %o5 /* is src word aligned */ bz,pn %icc, .Laldst cmp %o5, 2 /* is src half-word aligned */ -- cgit 1.4.1 From 2853e541c58af1f5d868c4161ea9562e7876a989 Mon Sep 17 00:00:00 2001 From: Daniel Cederman Date: Tue, 16 Jan 2024 09:31:41 +0100 Subject: sparc: Remove unwind information from signal return stubs [BZ #31244] The functions were previously written in C, but were not compiled with unwind information. The ENTRY/END macros includes .cfi_startproc and .cfi_endproc which adds unwind information. This caused the tests cleanup-8 and cleanup-10 in the GCC testsuite to fail. This patch adds a version of the ENTRY/END macros without the CFI instructions that can be used instead. sigaction registers a restorer address that is located two instructions before the stub function. This patch adds a two instruction padding to avoid that the unwinder accesses the unwind information from the function that the linker has placed right before it in memory. This fixes an issue with pthread_cancel that caused tst-mutex8-static (and other tests) to fail. Signed-off-by: Daniel Cederman Reviewed-by: Adhemerval Zanella (cherry picked from commit 7bd06985c0a143cdcba2762bfe020e53514a53de) --- sysdeps/sparc/sysdep.h | 9 +++++++++ sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S | 11 +++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/sysdeps/sparc/sysdep.h b/sysdeps/sparc/sysdep.h index 95068071cc..baab6817a6 100644 --- a/sysdeps/sparc/sysdep.h +++ b/sysdeps/sparc/sysdep.h @@ -76,6 +76,15 @@ C_LABEL(name) \ cfi_endproc; \ .size name, . - name +#define ENTRY_NOCFI(name) \ + .align 4; \ + .global C_SYMBOL_NAME(name); \ + .type name, @function; \ +C_LABEL(name) + +#define END_NOCFI(name) \ + .size name, . - name + #undef LOC #define LOC(name) .L##name diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S b/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S index 2829e881eb..a1492ea59e 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S @@ -23,12 +23,15 @@ [1] https://lkml.org/lkml/2016/5/27/465 */ -ENTRY (__rt_sigreturn_stub) + nop + nop + +ENTRY_NOCFI (__rt_sigreturn_stub) mov __NR_rt_sigreturn, %g1 ta 0x10 -END (__rt_sigreturn_stub) +END_NOCFI (__rt_sigreturn_stub) -ENTRY (__sigreturn_stub) +ENTRY_NOCFI (__sigreturn_stub) mov __NR_sigreturn, %g1 ta 0x10 -END (__sigreturn_stub) +END_NOCFI (__sigreturn_stub) -- cgit 1.4.1 From ec6aaab3e1d754a1ad762f9e9ca4e2525ce87ad3 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Mon, 5 Feb 2024 16:10:24 +0000 Subject: arm: Remove wrong ldr from _dl_start_user (BZ 31339) The commit 49d877a80b29d3002887b084eec6676d9f5fec18 (arm: Remove _dl_skip_args usage) removed the _SKIP_ARGS literal, which was previously loader to r4 on loader _start. However, the cleanup did not remove the following 'ldr r4, [sl, r4]' on _dl_start_user, used to check to skip the arguments after ld self-relocations. In my testing, the kernel initially set r4 to 0, which makes the ldr instruction just read the _GLOBAL_OFFSET_TABLE_. However, since r4 is a callee-saved register; a different runtime might not zero initialize it and thus trigger an invalid memory access. Checked on arm-linux-gnu. Reported-by: Adrian Ratiu Reviewed-by: Szabolcs Nagy (cherry picked from commit 1e25112dc0cb2515d27d8d178b1ecce778a9d37a) --- sysdeps/arm/dl-machine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h index 6a422713bd..659c6f16da 100644 --- a/sysdeps/arm/dl-machine.h +++ b/sysdeps/arm/dl-machine.h @@ -137,7 +137,6 @@ _start:\n\ _dl_start_user:\n\ adr r6, .L_GET_GOT\n\ add sl, sl, r6\n\ - ldr r4, [sl, r4]\n\ @ save the entry point in another register\n\ mov r6, r0\n\ @ get the original arg count\n\ -- cgit 1.4.1 From 8e99cc76a26a88589aaa4e54c1ae48fa27be26b7 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 11 Oct 2023 13:43:56 -0300 Subject: malloc: Use __get_nprocs on arena_get2 (BZ 30945) This restore the 2.33 semantic for arena_get2. It was changed by 11a02b035b46 to avoid arena_get2 call malloc (back when __get_nproc was refactored to use an scratch_buffer - 903bc7dcc2acafc). The __get_nproc was refactored over then and now it also avoid to call malloc. The 11a02b035b46 did not take in consideration any performance implication, which should have been discussed properly. The __get_nprocs_sched is still used as a fallback mechanism if procfs and sysfs is not acessible. Checked on x86_64-linux-gnu. Reviewed-by: DJ Delorie (cherry picked from commit 472894d2cfee5751b44c0aaa71ed87df81c8e62e) --- include/sys/sysinfo.h | 4 ---- malloc/arena.c | 2 +- misc/getsysstats.c | 6 ------ sysdeps/mach/getsysstats.c | 6 ------ sysdeps/unix/sysv/linux/getsysstats.c | 2 +- 5 files changed, 2 insertions(+), 18 deletions(-) diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h index c490561581..65742b1036 100644 --- a/include/sys/sysinfo.h +++ b/include/sys/sysinfo.h @@ -14,10 +14,6 @@ libc_hidden_proto (__get_nprocs_conf) extern int __get_nprocs (void); libc_hidden_proto (__get_nprocs) -/* Return the number of available processors which the process can - be scheduled. */ -extern int __get_nprocs_sched (void) attribute_hidden; - /* Return number of physical pages of memory in the system. */ extern long int __get_phys_pages (void); libc_hidden_proto (__get_phys_pages) diff --git a/malloc/arena.c b/malloc/arena.c index 0a684a720d..a1ee7928d3 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -937,7 +937,7 @@ arena_get2 (size_t size, mstate avoid_arena) narenas_limit = mp_.arena_max; else if (narenas > mp_.arena_test) { - int n = __get_nprocs_sched (); + int n = __get_nprocs (); if (n >= 1) narenas_limit = NARENAS_FROM_NCORES (n); diff --git a/misc/getsysstats.c b/misc/getsysstats.c index e56aff0f37..660f64eb80 100644 --- a/misc/getsysstats.c +++ b/misc/getsysstats.c @@ -44,12 +44,6 @@ weak_alias (__get_nprocs, get_nprocs) link_warning (get_nprocs, "warning: get_nprocs will always return 1") -int -__get_nprocs_sched (void) -{ - return 1; -} - long int __get_phys_pages (void) { diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c index 37ea5e6a7a..80ea7e17cb 100644 --- a/sysdeps/mach/getsysstats.c +++ b/sysdeps/mach/getsysstats.c @@ -62,12 +62,6 @@ __get_nprocs (void) libc_hidden_def (__get_nprocs) weak_alias (__get_nprocs, get_nprocs) -int -__get_nprocs_sched (void) -{ - return __get_nprocs (); -} - /* Return the number of physical pages on the system. */ long int __get_phys_pages (void) diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c index 064eaa08ae..4d01786120 100644 --- a/sysdeps/unix/sysv/linux/getsysstats.c +++ b/sysdeps/unix/sysv/linux/getsysstats.c @@ -29,7 +29,7 @@ #include #include -int +static int __get_nprocs_sched (void) { enum -- cgit 1.4.1 From 4d4ba8bae4bac5e0fd266c22517a3f16a1006bbe Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 28 Feb 2023 10:37:18 -0300 Subject: support: use 64-bit time_t (bug 30111) Ensure to use 64-bit time_t in the test infrastructure. (cherry picked from commit 3bfdc4e2bceb601b90c81a9baa73c1904db58b2f) --- support/Makefile | 18 ++++++++++++++++++ support/shell-container.c | 2 -- support/support_can_chroot.c | 4 ++-- support/support_copy_file.c | 2 +- support/support_descriptor_supports_holes.c | 2 +- support/test-container.c | 2 -- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/support/Makefile b/support/Makefile index 2b661a7eb8..75b96c35f5 100644 --- a/support/Makefile +++ b/support/Makefile @@ -239,6 +239,24 @@ CFLAGS-support_paths.c = \ CFLAGS-timespec.c += -fexcess-precision=standard CFLAGS-timespec-time64.c += -fexcess-precision=standard +# Ensure that general support files use 64-bit time_t +CFLAGS-delayed_exit.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-shell-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_can_chroot.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_copy_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_copy_file_range.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_descriptor_supports_holes.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_descriptors.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_process_state.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_stat_nanoseconds.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_subprocess.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-support_test_main.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-test-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +CFLAGS-xmkdirp.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 +# This is required to get an mkstemp which can create large files on some +# 32-bit platforms. +CFLAGS-temp_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 + ifeq (,$(CXX)) LINKS_DSO_PROGRAM = links-dso-program-c else diff --git a/support/shell-container.c b/support/shell-container.c index 6698061b9b..019a6c47d1 100644 --- a/support/shell-container.c +++ b/support/shell-container.c @@ -16,8 +16,6 @@ License along with the GNU C Library; if not, see . */ -#define _FILE_OFFSET_BITS 64 - #include #include #include diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c index ca0e5f7ef4..43979f7c3f 100644 --- a/support/support_can_chroot.c +++ b/support/support_can_chroot.c @@ -29,14 +29,14 @@ static void callback (void *closure) { int *result = closure; - struct stat64 before; + struct stat before; xstat ("/dev", &before); if (chroot ("/dev") != 0) { *result = errno; return; } - struct stat64 after; + struct stat after; xstat ("/", &after); TEST_VERIFY (before.st_dev == after.st_dev); TEST_VERIFY (before.st_ino == after.st_ino); diff --git a/support/support_copy_file.c b/support/support_copy_file.c index 9a936b37c7..52ed90fae0 100644 --- a/support/support_copy_file.c +++ b/support/support_copy_file.c @@ -24,7 +24,7 @@ void support_copy_file (const char *from, const char *to) { - struct stat64 st; + struct stat st; xstat (from, &st); int fd_from = xopen (from, O_RDONLY, 0); mode_t mode = st.st_mode & 0777; diff --git a/support/support_descriptor_supports_holes.c b/support/support_descriptor_supports_holes.c index d9bcade1cf..83f02f7cf6 100644 --- a/support/support_descriptor_supports_holes.c +++ b/support/support_descriptor_supports_holes.c @@ -40,7 +40,7 @@ support_descriptor_supports_holes (int fd) block_headroom = 32, }; - struct stat64 st; + struct stat st; xfstat (fd, &st); if (!S_ISREG (st.st_mode)) FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd); diff --git a/support/test-container.c b/support/test-container.c index b6a1158ae1..2033985a67 100644 --- a/support/test-container.c +++ b/support/test-container.c @@ -16,8 +16,6 @@ License along with the GNU C Library; if not, see . */ -#define _FILE_OFFSET_BITS 64 - #include #include #include -- cgit 1.4.1 From e24f8e6b35ee0242312cb0f1a9fb5a76403e724e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 19 Jul 2023 14:09:26 -0700 Subject: make ‘struct pthread’ a complete type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nptl/descr.h (struct pthread): Remove end_padding member, which made this type incomplete. (PTHREAD_STRUCT_END_PADDING): Stop using end_padding. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 3edc4ff2ceff4a59587ebecb94148d3bcfa1df62) --- nptl/descr.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nptl/descr.h b/nptl/descr.h index 5cacb286f3..70cf4b639a 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -405,11 +405,11 @@ struct pthread /* rseq area registered with the kernel. */ struct rseq rseq_area; - /* This member must be last. */ - char end_padding[]; - + /* Amount of end padding, if any, in this structure. + This definition relies on rseq_area being last. */ #define PTHREAD_STRUCT_END_PADDING \ - (sizeof (struct pthread) - offsetof (struct pthread, end_padding)) + (sizeof (struct pthread) - offsetof (struct pthread, rseq_area) \ + + sizeof (struct rseq)) } __attribute ((aligned (TCB_ALIGNMENT))); static inline bool -- cgit 1.4.1 From 54e812100df2a6f1d75fbef4e3b45c076599842f Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 21 Jul 2023 16:18:18 +0200 Subject: nptl: Unconditionally use a 32-byte rseq area If the kernel headers provide a larger struct rseq, we used that size as the argument to the rseq system call. As a result, rseq registration would fail on older kernels which only accept size 32. (cherry picked from commit 2c6b4b272e6b4d07303af25709051c3e96288f2d) --- nptl/descr.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/nptl/descr.h b/nptl/descr.h index 70cf4b639a..ff634dac33 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #ifndef TCB_ALIGNMENT @@ -402,14 +401,25 @@ struct pthread /* Used on strsignal. */ struct tls_internal_t tls_state; - /* rseq area registered with the kernel. */ - struct rseq rseq_area; + /* rseq area registered with the kernel. Use a custom definition + here to isolate from kernel struct rseq changes. The + implementation of sched_getcpu needs acccess to the cpu_id field; + the other fields are unused and not included here. */ + union + { + struct + { + uint32_t cpu_id_start; + uint32_t cpu_id; + }; + char pad[32]; /* Original rseq area size. */ + } rseq_area __attribute__ ((aligned (32))); /* Amount of end padding, if any, in this structure. This definition relies on rseq_area being last. */ #define PTHREAD_STRUCT_END_PADDING \ (sizeof (struct pthread) - offsetof (struct pthread, rseq_area) \ - + sizeof (struct rseq)) + + sizeof ((struct pthread) {}.rseq_area)) } __attribute ((aligned (TCB_ALIGNMENT))); static inline bool -- cgit 1.4.1 From b204650058ac29a3f6fcb710b09af4994fc09d9d Mon Sep 17 00:00:00 2001 From: Stefan Liebler Date: Tue, 25 Jul 2023 11:34:30 +0200 Subject: Include sys/rseq.h in tst-rseq-disable.c Starting with commit 2c6b4b272e6b4d07303af25709051c3e96288f2d "nptl: Unconditionally use a 32-byte rseq area", the testcase misc/tst-rseq-disable is UNSUPPORTED as RSEQ_SIG is not defined. The mentioned commit removes inclusion of sys/rseq.h in nptl/descr.h. Thus just include sys/rseq.h in the tst-rseq-disable.c as also done in tst-rseq.c and tst-rseq-nptl.c. Reviewed-by: Florian Weimer (cherry picked from commit 637aac2ae3980de31a6baab236a9255fe853cc76) --- sysdeps/unix/sysv/linux/tst-rseq-disable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sysdeps/unix/sysv/linux/tst-rseq-disable.c b/sysdeps/unix/sysv/linux/tst-rseq-disable.c index e1a2c02f78..a46b0d0562 100644 --- a/sysdeps/unix/sysv/linux/tst-rseq-disable.c +++ b/sysdeps/unix/sysv/linux/tst-rseq-disable.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #ifdef RSEQ_SIG -- cgit 1.4.1 From 1b85f77f43c8e352d6aac7835eedf654c5d9242b Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 15 Mar 2024 19:08:24 +0100 Subject: linux: Use rseq area unconditionally in sched_getcpu (bug 31479) Originally, nptl/descr.h included , but we removed that in commit 2c6b4b272e6b4d07303af25709051c3e96288f2d ("nptl: Unconditionally use a 32-byte rseq area"). After that, it was not ensured that the RSEQ_SIG macro was defined during sched_getcpu.c compilation that provided a definition. This commit always checks the rseq area for CPU number information before using the other approaches. This adds an unnecessary (but well-predictable) branch on architectures which do not define RSEQ_SIG, but its cost is small compared to the system call. Most architectures that have vDSO acceleration for getcpu also have rseq support. Fixes: 2c6b4b272e6b4d07303af25709051c3e96288f2d Fixes: 1d350aa06091211863e41169729cee1bca39f72f Reviewed-by: Arjun Shankar (cherry picked from commit 7a76f218677d149d8b7875b336722108239f7ee9) Fixes: 54e812100df2a6f1d75fbef4e3b45c076599842f --- sysdeps/unix/sysv/linux/sched_getcpu.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sysdeps/unix/sysv/linux/sched_getcpu.c b/sysdeps/unix/sysv/linux/sched_getcpu.c index 5c3301004c..3a2f712386 100644 --- a/sysdeps/unix/sysv/linux/sched_getcpu.c +++ b/sysdeps/unix/sysv/linux/sched_getcpu.c @@ -33,17 +33,9 @@ vsyscall_sched_getcpu (void) return r == -1 ? r : cpu; } -#ifdef RSEQ_SIG int sched_getcpu (void) { int cpu_id = THREAD_GETMEM_VOLATILE (THREAD_SELF, rseq_area.cpu_id); return __glibc_likely (cpu_id >= 0) ? cpu_id : vsyscall_sched_getcpu (); } -#else /* RSEQ_SIG */ -int -sched_getcpu (void) -{ - return vsyscall_sched_getcpu (); -} -#endif /* RSEQ_SIG */ -- cgit 1.4.1 From c21dfb30188557fb39c8016a60cc88b3b87f3f55 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Thu, 11 Aug 2022 17:52:00 +0100 Subject: AArch64: Fix typo in sve configure check (BZ# 29394) Fix a typo in the SVE configure check. This fixes [BZ# 29394]. (cherry picked from commit 12182ba18dabda791a4f63a11ee2e9d828f40f9b) --- sysdeps/aarch64/configure | 6 +++--- sysdeps/aarch64/configure.ac | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure index bf972122b1..2130f6b8f8 100644 --- a/sysdeps/aarch64/configure +++ b/sysdeps/aarch64/configure @@ -303,7 +303,7 @@ aarch64-variant-pcs = $libc_cv_aarch64_variant_pcs" # Check if asm support armv8.2-a+sve { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SVE support in assembler" >&5 $as_echo_n "checking for SVE support in assembler... " >&6; } -if ${libc_cv_asm_sve+:} false; then : +if ${libc_cv_aarch64_sve_asm+:} false; then : $as_echo_n "(cached) " >&6 else cat > conftest.s <<\EOF @@ -321,8 +321,8 @@ else fi rm -f conftest* fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_sve" >&5 -$as_echo "$libc_cv_asm_sve" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aarch64_sve_asm" >&5 +$as_echo "$libc_cv_aarch64_sve_asm" >&6; } if test $libc_cv_aarch64_sve_asm = yes; then $as_echo "#define HAVE_AARCH64_SVE_ASM 1" >>confdefs.h diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac index 51253d9802..85c6f76508 100644 --- a/sysdeps/aarch64/configure.ac +++ b/sysdeps/aarch64/configure.ac @@ -88,7 +88,7 @@ EOF LIBC_CONFIG_VAR([aarch64-variant-pcs], [$libc_cv_aarch64_variant_pcs]) # Check if asm support armv8.2-a+sve -AC_CACHE_CHECK(for SVE support in assembler, libc_cv_asm_sve, [dnl +AC_CACHE_CHECK([for SVE support in assembler], [libc_cv_aarch64_sve_asm], [dnl cat > conftest.s <<\EOF ptrue p0.b EOF -- cgit 1.4.1 From 9627bbbc1c06dbc7d24f61639488d4146082a951 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 26 Oct 2022 14:12:55 +0100 Subject: aarch64: Cleanup memset ifunc Cleanup memset ifunc selectors. The A64FX memset relies on a ZVA size of 256, so add an explicit check. (cherry picked from commit a8e72913fea0c6e2832c50523c60907ffa3b753b) --- sysdeps/aarch64/multiarch/ifunc-impl-list.c | 2 +- sysdeps/aarch64/multiarch/memset.c | 41 ++++++++++++++++++----------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c index 4144615ab2..c6fe149a7c 100644 --- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c +++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c @@ -60,7 +60,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_emag) IFUNC_IMPL_ADD (array, i, memset, 1, __memset_kunpeng) #if HAVE_AARCH64_SVE_ASM - IFUNC_IMPL_ADD (array, i, memset, sve, __memset_a64fx) + IFUNC_IMPL_ADD (array, i, memset, sve && zva_size == 256, __memset_a64fx) #endif IFUNC_IMPL_ADD (array, i, memset, 1, __memset_generic)) IFUNC_IMPL (i, name, memchr, diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c index c4008f346b..1e9ad2160c 100644 --- a/sysdeps/aarch64/multiarch/memset.c +++ b/sysdeps/aarch64/multiarch/memset.c @@ -31,25 +31,34 @@ extern __typeof (__redirect_memset) __libc_memset; extern __typeof (__redirect_memset) __memset_falkor attribute_hidden; extern __typeof (__redirect_memset) __memset_emag attribute_hidden; extern __typeof (__redirect_memset) __memset_kunpeng attribute_hidden; -# if HAVE_AARCH64_SVE_ASM extern __typeof (__redirect_memset) __memset_a64fx attribute_hidden; -# endif extern __typeof (__redirect_memset) __memset_generic attribute_hidden; -libc_ifunc (__libc_memset, - IS_KUNPENG920 (midr) - ?__memset_kunpeng - : ((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64 - ? __memset_falkor - : (IS_EMAG (midr) && zva_size == 64 - ? __memset_emag -# if HAVE_AARCH64_SVE_ASM - : (IS_A64FX (midr) && sve - ? __memset_a64fx - : __memset_generic)))); -# else - : __memset_generic))); -# endif +static inline __typeof (__redirect_memset) * +select_memset_ifunc (void) +{ + INIT_ARCH (); + + if (sve && HAVE_AARCH64_SVE_ASM) + { + if (IS_A64FX (midr) && zva_size == 256) + return __memset_a64fx; + return __memset_generic; + } + + if (IS_KUNPENG920 (midr)) + return __memset_kunpeng; + + if ((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64) + return __memset_falkor; + + if (IS_EMAG (midr) && zva_size == 64) + return __memset_emag; + + return __memset_generic; +} + +libc_ifunc (__libc_memset, select_memset_ifunc ()); # undef memset strong_alias (__libc_memset, memset); -- cgit 1.4.1 From 0cbe0b1a47f82b95a0c3cc06e7707d898446928d Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 26 Oct 2022 14:16:50 +0100 Subject: aarch64: Use memcpy_simd as the default memcpy Since __memcpy_simd is the fastest memcpy on almost all cores, replace the generic memcpy with it. If SVE is available, a SVE memcpy will be used by default (including for Neoverse N2). (cherry picked from commit e6f3fe362f1aab78b1448d69ecdbd9e3872636d3) --- sysdeps/aarch64/memcpy.S | 192 +++++++++------------ sysdeps/aarch64/multiarch/Makefile | 1 - sysdeps/aarch64/multiarch/ifunc-impl-list.c | 2 - sysdeps/aarch64/multiarch/memcpy.c | 4 - sysdeps/aarch64/multiarch/memcpy_advsimd.S | 248 ---------------------------- sysdeps/aarch64/multiarch/memmove.c | 4 - 6 files changed, 81 insertions(+), 370 deletions(-) delete mode 100644 sysdeps/aarch64/multiarch/memcpy_advsimd.S diff --git a/sysdeps/aarch64/memcpy.S b/sysdeps/aarch64/memcpy.S index 98d4e2c0e2..7b396b202f 100644 --- a/sysdeps/aarch64/memcpy.S +++ b/sysdeps/aarch64/memcpy.S @@ -1,4 +1,5 @@ -/* Copyright (C) 2012-2022 Free Software Foundation, Inc. +/* Generic optimized memcpy using SIMD. + Copyright (C) 2012-2022 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -20,7 +21,7 @@ /* Assumptions: * - * ARMv8-a, AArch64, unaligned accesses. + * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses. * */ @@ -36,21 +37,18 @@ #define B_l x8 #define B_lw w8 #define B_h x9 -#define C_l x10 #define C_lw w10 -#define C_h x11 -#define D_l x12 -#define D_h x13 -#define E_l x14 -#define E_h x15 -#define F_l x16 -#define F_h x17 -#define G_l count -#define G_h dst -#define H_l src -#define H_h srcend #define tmp1 x14 +#define A_q q0 +#define B_q q1 +#define C_q q2 +#define D_q q3 +#define E_q q4 +#define F_q q5 +#define G_q q6 +#define H_q q7 + #ifndef MEMMOVE # define MEMMOVE memmove #endif @@ -69,10 +67,9 @@ Large copies use a software pipelined loop processing 64 bytes per iteration. The destination pointer is 16-byte aligned to minimize unaligned accesses. The loop tail is handled by always copying 64 bytes - from the end. -*/ + from the end. */ -ENTRY_ALIGN (MEMCPY, 6) +ENTRY (MEMCPY) PTR_ARG (0) PTR_ARG (1) SIZE_ARG (2) @@ -87,10 +84,10 @@ ENTRY_ALIGN (MEMCPY, 6) /* Small copies: 0..32 bytes. */ cmp count, 16 b.lo L(copy16) - ldp A_l, A_h, [src] - ldp D_l, D_h, [srcend, -16] - stp A_l, A_h, [dstin] - stp D_l, D_h, [dstend, -16] + ldr A_q, [src] + ldr B_q, [srcend, -16] + str A_q, [dstin] + str B_q, [dstend, -16] ret /* Copy 8-15 bytes. */ @@ -102,7 +99,6 @@ L(copy16): str A_h, [dstend, -8] ret - .p2align 3 /* Copy 4-7 bytes. */ L(copy8): tbz count, 2, L(copy4) @@ -128,87 +124,69 @@ L(copy0): .p2align 4 /* Medium copies: 33..128 bytes. */ L(copy32_128): - ldp A_l, A_h, [src] - ldp B_l, B_h, [src, 16] - ldp C_l, C_h, [srcend, -32] - ldp D_l, D_h, [srcend, -16] + ldp A_q, B_q, [src] + ldp C_q, D_q, [srcend, -32] cmp count, 64 b.hi L(copy128) - stp A_l, A_h, [dstin] - stp B_l, B_h, [dstin, 16] - stp C_l, C_h, [dstend, -32] - stp D_l, D_h, [dstend, -16] + stp A_q, B_q, [dstin] + stp C_q, D_q, [dstend, -32] ret .p2align 4 /* Copy 65..128 bytes. */ L(copy128): - ldp E_l, E_h, [src, 32] - ldp F_l, F_h, [src, 48] + ldp E_q, F_q, [src, 32] cmp count, 96 b.ls L(copy96) - ldp G_l, G_h, [srcend, -64] - ldp H_l, H_h, [srcend, -48] - stp G_l, G_h, [dstend, -64] - stp H_l, H_h, [dstend, -48] + ldp G_q, H_q, [srcend, -64] + stp G_q, H_q, [dstend, -64] L(copy96): - stp A_l, A_h, [dstin] - stp B_l, B_h, [dstin, 16] - stp E_l, E_h, [dstin, 32] - stp F_l, F_h, [dstin, 48] - stp C_l, C_h, [dstend, -32] - stp D_l, D_h, [dstend, -16] + stp A_q, B_q, [dstin] + stp E_q, F_q, [dstin, 32] + stp C_q, D_q, [dstend, -32] ret - .p2align 4 + /* Align loop64 below to 16 bytes. */ + nop + /* Copy more than 128 bytes. */ L(copy_long): - /* Copy 16 bytes and then align dst to 16-byte alignment. */ - ldp D_l, D_h, [src] - and tmp1, dstin, 15 - bic dst, dstin, 15 - sub src, src, tmp1 + /* Copy 16 bytes and then align src to 16-byte alignment. */ + ldr D_q, [src] + and tmp1, src, 15 + bic src, src, 15 + sub dst, dstin, tmp1 add count, count, tmp1 /* Count is now 16 too large. */ - ldp A_l, A_h, [src, 16] - stp D_l, D_h, [dstin] - ldp B_l, B_h, [src, 32] - ldp C_l, C_h, [src, 48] - ldp D_l, D_h, [src, 64]! + ldp A_q, B_q, [src, 16] + str D_q, [dstin] + ldp C_q, D_q, [src, 48] subs count, count, 128 + 16 /* Test and readjust count. */ b.ls L(copy64_from_end) - L(loop64): - stp A_l, A_h, [dst, 16] - ldp A_l, A_h, [src, 16] - stp B_l, B_h, [dst, 32] - ldp B_l, B_h, [src, 32] - stp C_l, C_h, [dst, 48] - ldp C_l, C_h, [src, 48] - stp D_l, D_h, [dst, 64]! - ldp D_l, D_h, [src, 64]! + stp A_q, B_q, [dst, 16] + ldp A_q, B_q, [src, 80] + stp C_q, D_q, [dst, 48] + ldp C_q, D_q, [src, 112] + add src, src, 64 + add dst, dst, 64 subs count, count, 64 b.hi L(loop64) /* Write the last iteration and copy 64 bytes from the end. */ L(copy64_from_end): - ldp E_l, E_h, [srcend, -64] - stp A_l, A_h, [dst, 16] - ldp A_l, A_h, [srcend, -48] - stp B_l, B_h, [dst, 32] - ldp B_l, B_h, [srcend, -32] - stp C_l, C_h, [dst, 48] - ldp C_l, C_h, [srcend, -16] - stp D_l, D_h, [dst, 64] - stp E_l, E_h, [dstend, -64] - stp A_l, A_h, [dstend, -48] - stp B_l, B_h, [dstend, -32] - stp C_l, C_h, [dstend, -16] + ldp E_q, F_q, [srcend, -64] + stp A_q, B_q, [dst, 16] + ldp A_q, B_q, [srcend, -32] + stp C_q, D_q, [dst, 48] + stp E_q, F_q, [dstend, -64] + stp A_q, B_q, [dstend, -32] ret END (MEMCPY) libc_hidden_builtin_def (MEMCPY) -ENTRY_ALIGN (MEMMOVE, 4) + +ENTRY (MEMMOVE) PTR_ARG (0) PTR_ARG (1) SIZE_ARG (2) @@ -220,64 +198,56 @@ ENTRY_ALIGN (MEMMOVE, 4) cmp count, 32 b.hi L(copy32_128) - /* Small copies: 0..32 bytes. */ + /* Small moves: 0..32 bytes. */ cmp count, 16 b.lo L(copy16) - ldp A_l, A_h, [src] - ldp D_l, D_h, [srcend, -16] - stp A_l, A_h, [dstin] - stp D_l, D_h, [dstend, -16] + ldr A_q, [src] + ldr B_q, [srcend, -16] + str A_q, [dstin] + str B_q, [dstend, -16] ret - .p2align 4 L(move_long): /* Only use backward copy if there is an overlap. */ sub tmp1, dstin, src - cbz tmp1, L(copy0) + cbz tmp1, L(move0) cmp tmp1, count b.hs L(copy_long) /* Large backwards copy for overlapping copies. - Copy 16 bytes and then align dst to 16-byte alignment. */ - ldp D_l, D_h, [srcend, -16] - and tmp1, dstend, 15 - sub srcend, srcend, tmp1 + Copy 16 bytes and then align srcend to 16-byte alignment. */ +L(copy_long_backwards): + ldr D_q, [srcend, -16] + and tmp1, srcend, 15 + bic srcend, srcend, 15 sub count, count, tmp1 - ldp A_l, A_h, [srcend, -16] - stp D_l, D_h, [dstend, -16] - ldp B_l, B_h, [srcend, -32] - ldp C_l, C_h, [srcend, -48] - ldp D_l, D_h, [srcend, -64]! + ldp A_q, B_q, [srcend, -32] + str D_q, [dstend, -16] + ldp C_q, D_q, [srcend, -64] sub dstend, dstend, tmp1 subs count, count, 128 b.ls L(copy64_from_start) L(loop64_backwards): - stp A_l, A_h, [dstend, -16] - ldp A_l, A_h, [srcend, -16] - stp B_l, B_h, [dstend, -32] - ldp B_l, B_h, [srcend, -32] - stp C_l, C_h, [dstend, -48] - ldp C_l, C_h, [srcend, -48] - stp D_l, D_h, [dstend, -64]! - ldp D_l, D_h, [srcend, -64]! + str B_q, [dstend, -16] + str A_q, [dstend, -32] + ldp A_q, B_q, [srcend, -96] + str D_q, [dstend, -48] + str C_q, [dstend, -64]! + ldp C_q, D_q, [srcend, -128] + sub srcend, srcend, 64 subs count, count, 64 b.hi L(loop64_backwards) /* Write the last iteration and copy 64 bytes from the start. */ L(copy64_from_start): - ldp G_l, G_h, [src, 48] - stp A_l, A_h, [dstend, -16] - ldp A_l, A_h, [src, 32] - stp B_l, B_h, [dstend, -32] - ldp B_l, B_h, [src, 16] - stp C_l, C_h, [dstend, -48] - ldp C_l, C_h, [src] - stp D_l, D_h, [dstend, -64] - stp G_l, G_h, [dstin, 48] - stp A_l, A_h, [dstin, 32] - stp B_l, B_h, [dstin, 16] - stp C_l, C_h, [dstin] + ldp E_q, F_q, [src, 32] + stp A_q, B_q, [dstend, -32] + ldp A_q, B_q, [src] + stp C_q, D_q, [dstend, -64] + stp E_q, F_q, [dstin, 32] + stp A_q, B_q, [dstin] +L(move0): ret END (MEMMOVE) diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile index 16297192ee..223777d94e 100644 --- a/sysdeps/aarch64/multiarch/Makefile +++ b/sysdeps/aarch64/multiarch/Makefile @@ -3,7 +3,6 @@ sysdep_routines += \ memchr_generic \ memchr_nosimd \ memcpy_a64fx \ - memcpy_advsimd \ memcpy_falkor \ memcpy_generic \ memcpy_sve \ diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c index c6fe149a7c..ac8980288e 100644 --- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c +++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c @@ -37,7 +37,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx) IFUNC_IMPL_ADD (array, i, memcpy, !bti, __memcpy_thunderx2) IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor) - IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_simd) #if HAVE_AARCH64_SVE_ASM IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx) IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_sve) @@ -47,7 +46,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx) IFUNC_IMPL_ADD (array, i, memmove, !bti, __memmove_thunderx2) IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor) - IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_simd) #if HAVE_AARCH64_SVE_ASM IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_a64fx) IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_sve) diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c index 0486213f08..21d954e7f3 100644 --- a/sysdeps/aarch64/multiarch/memcpy.c +++ b/sysdeps/aarch64/multiarch/memcpy.c @@ -29,7 +29,6 @@ extern __typeof (__redirect_memcpy) __libc_memcpy; extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden; -extern __typeof (__redirect_memcpy) __memcpy_simd attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden; @@ -41,9 +40,6 @@ select_memcpy_ifunc (void) { INIT_ARCH (); - if (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr)) - return __memcpy_simd; - if (sve && HAVE_AARCH64_SVE_ASM) { if (IS_A64FX (midr)) diff --git a/sysdeps/aarch64/multiarch/memcpy_advsimd.S b/sysdeps/aarch64/multiarch/memcpy_advsimd.S deleted file mode 100644 index fe9beaf5ea..0000000000 --- a/sysdeps/aarch64/multiarch/memcpy_advsimd.S +++ /dev/null @@ -1,248 +0,0 @@ -/* Generic optimized memcpy using SIMD. - Copyright (C) 2020-2022 Free Software Foundation, Inc. - - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#include - -/* Assumptions: - * - * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses. - * - */ - -#define dstin x0 -#define src x1 -#define count x2 -#define dst x3 -#define srcend x4 -#define dstend x5 -#define A_l x6 -#define A_lw w6 -#define A_h x7 -#define B_l x8 -#define B_lw w8 -#define B_h x9 -#define C_lw w10 -#define tmp1 x14 - -#define A_q q0 -#define B_q q1 -#define C_q q2 -#define D_q q3 -#define E_q q4 -#define F_q q5 -#define G_q q6 -#define H_q q7 - - -/* This implementation supports both memcpy and memmove and shares most code. - It uses unaligned accesses and branchless sequences to keep the code small, - simple and improve performance. - - Copies are split into 3 main cases: small copies of up to 32 bytes, medium - copies of up to 128 bytes, and large copies. The overhead of the overlap - check in memmove is negligible since it is only required for large copies. - - Large copies use a software pipelined loop processing 64 bytes per - iteration. The destination pointer is 16-byte aligned to minimize - unaligned accesses. The loop tail is handled by always copying 64 bytes - from the end. */ - -ENTRY (__memcpy_simd) - PTR_ARG (0) - PTR_ARG (1) - SIZE_ARG (2) - - add srcend, src, count - add dstend, dstin, count - cmp count, 128 - b.hi L(copy_long) - cmp count, 32 - b.hi L(copy32_128) - - /* Small copies: 0..32 bytes. */ - cmp count, 16 - b.lo L(copy16) - ldr A_q, [src] - ldr B_q, [srcend, -16] - str A_q, [dstin] - str B_q, [dstend, -16] - ret - - /* Copy 8-15 bytes. */ -L(copy16): - tbz count, 3, L(copy8) - ldr A_l, [src] - ldr A_h, [srcend, -8] - str A_l, [dstin] - str A_h, [dstend, -8] - ret - - /* Copy 4-7 bytes. */ -L(copy8): - tbz count, 2, L(copy4) - ldr A_lw, [src] - ldr B_lw, [srcend, -4] - str A_lw, [dstin] - str B_lw, [dstend, -4] - ret - - /* Copy 0..3 bytes using a branchless sequence. */ -L(copy4): - cbz count, L(copy0) - lsr tmp1, count, 1 - ldrb A_lw, [src] - ldrb C_lw, [srcend, -1] - ldrb B_lw, [src, tmp1] - strb A_lw, [dstin] - strb B_lw, [dstin, tmp1] - strb C_lw, [dstend, -1] -L(copy0): - ret - - .p2align 4 - /* Medium copies: 33..128 bytes. */ -L(copy32_128): - ldp A_q, B_q, [src] - ldp C_q, D_q, [srcend, -32] - cmp count, 64 - b.hi L(copy128) - stp A_q, B_q, [dstin] - stp C_q, D_q, [dstend, -32] - ret - - .p2align 4 - /* Copy 65..128 bytes. */ -L(copy128): - ldp E_q, F_q, [src, 32] - cmp count, 96 - b.ls L(copy96) - ldp G_q, H_q, [srcend, -64] - stp G_q, H_q, [dstend, -64] -L(copy96): - stp A_q, B_q, [dstin] - stp E_q, F_q, [dstin, 32] - stp C_q, D_q, [dstend, -32] - ret - - /* Align loop64 below to 16 bytes. */ - nop - - /* Copy more than 128 bytes. */ -L(copy_long): - /* Copy 16 bytes and then align src to 16-byte alignment. */ - ldr D_q, [src] - and tmp1, src, 15 - bic src, src, 15 - sub dst, dstin, tmp1 - add count, count, tmp1 /* Count is now 16 too large. */ - ldp A_q, B_q, [src, 16] - str D_q, [dstin] - ldp C_q, D_q, [src, 48] - subs count, count, 128 + 16 /* Test and readjust count. */ - b.ls L(copy64_from_end) -L(loop64): - stp A_q, B_q, [dst, 16] - ldp A_q, B_q, [src, 80] - stp C_q, D_q, [dst, 48] - ldp C_q, D_q, [src, 112] - add src, src, 64 - add dst, dst, 64 - subs count, count, 64 - b.hi L(loop64) - - /* Write the last iteration and copy 64 bytes from the end. */ -L(copy64_from_end): - ldp E_q, F_q, [srcend, -64] - stp A_q, B_q, [dst, 16] - ldp A_q, B_q, [srcend, -32] - stp C_q, D_q, [dst, 48] - stp E_q, F_q, [dstend, -64] - stp A_q, B_q, [dstend, -32] - ret - -END (__memcpy_simd) -libc_hidden_builtin_def (__memcpy_simd) - - -ENTRY (__memmove_simd) - PTR_ARG (0) - PTR_ARG (1) - SIZE_ARG (2) - - add srcend, src, count - add dstend, dstin, count - cmp count, 128 - b.hi L(move_long) - cmp count, 32 - b.hi L(copy32_128) - - /* Small moves: 0..32 bytes. */ - cmp count, 16 - b.lo L(copy16) - ldr A_q, [src] - ldr B_q, [srcend, -16] - str A_q, [dstin] - str B_q, [dstend, -16] - ret - -L(move_long): - /* Only use backward copy if there is an overlap. */ - sub tmp1, dstin, src - cbz tmp1, L(move0) - cmp tmp1, count - b.hs L(copy_long) - - /* Large backwards copy for overlapping copies. - Copy 16 bytes and then align srcend to 16-byte alignment. */ -L(copy_long_backwards): - ldr D_q, [srcend, -16] - and tmp1, srcend, 15 - bic srcend, srcend, 15 - sub count, count, tmp1 - ldp A_q, B_q, [srcend, -32] - str D_q, [dstend, -16] - ldp C_q, D_q, [srcend, -64] - sub dstend, dstend, tmp1 - subs count, count, 128 - b.ls L(copy64_from_start) - -L(loop64_backwards): - str B_q, [dstend, -16] - str A_q, [dstend, -32] - ldp A_q, B_q, [srcend, -96] - str D_q, [dstend, -48] - str C_q, [dstend, -64]! - ldp C_q, D_q, [srcend, -128] - sub srcend, srcend, 64 - subs count, count, 64 - b.hi L(loop64_backwards) - - /* Write the last iteration and copy 64 bytes from the start. */ -L(copy64_from_start): - ldp E_q, F_q, [src, 32] - stp A_q, B_q, [dstend, -32] - ldp A_q, B_q, [src] - stp C_q, D_q, [dstend, -64] - stp E_q, F_q, [dstin, 32] - stp A_q, B_q, [dstin] -L(move0): - ret - -END (__memmove_simd) -libc_hidden_builtin_def (__memmove_simd) diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c index 261996ecc4..70e8eaef7c 100644 --- a/sysdeps/aarch64/multiarch/memmove.c +++ b/sysdeps/aarch64/multiarch/memmove.c @@ -29,7 +29,6 @@ extern __typeof (__redirect_memmove) __libc_memmove; extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden; -extern __typeof (__redirect_memmove) __memmove_simd attribute_hidden; extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden; extern __typeof (__redirect_memmove) __memmove_thunderx2 attribute_hidden; extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden; @@ -41,9 +40,6 @@ select_memmove_ifunc (void) { INIT_ARCH (); - if (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr)) - return __memmove_simd; - if (sve && HAVE_AARCH64_SVE_ASM) { if (IS_A64FX (midr)) -- cgit 1.4.1 From 34424b6770b25b09ace2849f34499845aa65b155 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:50:59 +0000 Subject: AArch64: Optimize memchr Optimize the main loop - large strings are 40% faster on modern CPUs. Reviewed-by: Szabolcs Nagy (cherry picked from commit ce758d4f063820c2bc743e12797d7454c66be718) --- sysdeps/aarch64/memchr.S | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/sysdeps/aarch64/memchr.S b/sysdeps/aarch64/memchr.S index 2053a977b6..79aa910da4 100644 --- a/sysdeps/aarch64/memchr.S +++ b/sysdeps/aarch64/memchr.S @@ -30,7 +30,6 @@ # define MEMCHR __memchr #endif -/* Arguments and results. */ #define srcin x0 #define chrin w1 #define cntin x2 @@ -73,42 +72,44 @@ ENTRY (MEMCHR) rbit synd, synd clz synd, synd - add result, srcin, synd, lsr 2 cmp cntin, synd, lsr 2 + add result, srcin, synd, lsr 2 csel result, result, xzr, hi ret + .p2align 3 L(start_loop): sub tmp, src, srcin - add tmp, tmp, 16 + add tmp, tmp, 17 subs cntrem, cntin, tmp - b.ls L(nomatch) + b.lo L(nomatch) /* Make sure that it won't overread by a 16-byte chunk */ - add tmp, cntrem, 15 - tbnz tmp, 4, L(loop32_2) - + tbz cntrem, 4, L(loop32_2) + sub src, src, 16 .p2align 4 L(loop32): - ldr qdata, [src, 16]! + ldr qdata, [src, 32]! cmeq vhas_chr.16b, vdata.16b, vrepchr.16b umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ fmov synd, dend cbnz synd, L(end) L(loop32_2): - ldr qdata, [src, 16]! - subs cntrem, cntrem, 32 + ldr qdata, [src, 16] cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - b.ls L(end) + subs cntrem, cntrem, 32 + b.lo L(end_2) umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ fmov synd, dend cbz synd, L(loop32) +L(end_2): + add src, src, 16 L(end): shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ + sub cntrem, src, srcin fmov synd, dend - add tmp, srcin, cntin - sub cntrem, tmp, src + sub cntrem, cntin, cntrem #ifndef __AARCH64EB__ rbit synd, synd #endif -- cgit 1.4.1 From 1296aa9b0b145b8a4c82ece6c6ea2f4afa87d21b Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:51:17 +0000 Subject: AArch64: Optimize memrchr Optimize the main loop - large strings are 43% faster on modern CPUs. Reviewed-by: Szabolcs Nagy (cherry picked from commit 00776241776e67fc666b896c1e85770f4f3ec1e1) --- sysdeps/aarch64/memrchr.S | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sysdeps/aarch64/memrchr.S b/sysdeps/aarch64/memrchr.S index 5179320720..428af51f70 100644 --- a/sysdeps/aarch64/memrchr.S +++ b/sysdeps/aarch64/memrchr.S @@ -26,7 +26,6 @@ * MTE compatible. */ -/* Arguments and results. */ #define srcin x0 #define chrin w1 #define cntin x2 @@ -77,31 +76,34 @@ ENTRY (__memrchr) csel result, result, xzr, hi ret + nop L(start_loop): - sub tmp, end, src - subs cntrem, cntin, tmp + subs cntrem, src, srcin b.ls L(nomatch) /* Make sure that it won't overread by a 16-byte chunk */ - add tmp, cntrem, 15 - tbnz tmp, 4, L(loop32_2) + sub cntrem, cntrem, 1 + tbz cntrem, 4, L(loop32_2) + add src, src, 16 - .p2align 4 + .p2align 5 L(loop32): - ldr qdata, [src, -16]! + ldr qdata, [src, -32]! cmeq vhas_chr.16b, vdata.16b, vrepchr.16b umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ fmov synd, dend cbnz synd, L(end) L(loop32_2): - ldr qdata, [src, -16]! + ldr qdata, [src, -16] subs cntrem, cntrem, 32 cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - b.ls L(end) + b.lo L(end_2) umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ fmov synd, dend cbz synd, L(loop32) +L(end_2): + sub src, src, 16 L(end): shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ fmov synd, dend -- cgit 1.4.1 From ef62fc2223bfd0c1d7cd657b88f54147eac47e92 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:51:48 +0000 Subject: AArch64: Improve strlen_asimd Use shrn for the mask, merge tst+bne into cbnz, and tweak code alignment. Performance improves slightly as a result. Reviewed-by: Szabolcs Nagy (cherry picked from commit 1bbb1a2022e126f21810d3d0ebe0a975d5243e43) --- sysdeps/aarch64/multiarch/strlen_asimd.S | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sysdeps/aarch64/multiarch/strlen_asimd.S b/sysdeps/aarch64/multiarch/strlen_asimd.S index 6faeb91361..13386eb5d4 100644 --- a/sysdeps/aarch64/multiarch/strlen_asimd.S +++ b/sysdeps/aarch64/multiarch/strlen_asimd.S @@ -48,6 +48,7 @@ #define tmp x2 #define tmpw w2 #define synd x3 +#define syndw w3 #define shift x4 /* For the first 32 bytes, NUL detection works on the principle that @@ -87,7 +88,6 @@ ENTRY (__strlen_asimd) PTR_ARG (0) - and tmp1, srcin, MIN_PAGE_SIZE - 1 cmp tmp1, MIN_PAGE_SIZE - 32 b.hi L(page_cross) @@ -123,7 +123,6 @@ ENTRY (__strlen_asimd) add len, len, tmp1, lsr 3 ret - .p2align 3 /* Look for a NUL byte at offset 16..31 in the string. */ L(bytes16_31): ldp data1, data2, [srcin, 16] @@ -151,6 +150,7 @@ L(bytes16_31): add len, len, tmp1, lsr 3 ret + nop L(loop_entry): bic src, srcin, 31 @@ -166,18 +166,12 @@ L(loop): /* Low 32 bits of synd are non-zero if a NUL was found in datav1. */ cmeq maskv.16b, datav1.16b, 0 sub len, src, srcin - tst synd, 0xffffffff - b.ne 1f + cbnz syndw, 1f cmeq maskv.16b, datav2.16b, 0 add len, len, 16 1: /* Generate a bitmask and compute correct byte offset. */ -#ifdef __AARCH64EB__ - bic maskv.8h, 0xf0 -#else - bic maskv.8h, 0x0f, lsl 8 -#endif - umaxp maskv.16b, maskv.16b, maskv.16b + shrn maskv.8b, maskv.8h, 4 fmov synd, maskd #ifndef __AARCH64EB__ rbit synd, synd @@ -186,8 +180,6 @@ L(loop): add len, len, tmp, lsr 2 ret - .p2align 4 - L(page_cross): bic src, srcin, 31 mov tmpw, 0x0c03 -- cgit 1.4.1 From 2e4cdcbd356094d36eca234e8dcecc5149d92dba Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:52:08 +0000 Subject: AArch64: Optimize strchr Simplify calculation of the mask using shrn. Unroll the main loop. Small strings are 20% faster on modern CPUs. Reviewed-by: Szabolcs Nagy (cherry picked from commit 51541a229740801882490177fa178e49264b13fb) --- sysdeps/aarch64/strchr.S | 52 ++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/sysdeps/aarch64/strchr.S b/sysdeps/aarch64/strchr.S index 003bf4a478..4781d45bd9 100644 --- a/sysdeps/aarch64/strchr.S +++ b/sysdeps/aarch64/strchr.S @@ -32,8 +32,7 @@ #define src x2 #define tmp1 x1 -#define wtmp2 w3 -#define tmp3 x3 +#define tmp2 x3 #define vrepchr v0 #define vdata v1 @@ -41,39 +40,30 @@ #define vhas_nul v2 #define vhas_chr v3 #define vrepmask v4 -#define vrepmask2 v5 -#define vend v6 -#define dend d6 +#define vend v5 +#define dend d5 /* Core algorithm. For each 16-byte chunk we calculate a 64-bit syndrome value with four bits - per byte. For even bytes, bits 0-1 are set if the relevant byte matched the - requested character, bits 2-3 are set if the byte is NUL (or matched), and - bits 4-7 are not used and must be zero if none of bits 0-3 are set). Odd - bytes set bits 4-7 so that adjacent bytes can be merged. Since the bits - in the syndrome reflect the order in which things occur in the original - string, counting trailing zeros identifies exactly which byte matched. */ + per byte. Bits 0-1 are set if the relevant byte matched the requested + character, bits 2-3 are set if the byte is NUL or matched. Count trailing + zeroes gives the position of the matching byte if it is a multiple of 4. + If it is not a multiple of 4, there was no match. */ ENTRY (strchr) PTR_ARG (0) bic src, srcin, 15 dup vrepchr.16b, chrin ld1 {vdata.16b}, [src] - mov wtmp2, 0x3003 - dup vrepmask.8h, wtmp2 + movi vrepmask.16b, 0x33 cmeq vhas_nul.16b, vdata.16b, 0 cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - mov wtmp2, 0xf00f - dup vrepmask2.8h, wtmp2 - bit vhas_nul.16b, vhas_chr.16b, vrepmask.16b - and vhas_nul.16b, vhas_nul.16b, vrepmask2.16b - lsl tmp3, srcin, 2 - addp vend.16b, vhas_nul.16b, vhas_nul.16b /* 128->64 */ - + lsl tmp2, srcin, 2 + shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ fmov tmp1, dend - lsr tmp1, tmp1, tmp3 + lsr tmp1, tmp1, tmp2 cbz tmp1, L(loop) rbit tmp1, tmp1 @@ -87,28 +77,34 @@ ENTRY (strchr) .p2align 4 L(loop): - ldr qdata, [src, 16]! + ldr qdata, [src, 16] + cmeq vhas_chr.16b, vdata.16b, vrepchr.16b + cmhs vhas_nul.16b, vhas_chr.16b, vdata.16b + umaxp vend.16b, vhas_nul.16b, vhas_nul.16b + fmov tmp1, dend + cbnz tmp1, L(end) + ldr qdata, [src, 32]! cmeq vhas_chr.16b, vdata.16b, vrepchr.16b cmhs vhas_nul.16b, vhas_chr.16b, vdata.16b umaxp vend.16b, vhas_nul.16b, vhas_nul.16b fmov tmp1, dend cbz tmp1, L(loop) + sub src, src, 16 +L(end): #ifdef __AARCH64EB__ bif vhas_nul.16b, vhas_chr.16b, vrepmask.16b - and vhas_nul.16b, vhas_nul.16b, vrepmask2.16b - addp vend.16b, vhas_nul.16b, vhas_nul.16b /* 128->64 */ + shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ fmov tmp1, dend #else bit vhas_nul.16b, vhas_chr.16b, vrepmask.16b - and vhas_nul.16b, vhas_nul.16b, vrepmask2.16b - addp vend.16b, vhas_nul.16b, vhas_nul.16b /* 128->64 */ + shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ fmov tmp1, dend rbit tmp1, tmp1 #endif + add src, src, 16 clz tmp1, tmp1 - /* Tmp1 is an even multiple of 2 if the target character was - found first. Otherwise we've found the end of string. */ + /* Tmp1 is a multiple of 4 if the target character was found. */ tst tmp1, 2 add result, src, tmp1, lsr 2 csel result, result, xzr, eq -- cgit 1.4.1 From 8ee69bd2df74fcc18ecf7e08eb5c74809c0be0e9 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:52:23 +0000 Subject: AArch64: Improve strchrnul Unroll the main loop, which improves performance slightly. Reviewed-by: Szabolcs Nagy (cherry picked from commit 09ebd8549b2ce5a3a6c0c7c5f3e62227faf50a99) --- sysdeps/aarch64/strchrnul.S | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sysdeps/aarch64/strchrnul.S b/sysdeps/aarch64/strchrnul.S index ee154ab74b..94465fc088 100644 --- a/sysdeps/aarch64/strchrnul.S +++ b/sysdeps/aarch64/strchrnul.S @@ -70,14 +70,22 @@ ENTRY (__strchrnul) .p2align 4 L(loop): - ldr qdata, [src, 16]! + ldr qdata, [src, 16] + cmeq vhas_chr.16b, vdata.16b, vrepchr.16b + cmhs vhas_chr.16b, vhas_chr.16b, vdata.16b + umaxp vend.16b, vhas_chr.16b, vhas_chr.16b + fmov tmp1, dend + cbnz tmp1, L(end) + ldr qdata, [src, 32]! cmeq vhas_chr.16b, vdata.16b, vrepchr.16b cmhs vhas_chr.16b, vhas_chr.16b, vdata.16b umaxp vend.16b, vhas_chr.16b, vhas_chr.16b fmov tmp1, dend cbz tmp1, L(loop) - + sub src, src, 16 +L(end): shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ + add src, src, 16 fmov tmp1, dend #ifndef __AARCH64EB__ rbit tmp1, tmp1 -- cgit 1.4.1 From 90d9b8897bd21f1ce443cd2e046b4ab9ce24d4b4 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:52:39 +0000 Subject: AArch64: Optimize strcpy Unroll the main loop. Large strings are around 20% faster on modern CPUs. Reviewed-by: Szabolcs Nagy (cherry picked from commit 349e48c01e85bd96006860084e76d322e6ca02f1) --- sysdeps/aarch64/strcpy.S | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/sysdeps/aarch64/strcpy.S b/sysdeps/aarch64/strcpy.S index 78d27b4aa6..6eeda12df6 100644 --- a/sysdeps/aarch64/strcpy.S +++ b/sysdeps/aarch64/strcpy.S @@ -30,7 +30,6 @@ * MTE compatible. */ -/* Arguments and results. */ #define dstin x0 #define srcin x1 #define result x0 @@ -76,14 +75,14 @@ ENTRY (STRCPY) ld1 {vdata.16b}, [src] cmeq vhas_nul.16b, vdata.16b, 0 lsl shift, srcin, 2 - shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ + shrn vend.8b, vhas_nul.8h, 4 fmov synd, dend lsr synd, synd, shift cbnz synd, L(tail) ldr dataq, [src, 16]! cmeq vhas_nul.16b, vdata.16b, 0 - shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ + shrn vend.8b, vhas_nul.8h, 4 fmov synd, dend cbz synd, L(start_loop) @@ -102,13 +101,10 @@ ENTRY (STRCPY) IFSTPCPY (add result, dstin, len) ret - .p2align 4,,8 L(tail): rbit synd, synd clz len, synd lsr len, len, 2 - - .p2align 4 L(less16): tbz len, 3, L(less8) sub tmp, len, 7 @@ -141,31 +137,37 @@ L(zerobyte): .p2align 4 L(start_loop): - sub len, src, srcin + sub tmp, srcin, dstin ldr dataq2, [srcin] - add dst, dstin, len + sub dst, src, tmp str dataq2, [dstin] - - .p2align 5 L(loop): - str dataq, [dst], 16 - ldr dataq, [src, 16]! + str dataq, [dst], 32 + ldr dataq, [src, 16] + cmeq vhas_nul.16b, vdata.16b, 0 + umaxp vend.16b, vhas_nul.16b, vhas_nul.16b + fmov synd, dend + cbnz synd, L(loopend) + str dataq, [dst, -16] + ldr dataq, [src, 32]! cmeq vhas_nul.16b, vdata.16b, 0 umaxp vend.16b, vhas_nul.16b, vhas_nul.16b fmov synd, dend cbz synd, L(loop) - + add dst, dst, 16 +L(loopend): shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ fmov synd, dend + sub dst, dst, 31 #ifndef __AARCH64EB__ rbit synd, synd #endif clz len, synd lsr len, len, 2 - sub tmp, len, 15 - ldr dataq, [src, tmp] - str dataq, [dst, tmp] - IFSTPCPY (add result, dst, len) + add dst, dst, len + ldr dataq, [dst, tmp] + str dataq, [dst] + IFSTPCPY (add result, dst, 15) ret END (STRCPY) -- cgit 1.4.1 From daa13ed0acd760f0c853e5521bfbfc050cc23574 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:52:53 +0000 Subject: AArch64: Optimize strlen Optimize strlen by unrolling the main loop. Large strings are 64% faster on modern CPUs. Reviewed-by: Szabolcs Nagy (cherry picked from commit 03c8ce5000198947a4dd7b2c14e5131738fda62b) --- sysdeps/aarch64/strlen.S | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sysdeps/aarch64/strlen.S b/sysdeps/aarch64/strlen.S index 3a5d088407..10b9ec0769 100644 --- a/sysdeps/aarch64/strlen.S +++ b/sysdeps/aarch64/strlen.S @@ -43,12 +43,9 @@ #define dend d2 /* Core algorithm: - - For each 16-byte chunk we calculate a 64-bit nibble mask value with four bits - per byte. We take 4 bits of every comparison byte with shift right and narrow - by 4 instruction. Since the bits in the nibble mask reflect the order in - which things occur in the original string, counting trailing zeros identifies - exactly which byte matched. */ + Process the string in 16-byte aligned chunks. Compute a 64-bit mask with + four bits per byte using the shrn instruction. A count trailing zeros then + identifies the first zero byte. */ ENTRY (STRLEN) PTR_ARG (0) @@ -68,18 +65,25 @@ ENTRY (STRLEN) .p2align 5 L(loop): - ldr data, [src, 16]! + ldr data, [src, 16] + cmeq vhas_nul.16b, vdata.16b, 0 + umaxp vend.16b, vhas_nul.16b, vhas_nul.16b + fmov synd, dend + cbnz synd, L(loop_end) + ldr data, [src, 32]! cmeq vhas_nul.16b, vdata.16b, 0 umaxp vend.16b, vhas_nul.16b, vhas_nul.16b fmov synd, dend cbz synd, L(loop) - + sub src, src, 16 +L(loop_end): shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ sub result, src, srcin fmov synd, dend #ifndef __AARCH64EB__ rbit synd, synd #endif + add result, result, 16 clz tmp, synd add result, result, tmp, lsr 2 ret -- cgit 1.4.1 From 7cbcc959270dcf25789b2f09c4bf1c60a86b760a Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:53:05 +0000 Subject: AArch64: Optimize strnlen Optimize strnlen using the shrn instruction and improve the main loop. Small strings are around 10% faster, large strings are 40% faster on modern CPUs. Reviewed-by: Szabolcs Nagy (cherry picked from commit ad098893ba3c3344a5f2f6ab1627c47204afdb47) --- sysdeps/aarch64/strnlen.S | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/sysdeps/aarch64/strnlen.S b/sysdeps/aarch64/strnlen.S index 282bddc9aa..a44a49a920 100644 --- a/sysdeps/aarch64/strnlen.S +++ b/sysdeps/aarch64/strnlen.S @@ -44,19 +44,16 @@ /* Core algorithm: - - For each 16-byte chunk we calculate a 64-bit nibble mask value with four bits - per byte. We take 4 bits of every comparison byte with shift right and narrow - by 4 instruction. Since the bits in the nibble mask reflect the order in - which things occur in the original string, counting trailing zeros identifies - exactly which byte matched. */ + Process the string in 16-byte aligned chunks. Compute a 64-bit mask with + four bits per byte using the shrn instruction. A count trailing zeros then + identifies the first zero byte. */ ENTRY (__strnlen) PTR_ARG (0) SIZE_ARG (1) bic src, srcin, 15 cbz cntin, L(nomatch) - ld1 {vdata.16b}, [src], 16 + ld1 {vdata.16b}, [src] cmeq vhas_chr.16b, vdata.16b, 0 lsl shift, srcin, 2 shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ @@ -71,36 +68,40 @@ L(finish): csel result, cntin, result, ls ret +L(nomatch): + mov result, cntin + ret + L(start_loop): sub tmp, src, srcin + add tmp, tmp, 17 subs cntrem, cntin, tmp - b.ls L(nomatch) + b.lo L(nomatch) /* Make sure that it won't overread by a 16-byte chunk */ - add tmp, cntrem, 15 - tbnz tmp, 4, L(loop32_2) - + tbz cntrem, 4, L(loop32_2) + sub src, src, 16 .p2align 5 L(loop32): - ldr qdata, [src], 16 + ldr qdata, [src, 32]! cmeq vhas_chr.16b, vdata.16b, 0 umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ fmov synd, dend cbnz synd, L(end) L(loop32_2): - ldr qdata, [src], 16 + ldr qdata, [src, 16] subs cntrem, cntrem, 32 cmeq vhas_chr.16b, vdata.16b, 0 - b.ls L(end) + b.lo L(end_2) umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ fmov synd, dend cbz synd, L(loop32) - +L(end_2): + add src, src, 16 L(end): shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ - sub src, src, 16 - mov synd, vend.d[0] sub result, src, srcin + fmov synd, dend #ifndef __AARCH64EB__ rbit synd, synd #endif @@ -110,10 +111,6 @@ L(end): csel result, cntin, result, ls ret -L(nomatch): - mov result, cntin - ret - END (__strnlen) libc_hidden_def (__strnlen) weak_alias (__strnlen, strnlen) -- cgit 1.4.1 From 600098c58ab53107a76237cba8b90ce26b253b56 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 11 Jan 2023 13:53:19 +0000 Subject: AArch64: Improve strrchr Use shrn for narrowing the mask which simplifies code and speeds up small strings. Unroll the first search loop to improve performance on large strings. Reviewed-by: Szabolcs Nagy (cherry picked from commit 55599d480437dcf129b41b95be32b48f2a9e5da9) --- sysdeps/aarch64/strrchr.S | 58 +++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/sysdeps/aarch64/strrchr.S b/sysdeps/aarch64/strrchr.S index 596e77c43b..eda6fefb99 100644 --- a/sysdeps/aarch64/strrchr.S +++ b/sysdeps/aarch64/strrchr.S @@ -22,19 +22,16 @@ /* Assumptions: * - * ARMv8-a, AArch64 - * Neon Available. + * ARMv8-a, AArch64, Advanced SIMD. * MTE compatible. */ -/* Arguments and results. */ #define srcin x0 #define chrin w1 #define result x0 #define src x2 #define tmp x3 -#define wtmp w3 #define synd x3 #define shift x4 #define src_match x4 @@ -46,7 +43,6 @@ #define vhas_nul v2 #define vhas_chr v3 #define vrepmask v4 -#define vrepmask2 v5 #define vend v5 #define dend d5 @@ -58,59 +54,71 @@ the relevant byte matched the requested character; bits 2-3 are set if the relevant byte matched the NUL end of string. */ -ENTRY(strrchr) +ENTRY (strrchr) PTR_ARG (0) bic src, srcin, 15 dup vrepchr.16b, chrin - mov wtmp, 0x3003 - dup vrepmask.8h, wtmp - tst srcin, 15 - beq L(loop1) - - ld1 {vdata.16b}, [src], 16 + movi vrepmask.16b, 0x33 + ld1 {vdata.16b}, [src] cmeq vhas_nul.16b, vdata.16b, 0 cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - mov wtmp, 0xf00f - dup vrepmask2.8h, wtmp bit vhas_nul.16b, vhas_chr.16b, vrepmask.16b - and vhas_nul.16b, vhas_nul.16b, vrepmask2.16b - addp vend.16b, vhas_nul.16b, vhas_nul.16b + shrn vend.8b, vhas_nul.8h, 4 lsl shift, srcin, 2 fmov synd, dend lsr synd, synd, shift lsl synd, synd, shift ands nul_match, synd, 0xcccccccccccccccc bne L(tail) - cbnz synd, L(loop2) + cbnz synd, L(loop2_start) - .p2align 5 + .p2align 4 L(loop1): - ld1 {vdata.16b}, [src], 16 + ldr q1, [src, 16] + cmeq vhas_chr.16b, vdata.16b, vrepchr.16b + cmhs vhas_nul.16b, vhas_chr.16b, vdata.16b + umaxp vend.16b, vhas_nul.16b, vhas_nul.16b + fmov synd, dend + cbnz synd, L(loop1_end) + ldr q1, [src, 32]! cmeq vhas_chr.16b, vdata.16b, vrepchr.16b cmhs vhas_nul.16b, vhas_chr.16b, vdata.16b umaxp vend.16b, vhas_nul.16b, vhas_nul.16b fmov synd, dend cbz synd, L(loop1) - + sub src, src, 16 +L(loop1_end): + add src, src, 16 cmeq vhas_nul.16b, vdata.16b, 0 +#ifdef __AARCH64EB__ + bif vhas_nul.16b, vhas_chr.16b, vrepmask.16b + shrn vend.8b, vhas_nul.8h, 4 + fmov synd, dend + rbit synd, synd +#else bit vhas_nul.16b, vhas_chr.16b, vrepmask.16b - bic vhas_nul.8h, 0x0f, lsl 8 - addp vend.16b, vhas_nul.16b, vhas_nul.16b + shrn vend.8b, vhas_nul.8h, 4 fmov synd, dend +#endif ands nul_match, synd, 0xcccccccccccccccc - beq L(loop2) - + beq L(loop2_start) L(tail): sub nul_match, nul_match, 1 and chr_match, synd, 0x3333333333333333 ands chr_match, chr_match, nul_match - sub result, src, 1 + add result, src, 15 clz tmp, chr_match sub result, result, tmp, lsr 2 csel result, result, xzr, ne ret .p2align 4 + nop + nop +L(loop2_start): + add src, src, 16 + bic vrepmask.8h, 0xf0 + L(loop2): cmp synd, 0 csel src_match, src, src_match, ne -- cgit 1.4.1 From f45608f6d74b95d0711c80c24b5eda07b60a7e50 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 1 Feb 2023 18:45:19 +0000 Subject: AArch64: Improve SVE memcpy and memmove Improve SVE memcpy by copying 2 vectors if the size is small enough. This improves performance of random memcpy by ~9% on Neoverse V1, and 33-64 byte copies are ~16% faster. Reviewed-by: Szabolcs Nagy (cherry picked from commit d2d3f3720ce627a4fe154d8dd14db716a32bcc6e) --- sysdeps/aarch64/multiarch/memcpy_sve.S | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/sysdeps/aarch64/multiarch/memcpy_sve.S b/sysdeps/aarch64/multiarch/memcpy_sve.S index a70907ec55..6bc8390fe8 100644 --- a/sysdeps/aarch64/multiarch/memcpy_sve.S +++ b/sysdeps/aarch64/multiarch/memcpy_sve.S @@ -67,14 +67,15 @@ ENTRY (__memcpy_sve) cmp count, 128 b.hi L(copy_long) - cmp count, 32 + cntb vlen + cmp count, vlen, lsl 1 b.hi L(copy32_128) - whilelo p0.b, xzr, count - cntb vlen - tbnz vlen, 4, L(vlen128) - ld1b z0.b, p0/z, [src] - st1b z0.b, p0, [dstin] + whilelo p1.b, vlen, count + ld1b z0.b, p0/z, [src, 0, mul vl] + ld1b z1.b, p1/z, [src, 1, mul vl] + st1b z0.b, p0, [dstin, 0, mul vl] + st1b z1.b, p1, [dstin, 1, mul vl] ret /* Medium copies: 33..128 bytes. */ @@ -102,14 +103,6 @@ L(copy96): stp C_q, D_q, [dstend, -32] ret -L(vlen128): - whilelo p1.b, vlen, count - ld1b z0.b, p0/z, [src, 0, mul vl] - ld1b z1.b, p1/z, [src, 1, mul vl] - st1b z0.b, p0, [dstin, 0, mul vl] - st1b z1.b, p1, [dstin, 1, mul vl] - ret - .p2align 4 /* Copy more than 128 bytes. */ L(copy_long): @@ -158,14 +151,15 @@ ENTRY (__memmove_sve) cmp count, 128 b.hi L(move_long) - cmp count, 32 + cntb vlen + cmp count, vlen, lsl 1 b.hi L(copy32_128) - whilelo p0.b, xzr, count - cntb vlen - tbnz vlen, 4, L(vlen128) - ld1b z0.b, p0/z, [src] - st1b z0.b, p0, [dstin] + whilelo p1.b, vlen, count + ld1b z0.b, p0/z, [src, 0, mul vl] + ld1b z1.b, p1/z, [src, 1, mul vl] + st1b z0.b, p0, [dstin, 0, mul vl] + st1b z1.b, p1, [dstin, 1, mul vl] ret .p2align 4 -- cgit 1.4.1 From aaa0fc324d695915ad1a3fe162942989e9dd6f5b Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Tue, 17 Oct 2023 13:13:27 +0000 Subject: Add HWCAP2_MOPS from Linux 6.5 to AArch64 bits/hwcap.h Linux 6.5 adds a new AArch64 HWCAP2 value, HWCAP2_MOPS. Add it to glibc's bits/hwcap.h. Tested with build-many-glibcs.py for aarch64-linux-gnu. (cherry picked from commit ff5d2abd18629e0efac41e31699cdff3be0e08fa) --- sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h b/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h index 616239bb84..b7ffea84e5 100644 --- a/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h +++ b/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h @@ -78,3 +78,24 @@ #define HWCAP2_AFP (1 << 20) #define HWCAP2_RPRES (1 << 21) #define HWCAP2_MTE3 (1 << 22) +#define HWCAP2_SME (1 << 23) +#define HWCAP2_SME_I16I64 (1 << 24) +#define HWCAP2_SME_F64F64 (1 << 25) +#define HWCAP2_SME_I8I32 (1 << 26) +#define HWCAP2_SME_F16F32 (1 << 27) +#define HWCAP2_SME_B16F32 (1 << 28) +#define HWCAP2_SME_F32F32 (1 << 29) +#define HWCAP2_SME_FA64 (1 << 30) +#define HWCAP2_WFXT (1UL << 31) +#define HWCAP2_EBF16 (1UL << 32) +#define HWCAP2_SVE_EBF16 (1UL << 33) +#define HWCAP2_CSSC (1UL << 34) +#define HWCAP2_RPRFM (1UL << 35) +#define HWCAP2_SVE2P1 (1UL << 36) +#define HWCAP2_SME2 (1UL << 37) +#define HWCAP2_SME2P1 (1UL << 38) +#define HWCAP2_SME_I16I32 (1UL << 39) +#define HWCAP2_SME_BI32I32 (1UL << 40) +#define HWCAP2_SME_B16B16 (1UL << 41) +#define HWCAP2_SME_F16F16 (1UL << 42) +#define HWCAP2_MOPS (1UL << 43) -- cgit 1.4.1 From 3bac018a985f202b36556dba9ae187cc8474342f Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Tue, 17 Oct 2023 16:54:21 +0100 Subject: AArch64: Add support for MOPS memcpy/memmove/memset Add support for MOPS in cpu_features and INIT_ARCH. Add ifuncs using MOPS for memcpy, memmove and memset (use .inst for now so it works with all binutils versions without needing complex configure and conditional compilation). Reviewed-by: Szabolcs Nagy (cherry picked from commit 2bd00179885928fd95fcabfafc50e7b5c6e660d2) --- sysdeps/aarch64/multiarch/Makefile | 3 ++ sysdeps/aarch64/multiarch/ifunc-impl-list.c | 3 ++ sysdeps/aarch64/multiarch/init-arch.h | 4 ++- sysdeps/aarch64/multiarch/memcpy.c | 4 +++ sysdeps/aarch64/multiarch/memcpy_mops.S | 39 ++++++++++++++++++++++++++ sysdeps/aarch64/multiarch/memmove.c | 4 +++ sysdeps/aarch64/multiarch/memmove_mops.S | 39 ++++++++++++++++++++++++++ sysdeps/aarch64/multiarch/memset.c | 4 +++ sysdeps/aarch64/multiarch/memset_mops.S | 38 +++++++++++++++++++++++++ sysdeps/unix/sysv/linux/aarch64/cpu-features.c | 3 ++ sysdeps/unix/sysv/linux/aarch64/cpu-features.h | 1 + 11 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 sysdeps/aarch64/multiarch/memcpy_mops.S create mode 100644 sysdeps/aarch64/multiarch/memmove_mops.S create mode 100644 sysdeps/aarch64/multiarch/memset_mops.S diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile index 223777d94e..e6099548b9 100644 --- a/sysdeps/aarch64/multiarch/Makefile +++ b/sysdeps/aarch64/multiarch/Makefile @@ -5,14 +5,17 @@ sysdep_routines += \ memcpy_a64fx \ memcpy_falkor \ memcpy_generic \ + memcpy_mops \ memcpy_sve \ memcpy_thunderx \ memcpy_thunderx2 \ + memmove_mops \ memset_a64fx \ memset_emag \ memset_falkor \ memset_generic \ memset_kunpeng \ + memset_mops \ strlen_asimd \ strlen_mte \ # sysdep_routines diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c index ac8980288e..b34972303f 100644 --- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c +++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c @@ -41,6 +41,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx) IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_sve) #endif + IFUNC_IMPL_ADD (array, i, memcpy, mops, __memcpy_mops) IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic)) IFUNC_IMPL (i, name, memmove, IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx) @@ -50,6 +51,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_a64fx) IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_sve) #endif + IFUNC_IMPL_ADD (array, i, memmove, mops, __memmove_mops) IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic)) IFUNC_IMPL (i, name, memset, /* Enable this on non-falkor processors too so that other cores @@ -60,6 +62,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, #if HAVE_AARCH64_SVE_ASM IFUNC_IMPL_ADD (array, i, memset, sve && zva_size == 256, __memset_a64fx) #endif + IFUNC_IMPL_ADD (array, i, memset, mops, __memset_mops) IFUNC_IMPL_ADD (array, i, memset, 1, __memset_generic)) IFUNC_IMPL (i, name, memchr, IFUNC_IMPL_ADD (array, i, memchr, !mte, __memchr_nosimd) diff --git a/sysdeps/aarch64/multiarch/init-arch.h b/sysdeps/aarch64/multiarch/init-arch.h index a4dcac0019..5da1656954 100644 --- a/sysdeps/aarch64/multiarch/init-arch.h +++ b/sysdeps/aarch64/multiarch/init-arch.h @@ -35,4 +35,6 @@ bool __attribute__((unused)) mte = \ MTE_ENABLED (); \ bool __attribute__((unused)) sve = \ - GLRO(dl_aarch64_cpu_features).sve; + GLRO(dl_aarch64_cpu_features).sve; \ + bool __attribute__((unused)) mops = \ + GLRO(dl_aarch64_cpu_features).mops; diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c index 21d954e7f3..2c279c254d 100644 --- a/sysdeps/aarch64/multiarch/memcpy.c +++ b/sysdeps/aarch64/multiarch/memcpy.c @@ -34,12 +34,16 @@ extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_a64fx attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_sve attribute_hidden; +extern __typeof (__redirect_memcpy) __memcpy_mops attribute_hidden; static inline __typeof (__redirect_memcpy) * select_memcpy_ifunc (void) { INIT_ARCH (); + if (mops) + return __memcpy_mops; + if (sve && HAVE_AARCH64_SVE_ASM) { if (IS_A64FX (midr)) diff --git a/sysdeps/aarch64/multiarch/memcpy_mops.S b/sysdeps/aarch64/multiarch/memcpy_mops.S new file mode 100644 index 0000000000..4685629664 --- /dev/null +++ b/sysdeps/aarch64/multiarch/memcpy_mops.S @@ -0,0 +1,39 @@ +/* Optimized memcpy for MOPS. + Copyright (C) 2023 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#include + +/* Assumptions: + * + * AArch64, MOPS. + * + */ + +ENTRY (__memcpy_mops) + PTR_ARG (0) + PTR_ARG (1) + SIZE_ARG (2) + + mov x3, x0 + .inst 0x19010443 /* cpyfp [x3]!, [x1]!, x2! */ + .inst 0x19410443 /* cpyfm [x3]!, [x1]!, x2! */ + .inst 0x19810443 /* cpyfe [x3]!, [x1]!, x2! */ + ret + +END (__memcpy_mops) diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c index 70e8eaef7c..6b19d0a560 100644 --- a/sysdeps/aarch64/multiarch/memmove.c +++ b/sysdeps/aarch64/multiarch/memmove.c @@ -34,12 +34,16 @@ extern __typeof (__redirect_memmove) __memmove_thunderx2 attribute_hidden; extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden; extern __typeof (__redirect_memmove) __memmove_a64fx attribute_hidden; extern __typeof (__redirect_memmove) __memmove_sve attribute_hidden; +extern __typeof (__redirect_memmove) __memmove_mops attribute_hidden; static inline __typeof (__redirect_memmove) * select_memmove_ifunc (void) { INIT_ARCH (); + if (mops) + return __memmove_mops; + if (sve && HAVE_AARCH64_SVE_ASM) { if (IS_A64FX (midr)) diff --git a/sysdeps/aarch64/multiarch/memmove_mops.S b/sysdeps/aarch64/multiarch/memmove_mops.S new file mode 100644 index 0000000000..c5ea66be3a --- /dev/null +++ b/sysdeps/aarch64/multiarch/memmove_mops.S @@ -0,0 +1,39 @@ +/* Optimized memmove for MOPS. + Copyright (C) 2023 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#include + +/* Assumptions: + * + * AArch64, MOPS. + * + */ + +ENTRY (__memmove_mops) + PTR_ARG (0) + PTR_ARG (1) + SIZE_ARG (2) + + mov x3, x0 + .inst 0x1d010443 /* cpyp [x3]!, [x1]!, x2! */ + .inst 0x1d410443 /* cpym [x3]!, [x1]!, x2! */ + .inst 0x1d810443 /* cpye [x3]!, [x1]!, x2! */ + ret + +END (__memmove_mops) diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c index 1e9ad2160c..32ded63725 100644 --- a/sysdeps/aarch64/multiarch/memset.c +++ b/sysdeps/aarch64/multiarch/memset.c @@ -33,12 +33,16 @@ extern __typeof (__redirect_memset) __memset_emag attribute_hidden; extern __typeof (__redirect_memset) __memset_kunpeng attribute_hidden; extern __typeof (__redirect_memset) __memset_a64fx attribute_hidden; extern __typeof (__redirect_memset) __memset_generic attribute_hidden; +extern __typeof (__redirect_memset) __memset_mops attribute_hidden; static inline __typeof (__redirect_memset) * select_memset_ifunc (void) { INIT_ARCH (); + if (mops) + return __memset_mops; + if (sve && HAVE_AARCH64_SVE_ASM) { if (IS_A64FX (midr) && zva_size == 256) diff --git a/sysdeps/aarch64/multiarch/memset_mops.S b/sysdeps/aarch64/multiarch/memset_mops.S new file mode 100644 index 0000000000..ca820b8636 --- /dev/null +++ b/sysdeps/aarch64/multiarch/memset_mops.S @@ -0,0 +1,38 @@ +/* Optimized memset for MOPS. + Copyright (C) 2023 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#include + +/* Assumptions: + * + * AArch64, MOPS. + * + */ + +ENTRY (__memset_mops) + PTR_ARG (0) + SIZE_ARG (2) + + mov x3, x0 + .inst 0x19c10443 /* setp [x3]!, x2!, x1 */ + .inst 0x19c14443 /* setm [x3]!, x2!, x1 */ + .inst 0x19c18443 /* sete [x3]!, x2!, x1 */ + ret + +END (__memset_mops) diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c index d14c0f4e1f..77549b0bdf 100644 --- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c @@ -126,4 +126,7 @@ init_cpu_features (struct cpu_features *cpu_features) /* Check if SVE is supported. */ cpu_features->sve = GLRO (dl_hwcap) & HWCAP_SVE; + + /* Check if MOPS is supported. */ + cpu_features->mops = GLRO (dl_hwcap2) & HWCAP2_MOPS; } diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h index 391165a99c..7e18062aa2 100644 --- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h +++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h @@ -76,6 +76,7 @@ struct cpu_features /* Currently, the GLIBC memory tagging tunable only defines 8 bits. */ uint8_t mte_state; bool sve; + bool mops; }; #endif /* _CPU_FEATURES_AARCH64_H */ -- cgit 1.4.1 From 6bb41218730dd042c53964b03cdb2a0835293991 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Tue, 24 Oct 2023 13:51:07 +0100 Subject: AArch64: Cleanup ifuncs Cleanup ifuncs. Remove uses of libc_hidden_builtin_def, use ENTRY rather than ENTRY_ALIGN, remove unnecessary defines and conditional compilation. Rename strlen_mte to strlen_generic. Remove rtld-memset. Reviewed-by: Szabolcs Nagy (cherry picked from commit 9fd3409842b3e2d31cff5dbd6f96066c430f0aa2) --- sysdeps/aarch64/memset.S | 2 +- sysdeps/aarch64/multiarch/Makefile | 2 +- sysdeps/aarch64/multiarch/ifunc-impl-list.c | 2 +- sysdeps/aarch64/multiarch/memchr_nosimd.S | 9 ++----- sysdeps/aarch64/multiarch/memcpy_a64fx.S | 14 +++------- sysdeps/aarch64/multiarch/memcpy_falkor.S | 6 ++--- sysdeps/aarch64/multiarch/memcpy_sve.S | 2 -- sysdeps/aarch64/multiarch/memcpy_thunderx.S | 27 ++++--------------- sysdeps/aarch64/multiarch/memcpy_thunderx2.S | 28 +++----------------- sysdeps/aarch64/multiarch/memset_a64fx.S | 8 ++---- sysdeps/aarch64/multiarch/memset_base64.S | 3 +-- sysdeps/aarch64/multiarch/memset_emag.S | 8 +++--- sysdeps/aarch64/multiarch/memset_generic.S | 8 +++++- sysdeps/aarch64/multiarch/memset_kunpeng.S | 9 ++----- sysdeps/aarch64/multiarch/rtld-memset.S | 25 ------------------ sysdeps/aarch64/multiarch/strlen.c | 4 +-- sysdeps/aarch64/multiarch/strlen_asimd.S | 1 - sysdeps/aarch64/multiarch/strlen_generic.S | 39 ++++++++++++++++++++++++++++ sysdeps/aarch64/multiarch/strlen_mte.S | 39 ---------------------------- 19 files changed, 76 insertions(+), 160 deletions(-) delete mode 100644 sysdeps/aarch64/multiarch/rtld-memset.S create mode 100644 sysdeps/aarch64/multiarch/strlen_generic.S delete mode 100644 sysdeps/aarch64/multiarch/strlen_mte.S diff --git a/sysdeps/aarch64/memset.S b/sysdeps/aarch64/memset.S index 957996bd19..0219f6cd6f 100644 --- a/sysdeps/aarch64/memset.S +++ b/sysdeps/aarch64/memset.S @@ -29,7 +29,7 @@ * */ -ENTRY_ALIGN (MEMSET, 6) +ENTRY (MEMSET) PTR_ARG (0) SIZE_ARG (2) diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile index e6099548b9..a1a4de3cd9 100644 --- a/sysdeps/aarch64/multiarch/Makefile +++ b/sysdeps/aarch64/multiarch/Makefile @@ -17,6 +17,6 @@ sysdep_routines += \ memset_kunpeng \ memset_mops \ strlen_asimd \ - strlen_mte \ + strlen_generic \ # sysdep_routines endif diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c index b34972303f..6947512a9b 100644 --- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c +++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c @@ -70,7 +70,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, strlen, IFUNC_IMPL_ADD (array, i, strlen, !mte, __strlen_asimd) - IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_mte)) + IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_generic)) return 0; } diff --git a/sysdeps/aarch64/multiarch/memchr_nosimd.S b/sysdeps/aarch64/multiarch/memchr_nosimd.S index ddf7533943..e39f39e6b3 100644 --- a/sysdeps/aarch64/multiarch/memchr_nosimd.S +++ b/sysdeps/aarch64/multiarch/memchr_nosimd.S @@ -26,10 +26,6 @@ * Use base integer registers. */ -#ifndef MEMCHR -# define MEMCHR __memchr_nosimd -#endif - /* Arguments and results. */ #define srcin x0 #define chrin x1 @@ -62,7 +58,7 @@ #define REP8_7f 0x7f7f7f7f7f7f7f7f -ENTRY_ALIGN (MEMCHR, 6) +ENTRY (__memchr_nosimd) PTR_ARG (0) SIZE_ARG (2) @@ -219,5 +215,4 @@ L(none_chr): mov result, 0 ret -END (MEMCHR) -libc_hidden_builtin_def (MEMCHR) +END (__memchr_nosimd) diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S index c4eab06176..c254dc8b9f 100644 --- a/sysdeps/aarch64/multiarch/memcpy_a64fx.S +++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S @@ -39,9 +39,6 @@ #define vlen8 x8 #if HAVE_AARCH64_SVE_ASM -# if IS_IN (libc) -# define MEMCPY __memcpy_a64fx -# define MEMMOVE __memmove_a64fx .arch armv8.2-a+sve @@ -97,7 +94,7 @@ #undef BTI_C #define BTI_C -ENTRY (MEMCPY) +ENTRY (__memcpy_a64fx) PTR_ARG (0) PTR_ARG (1) @@ -234,11 +231,10 @@ L(last_bytes): st1b z3.b, p0, [dstend, -1, mul vl] ret -END (MEMCPY) -libc_hidden_builtin_def (MEMCPY) +END (__memcpy_a64fx) -ENTRY_ALIGN (MEMMOVE, 4) +ENTRY_ALIGN (__memmove_a64fx, 4) PTR_ARG (0) PTR_ARG (1) @@ -307,7 +303,5 @@ L(full_overlap): mov dst, dstin b L(last_bytes) -END (MEMMOVE) -libc_hidden_builtin_def (MEMMOVE) -# endif /* IS_IN (libc) */ +END (__memmove_a64fx) #endif /* HAVE_AARCH64_SVE_ASM */ diff --git a/sysdeps/aarch64/multiarch/memcpy_falkor.S b/sysdeps/aarch64/multiarch/memcpy_falkor.S index 117edd9cfc..38db52e837 100644 --- a/sysdeps/aarch64/multiarch/memcpy_falkor.S +++ b/sysdeps/aarch64/multiarch/memcpy_falkor.S @@ -71,7 +71,7 @@ The non-temporal stores help optimize cache utilization. */ #if IS_IN (libc) -ENTRY_ALIGN (__memcpy_falkor, 6) +ENTRY (__memcpy_falkor) PTR_ARG (0) PTR_ARG (1) @@ -198,7 +198,6 @@ L(loop64): ret END (__memcpy_falkor) -libc_hidden_builtin_def (__memcpy_falkor) /* RATIONALE: @@ -216,7 +215,7 @@ libc_hidden_builtin_def (__memcpy_falkor) For small and medium cases memcpy is used. */ -ENTRY_ALIGN (__memmove_falkor, 6) +ENTRY (__memmove_falkor) PTR_ARG (0) PTR_ARG (1) @@ -311,5 +310,4 @@ L(move_long): 3: ret END (__memmove_falkor) -libc_hidden_builtin_def (__memmove_falkor) #endif diff --git a/sysdeps/aarch64/multiarch/memcpy_sve.S b/sysdeps/aarch64/multiarch/memcpy_sve.S index 6bc8390fe8..71d2f84f63 100644 --- a/sysdeps/aarch64/multiarch/memcpy_sve.S +++ b/sysdeps/aarch64/multiarch/memcpy_sve.S @@ -141,7 +141,6 @@ L(copy64_from_end): ret END (__memcpy_sve) -libc_hidden_builtin_def (__memcpy_sve) ENTRY (__memmove_sve) @@ -208,5 +207,4 @@ L(return): ret END (__memmove_sve) -libc_hidden_builtin_def (__memmove_sve) #endif diff --git a/sysdeps/aarch64/multiarch/memcpy_thunderx.S b/sysdeps/aarch64/multiarch/memcpy_thunderx.S index 21e703dddd..2fb6be5c78 100644 --- a/sysdeps/aarch64/multiarch/memcpy_thunderx.S +++ b/sysdeps/aarch64/multiarch/memcpy_thunderx.S @@ -65,21 +65,7 @@ Overlapping large forward memmoves use a loop that copies backwards. */ -#ifndef MEMMOVE -# define MEMMOVE memmove -#endif -#ifndef MEMCPY -# define MEMCPY memcpy -#endif - -#if IS_IN (libc) - -# undef MEMCPY -# define MEMCPY __memcpy_thunderx -# undef MEMMOVE -# define MEMMOVE __memmove_thunderx - -ENTRY_ALIGN (MEMMOVE, 6) +ENTRY (__memmove_thunderx) PTR_ARG (0) PTR_ARG (1) @@ -91,9 +77,9 @@ ENTRY_ALIGN (MEMMOVE, 6) b.lo L(move_long) /* Common case falls through into memcpy. */ -END (MEMMOVE) -libc_hidden_builtin_def (MEMMOVE) -ENTRY (MEMCPY) +END (__memmove_thunderx) + +ENTRY (__memcpy_thunderx) PTR_ARG (0) PTR_ARG (1) @@ -316,7 +302,4 @@ L(move_long): stp C_l, C_h, [dstin] 3: ret -END (MEMCPY) -libc_hidden_builtin_def (MEMCPY) - -#endif +END (__memcpy_thunderx) diff --git a/sysdeps/aarch64/multiarch/memcpy_thunderx2.S b/sysdeps/aarch64/multiarch/memcpy_thunderx2.S index 5e0a59ee5d..3fceb1036d 100644 --- a/sysdeps/aarch64/multiarch/memcpy_thunderx2.S +++ b/sysdeps/aarch64/multiarch/memcpy_thunderx2.S @@ -75,27 +75,12 @@ #define I_v v16 #define J_v v17 -#ifndef MEMMOVE -# define MEMMOVE memmove -#endif -#ifndef MEMCPY -# define MEMCPY memcpy -#endif - -#if IS_IN (libc) - -#undef MEMCPY -#define MEMCPY __memcpy_thunderx2 -#undef MEMMOVE -#define MEMMOVE __memmove_thunderx2 - - /* Overlapping large forward memmoves use a loop that copies backwards. Otherwise memcpy is used. Small moves branch to memcopy16 directly. The longer memcpy cases fall through to the memcpy head. */ -ENTRY_ALIGN (MEMMOVE, 6) +ENTRY (__memmove_thunderx2) PTR_ARG (0) PTR_ARG (1) @@ -109,8 +94,7 @@ ENTRY_ALIGN (MEMMOVE, 6) ccmp tmp1, count, 2, hi b.lo L(move_long) -END (MEMMOVE) -libc_hidden_builtin_def (MEMMOVE) +END (__memmove_thunderx2) /* Copies are split into 3 main cases: small copies of up to 16 bytes, @@ -124,8 +108,7 @@ libc_hidden_builtin_def (MEMMOVE) #define MEMCPY_PREFETCH_LDR 640 - .p2align 4 -ENTRY (MEMCPY) +ENTRY (__memcpy_thunderx2) PTR_ARG (0) PTR_ARG (1) @@ -449,7 +432,7 @@ L(move_long): 3: ret -END (MEMCPY) +END (__memcpy_thunderx2) .section .rodata .p2align 4 @@ -472,6 +455,3 @@ L(ext_table): .word L(ext_size_13) -. .word L(ext_size_14) -. .word L(ext_size_15) -. - -libc_hidden_builtin_def (MEMCPY) -#endif diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S index dc87190724..4a4d4ed504 100644 --- a/sysdeps/aarch64/multiarch/memset_a64fx.S +++ b/sysdeps/aarch64/multiarch/memset_a64fx.S @@ -33,8 +33,6 @@ #define vector_length x9 #if HAVE_AARCH64_SVE_ASM -# if IS_IN (libc) -# define MEMSET __memset_a64fx .arch armv8.2-a+sve @@ -49,7 +47,7 @@ #undef BTI_C #define BTI_C -ENTRY (MEMSET) +ENTRY (__memset_a64fx) PTR_ARG (0) SIZE_ARG (2) @@ -166,8 +164,6 @@ L(L2): add count, count, CACHE_LINE_SIZE b L(last) -END (MEMSET) -libc_hidden_builtin_def (MEMSET) +END (__memset_a64fx) -#endif /* IS_IN (libc) */ #endif /* HAVE_AARCH64_SVE_ASM */ diff --git a/sysdeps/aarch64/multiarch/memset_base64.S b/sysdeps/aarch64/multiarch/memset_base64.S index 32d20d739e..8d3e1e1b7f 100644 --- a/sysdeps/aarch64/multiarch/memset_base64.S +++ b/sysdeps/aarch64/multiarch/memset_base64.S @@ -34,7 +34,7 @@ * */ -ENTRY_ALIGN (MEMSET, 6) +ENTRY (MEMSET) PTR_ARG (0) SIZE_ARG (2) @@ -183,4 +183,3 @@ L(zva_64): #endif END (MEMSET) -libc_hidden_builtin_def (MEMSET) diff --git a/sysdeps/aarch64/multiarch/memset_emag.S b/sysdeps/aarch64/multiarch/memset_emag.S index 922c1ed57d..a1d31cd9ac 100644 --- a/sysdeps/aarch64/multiarch/memset_emag.S +++ b/sysdeps/aarch64/multiarch/memset_emag.S @@ -19,8 +19,7 @@ #include -#if IS_IN (libc) -# define MEMSET __memset_emag +#define MEMSET __memset_emag /* * Using DC ZVA to zero memory does not produce better performance if @@ -30,7 +29,6 @@ * workloads. */ -# define DC_ZVA_THRESHOLD 0 +#define DC_ZVA_THRESHOLD 0 -# include "./memset_base64.S" -#endif +#include "./memset_base64.S" diff --git a/sysdeps/aarch64/multiarch/memset_generic.S b/sysdeps/aarch64/multiarch/memset_generic.S index c879be93d5..6efcb5f00d 100644 --- a/sysdeps/aarch64/multiarch/memset_generic.S +++ b/sysdeps/aarch64/multiarch/memset_generic.S @@ -21,9 +21,15 @@ #if IS_IN (libc) # define MEMSET __memset_generic + +/* Do not hide the generic version of memset, we use it internally. */ +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(name) + /* Add a hidden definition for use within libc.so. */ # ifdef SHARED .globl __GI_memset; __GI_memset = __memset_generic # endif -# include #endif + +#include <../memset.S> diff --git a/sysdeps/aarch64/multiarch/memset_kunpeng.S b/sysdeps/aarch64/multiarch/memset_kunpeng.S index a6d2c8c3bb..8f2deddb74 100644 --- a/sysdeps/aarch64/multiarch/memset_kunpeng.S +++ b/sysdeps/aarch64/multiarch/memset_kunpeng.S @@ -20,16 +20,13 @@ #include #include -#if IS_IN (libc) -# define MEMSET __memset_kunpeng - /* Assumptions: * * ARMv8-a, AArch64, unaligned accesses * */ -ENTRY_ALIGN (MEMSET, 6) +ENTRY (__memset_kunpeng) PTR_ARG (0) SIZE_ARG (2) @@ -108,6 +105,4 @@ L(set_long): stp q0, q0, [dstend, -32] ret -END (MEMSET) -libc_hidden_builtin_def (MEMSET) -#endif +END (__memset_kunpeng) diff --git a/sysdeps/aarch64/multiarch/rtld-memset.S b/sysdeps/aarch64/multiarch/rtld-memset.S deleted file mode 100644 index 7968d25e48..0000000000 --- a/sysdeps/aarch64/multiarch/rtld-memset.S +++ /dev/null @@ -1,25 +0,0 @@ -/* Memset for aarch64, for the dynamic linker. - Copyright (C) 2017-2022 Free Software Foundation, Inc. - - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#include - -#if IS_IN (rtld) -# define MEMSET memset -# include -#endif diff --git a/sysdeps/aarch64/multiarch/strlen.c b/sysdeps/aarch64/multiarch/strlen.c index 6d27c126b0..a951967fcd 100644 --- a/sysdeps/aarch64/multiarch/strlen.c +++ b/sysdeps/aarch64/multiarch/strlen.c @@ -28,10 +28,10 @@ extern __typeof (__redirect_strlen) __strlen; -extern __typeof (__redirect_strlen) __strlen_mte attribute_hidden; +extern __typeof (__redirect_strlen) __strlen_generic attribute_hidden; extern __typeof (__redirect_strlen) __strlen_asimd attribute_hidden; -libc_ifunc (__strlen, (mte ? __strlen_mte : __strlen_asimd)); +libc_ifunc (__strlen, (mte ? __strlen_generic : __strlen_asimd)); # undef strlen strong_alias (__strlen, strlen); diff --git a/sysdeps/aarch64/multiarch/strlen_asimd.S b/sysdeps/aarch64/multiarch/strlen_asimd.S index 13386eb5d4..dcd4589d10 100644 --- a/sysdeps/aarch64/multiarch/strlen_asimd.S +++ b/sysdeps/aarch64/multiarch/strlen_asimd.S @@ -203,4 +203,3 @@ L(page_cross): ret END (__strlen_asimd) -libc_hidden_builtin_def (__strlen_asimd) diff --git a/sysdeps/aarch64/multiarch/strlen_generic.S b/sysdeps/aarch64/multiarch/strlen_generic.S new file mode 100644 index 0000000000..014e376ec1 --- /dev/null +++ b/sysdeps/aarch64/multiarch/strlen_generic.S @@ -0,0 +1,39 @@ +/* A Generic Optimized strlen implementation for AARCH64. + Copyright (C) 2018-2022 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 + . */ + +/* The actual strlen code is in ../strlen.S. If we are building libc this file + defines __strlen_generic. Otherwise the include of ../strlen.S will define + the normal __strlen entry points. */ + +#include + +#if IS_IN (libc) + +# define STRLEN __strlen_generic + +/* Do not hide the generic version of strlen, we use it internally. */ +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(name) + +# ifdef SHARED +/* It doesn't make sense to send libc-internal strlen calls through a PLT. */ + .globl __GI_strlen; __GI_strlen = __strlen_generic +# endif +#endif + +#include "../strlen.S" diff --git a/sysdeps/aarch64/multiarch/strlen_mte.S b/sysdeps/aarch64/multiarch/strlen_mte.S deleted file mode 100644 index bf03ac53eb..0000000000 --- a/sysdeps/aarch64/multiarch/strlen_mte.S +++ /dev/null @@ -1,39 +0,0 @@ -/* A Generic Optimized strlen implementation for AARCH64. - Copyright (C) 2018-2022 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 - . */ - -/* The actual strlen code is in ../strlen.S. If we are building libc this file - defines __strlen_mte. Otherwise the include of ../strlen.S will define - the normal __strlen entry points. */ - -#include - -#if IS_IN (libc) - -# define STRLEN __strlen_mte - -/* Do not hide the generic version of strlen, we use it internally. */ -# undef libc_hidden_builtin_def -# define libc_hidden_builtin_def(name) - -# ifdef SHARED -/* It doesn't make sense to send libc-internal strlen calls through a PLT. */ - .globl __GI_strlen; __GI_strlen = __strlen_mte -# endif -#endif - -#include "../strlen.S" -- cgit 1.4.1 From f9ae26cbbec008eb572a2af8a743ea7d3945e78e Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Thu, 26 Oct 2023 16:34:47 +0100 Subject: AArch64: Cleanup emag memset Cleanup emag memset - merge the memset_base64.S file, remove the unused ZVA code (since it is disabled on emag). Reviewed-by: Adhemerval Zanella (cherry picked from commit 9627ab99b50d250c6dd3001a3355aa03692f7fe5) --- sysdeps/aarch64/multiarch/ifunc-impl-list.c | 2 +- sysdeps/aarch64/multiarch/memset.c | 2 +- sysdeps/aarch64/multiarch/memset_base64.S | 185 ---------------------------- sysdeps/aarch64/multiarch/memset_emag.S | 98 +++++++++++++-- 4 files changed, 90 insertions(+), 197 deletions(-) delete mode 100644 sysdeps/aarch64/multiarch/memset_base64.S diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c index 6947512a9b..d651311b4b 100644 --- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c +++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c @@ -57,7 +57,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, /* Enable this on non-falkor processors too so that other cores can do a comparative analysis with __memset_generic. */ IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_falkor) - IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_emag) + IFUNC_IMPL_ADD (array, i, memset, 1, __memset_emag) IFUNC_IMPL_ADD (array, i, memset, 1, __memset_kunpeng) #if HAVE_AARCH64_SVE_ASM IFUNC_IMPL_ADD (array, i, memset, sve && zva_size == 256, __memset_a64fx) diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c index 32ded63725..7dd9fddc8d 100644 --- a/sysdeps/aarch64/multiarch/memset.c +++ b/sysdeps/aarch64/multiarch/memset.c @@ -56,7 +56,7 @@ select_memset_ifunc (void) if ((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64) return __memset_falkor; - if (IS_EMAG (midr) && zva_size == 64) + if (IS_EMAG (midr)) return __memset_emag; return __memset_generic; diff --git a/sysdeps/aarch64/multiarch/memset_base64.S b/sysdeps/aarch64/multiarch/memset_base64.S deleted file mode 100644 index 8d3e1e1b7f..0000000000 --- a/sysdeps/aarch64/multiarch/memset_base64.S +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (C) 2018-2022 Free Software Foundation, Inc. - - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#include -#include "memset-reg.h" - -#ifndef MEMSET -# define MEMSET __memset_base64 -#endif - -/* To disable DC ZVA, set this threshold to 0. */ -#ifndef DC_ZVA_THRESHOLD -# define DC_ZVA_THRESHOLD 512 -#endif - -/* Assumptions: - * - * ARMv8-a, AArch64, unaligned accesses - * - */ - -ENTRY (MEMSET) - - PTR_ARG (0) - SIZE_ARG (2) - - bfi valw, valw, 8, 8 - bfi valw, valw, 16, 16 - bfi val, val, 32, 32 - - add dstend, dstin, count - - cmp count, 96 - b.hi L(set_long) - cmp count, 16 - b.hs L(set_medium) - - /* Set 0..15 bytes. */ - tbz count, 3, 1f - str val, [dstin] - str val, [dstend, -8] - ret - - .p2align 3 -1: tbz count, 2, 2f - str valw, [dstin] - str valw, [dstend, -4] - ret -2: cbz count, 3f - strb valw, [dstin] - tbz count, 1, 3f - strh valw, [dstend, -2] -3: ret - - .p2align 3 - /* Set 16..96 bytes. */ -L(set_medium): - stp val, val, [dstin] - tbnz count, 6, L(set96) - stp val, val, [dstend, -16] - tbz count, 5, 1f - stp val, val, [dstin, 16] - stp val, val, [dstend, -32] -1: ret - - .p2align 4 - /* Set 64..96 bytes. Write 64 bytes from the start and - 32 bytes from the end. */ -L(set96): - stp val, val, [dstin, 16] - stp val, val, [dstin, 32] - stp val, val, [dstin, 48] - stp val, val, [dstend, -32] - stp val, val, [dstend, -16] - ret - - .p2align 4 -L(set_long): - stp val, val, [dstin] - bic dst, dstin, 15 -#if DC_ZVA_THRESHOLD - cmp count, DC_ZVA_THRESHOLD - ccmp val, 0, 0, cs - b.eq L(zva_64) -#endif - /* Small-size or non-zero memset does not use DC ZVA. */ - sub count, dstend, dst - - /* - * Adjust count and bias for loop. By substracting extra 1 from count, - * it is easy to use tbz instruction to check whether loop tailing - * count is less than 33 bytes, so as to bypass 2 unneccesary stps. - */ - sub count, count, 64+16+1 - -#if DC_ZVA_THRESHOLD - /* Align loop on 16-byte boundary, this might be friendly to i-cache. */ - nop -#endif - -1: stp val, val, [dst, 16] - stp val, val, [dst, 32] - stp val, val, [dst, 48] - stp val, val, [dst, 64]! - subs count, count, 64 - b.hs 1b - - tbz count, 5, 1f /* Remaining count is less than 33 bytes? */ - stp val, val, [dst, 16] - stp val, val, [dst, 32] -1: stp val, val, [dstend, -32] - stp val, val, [dstend, -16] - ret - -#if DC_ZVA_THRESHOLD - .p2align 3 -L(zva_64): - stp val, val, [dst, 16] - stp val, val, [dst, 32] - stp val, val, [dst, 48] - bic dst, dst, 63 - - /* - * Previous memory writes might cross cache line boundary, and cause - * cache line partially dirty. Zeroing this kind of cache line using - * DC ZVA will incur extra cost, for it requires loading untouched - * part of the line from memory before zeoring. - * - * So, write the first 64 byte aligned block using stp to force - * fully dirty cache line. - */ - stp val, val, [dst, 64] - stp val, val, [dst, 80] - stp val, val, [dst, 96] - stp val, val, [dst, 112] - - sub count, dstend, dst - /* - * Adjust count and bias for loop. By substracting extra 1 from count, - * it is easy to use tbz instruction to check whether loop tailing - * count is less than 33 bytes, so as to bypass 2 unneccesary stps. - */ - sub count, count, 128+64+64+1 - add dst, dst, 128 - nop - - /* DC ZVA sets 64 bytes each time. */ -1: dc zva, dst - add dst, dst, 64 - subs count, count, 64 - b.hs 1b - - /* - * Write the last 64 byte aligned block using stp to force fully - * dirty cache line. - */ - stp val, val, [dst, 0] - stp val, val, [dst, 16] - stp val, val, [dst, 32] - stp val, val, [dst, 48] - - tbz count, 5, 1f /* Remaining count is less than 33 bytes? */ - stp val, val, [dst, 64] - stp val, val, [dst, 80] -1: stp val, val, [dstend, -32] - stp val, val, [dstend, -16] - ret -#endif - -END (MEMSET) diff --git a/sysdeps/aarch64/multiarch/memset_emag.S b/sysdeps/aarch64/multiarch/memset_emag.S index a1d31cd9ac..7ecf61dc59 100644 --- a/sysdeps/aarch64/multiarch/memset_emag.S +++ b/sysdeps/aarch64/multiarch/memset_emag.S @@ -18,17 +18,95 @@ . */ #include +#include "memset-reg.h" -#define MEMSET __memset_emag - -/* - * Using DC ZVA to zero memory does not produce better performance if - * memory size is not very large, especially when there are multiple - * processes/threads contending memory/cache. Here we set threshold to - * zero to disable using DC ZVA, which is good for multi-process/thread - * workloads. +/* Assumptions: + * + * ARMv8-a, AArch64, unaligned accesses + * */ -#define DC_ZVA_THRESHOLD 0 +ENTRY (__memset_emag) + + PTR_ARG (0) + SIZE_ARG (2) + + bfi valw, valw, 8, 8 + bfi valw, valw, 16, 16 + bfi val, val, 32, 32 + + add dstend, dstin, count + + cmp count, 96 + b.hi L(set_long) + cmp count, 16 + b.hs L(set_medium) + + /* Set 0..15 bytes. */ + tbz count, 3, 1f + str val, [dstin] + str val, [dstend, -8] + ret + + .p2align 3 +1: tbz count, 2, 2f + str valw, [dstin] + str valw, [dstend, -4] + ret +2: cbz count, 3f + strb valw, [dstin] + tbz count, 1, 3f + strh valw, [dstend, -2] +3: ret + + .p2align 3 + /* Set 16..96 bytes. */ +L(set_medium): + stp val, val, [dstin] + tbnz count, 6, L(set96) + stp val, val, [dstend, -16] + tbz count, 5, 1f + stp val, val, [dstin, 16] + stp val, val, [dstend, -32] +1: ret + + .p2align 4 + /* Set 64..96 bytes. Write 64 bytes from the start and + 32 bytes from the end. */ +L(set96): + stp val, val, [dstin, 16] + stp val, val, [dstin, 32] + stp val, val, [dstin, 48] + stp val, val, [dstend, -32] + stp val, val, [dstend, -16] + ret + + .p2align 4 +L(set_long): + stp val, val, [dstin] + bic dst, dstin, 15 + /* Small-size or non-zero memset does not use DC ZVA. */ + sub count, dstend, dst + + /* + * Adjust count and bias for loop. By subtracting extra 1 from count, + * it is easy to use tbz instruction to check whether loop tailing + * count is less than 33 bytes, so as to bypass 2 unnecessary stps. + */ + sub count, count, 64+16+1 + +1: stp val, val, [dst, 16] + stp val, val, [dst, 32] + stp val, val, [dst, 48] + stp val, val, [dst, 64]! + subs count, count, 64 + b.hs 1b + + tbz count, 5, 1f /* Remaining count is less than 33 bytes? */ + stp val, val, [dst, 16] + stp val, val, [dst, 32] +1: stp val, val, [dstend, -32] + stp val, val, [dstend, -16] + ret -#include "./memset_base64.S" +END (__memset_emag) -- cgit 1.4.1 From 1da017615277676054c47d99b030230e295d8583 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Thu, 26 Oct 2023 17:07:21 +0100 Subject: AArch64: Add memset_zva64 Add a specialized memset for the common ZVA size of 64 to avoid the overhead of reading the ZVA size. Since the code is identical to __memset_falkor, remove the latter. Reviewed-by: Adhemerval Zanella (cherry picked from commit 3d7090f14b13312320e425b27dcf0fe72de026fd) --- sysdeps/aarch64/memset.S | 10 +++--- sysdeps/aarch64/multiarch/Makefile | 2 +- sysdeps/aarch64/multiarch/ifunc-impl-list.c | 4 +-- sysdeps/aarch64/multiarch/memset.c | 9 +++-- sysdeps/aarch64/multiarch/memset_falkor.S | 54 ----------------------------- sysdeps/aarch64/multiarch/memset_zva64.S | 27 +++++++++++++++ 6 files changed, 38 insertions(+), 68 deletions(-) delete mode 100644 sysdeps/aarch64/multiarch/memset_falkor.S create mode 100644 sysdeps/aarch64/multiarch/memset_zva64.S diff --git a/sysdeps/aarch64/memset.S b/sysdeps/aarch64/memset.S index 0219f6cd6f..b76d1c3e5e 100644 --- a/sysdeps/aarch64/memset.S +++ b/sysdeps/aarch64/memset.S @@ -101,19 +101,19 @@ L(tail64): ret L(try_zva): -#ifdef ZVA_MACRO - zva_macro -#else +#ifndef ZVA64_ONLY .p2align 3 mrs tmp1, dczid_el0 tbnz tmp1w, 4, L(no_zva) and tmp1w, tmp1w, 15 cmp tmp1w, 4 /* ZVA size is 64 bytes. */ b.ne L(zva_128) - + nop +#endif /* Write the first and last 64 byte aligned block using stp rather than using DC ZVA. This is faster on some cores. */ + .p2align 4 L(zva_64): str q0, [dst, 16] stp q0, q0, [dst, 32] @@ -123,7 +123,6 @@ L(zva_64): sub count, dstend, dst /* Count is now 128 too large. */ sub count, count, 128+64+64 /* Adjust count and bias for loop. */ add dst, dst, 128 - nop 1: dc zva, dst add dst, dst, 64 subs count, count, 64 @@ -134,6 +133,7 @@ L(zva_64): stp q0, q0, [dstend, -32] ret +#ifndef ZVA64_ONLY .p2align 3 L(zva_128): cmp tmp1w, 5 /* ZVA size is 128 bytes. */ diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile index a1a4de3cd9..171ca5e4cf 100644 --- a/sysdeps/aarch64/multiarch/Makefile +++ b/sysdeps/aarch64/multiarch/Makefile @@ -12,10 +12,10 @@ sysdep_routines += \ memmove_mops \ memset_a64fx \ memset_emag \ - memset_falkor \ memset_generic \ memset_kunpeng \ memset_mops \ + memset_zva64 \ strlen_asimd \ strlen_generic \ # sysdep_routines diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c index d651311b4b..e9076f8081 100644 --- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c +++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c @@ -54,9 +54,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL_ADD (array, i, memmove, mops, __memmove_mops) IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic)) IFUNC_IMPL (i, name, memset, - /* Enable this on non-falkor processors too so that other cores - can do a comparative analysis with __memset_generic. */ - IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_falkor) + IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_zva64) IFUNC_IMPL_ADD (array, i, memset, 1, __memset_emag) IFUNC_IMPL_ADD (array, i, memset, 1, __memset_kunpeng) #if HAVE_AARCH64_SVE_ASM diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c index 7dd9fddc8d..9ef9521fa6 100644 --- a/sysdeps/aarch64/multiarch/memset.c +++ b/sysdeps/aarch64/multiarch/memset.c @@ -28,7 +28,7 @@ extern __typeof (__redirect_memset) __libc_memset; -extern __typeof (__redirect_memset) __memset_falkor attribute_hidden; +extern __typeof (__redirect_memset) __memset_zva64 attribute_hidden; extern __typeof (__redirect_memset) __memset_emag attribute_hidden; extern __typeof (__redirect_memset) __memset_kunpeng attribute_hidden; extern __typeof (__redirect_memset) __memset_a64fx attribute_hidden; @@ -47,18 +47,17 @@ select_memset_ifunc (void) { if (IS_A64FX (midr) && zva_size == 256) return __memset_a64fx; - return __memset_generic; } if (IS_KUNPENG920 (midr)) return __memset_kunpeng; - if ((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64) - return __memset_falkor; - if (IS_EMAG (midr)) return __memset_emag; + if (zva_size == 64) + return __memset_zva64; + return __memset_generic; } diff --git a/sysdeps/aarch64/multiarch/memset_falkor.S b/sysdeps/aarch64/multiarch/memset_falkor.S deleted file mode 100644 index 657f4c60b4..0000000000 --- a/sysdeps/aarch64/multiarch/memset_falkor.S +++ /dev/null @@ -1,54 +0,0 @@ -/* Memset for falkor. - Copyright (C) 2017-2022 Free Software Foundation, Inc. - - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#include -#include - -/* Reading dczid_el0 is expensive on falkor so move it into the ifunc - resolver and assume ZVA size of 64 bytes. The IFUNC resolver takes care to - use this function only when ZVA is enabled. */ - -#if IS_IN (libc) -.macro zva_macro - .p2align 4 - /* Write the first and last 64 byte aligned block using stp rather - than using DC ZVA. This is faster on some cores. */ - str q0, [dst, 16] - stp q0, q0, [dst, 32] - bic dst, dst, 63 - stp q0, q0, [dst, 64] - stp q0, q0, [dst, 96] - sub count, dstend, dst /* Count is now 128 too large. */ - sub count, count, 128+64+64 /* Adjust count and bias for loop. */ - add dst, dst, 128 -1: dc zva, dst - add dst, dst, 64 - subs count, count, 64 - b.hi 1b - stp q0, q0, [dst, 0] - stp q0, q0, [dst, 32] - stp q0, q0, [dstend, -64] - stp q0, q0, [dstend, -32] - ret -.endm - -# define ZVA_MACRO zva_macro -# define MEMSET __memset_falkor -# include -#endif diff --git a/sysdeps/aarch64/multiarch/memset_zva64.S b/sysdeps/aarch64/multiarch/memset_zva64.S new file mode 100644 index 0000000000..13f45fd3d8 --- /dev/null +++ b/sysdeps/aarch64/multiarch/memset_zva64.S @@ -0,0 +1,27 @@ +/* Optimized memset for zva size = 64. + Copyright (C) 2023 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#include + +#define ZVA64_ONLY 1 +#define MEMSET __memset_zva64 +#undef libc_hidden_builtin_def +#define libc_hidden_builtin_def(X) + +#include "../memset.S" -- cgit 1.4.1 From 5a5211b4384546ed4554a9431b884dc75766b941 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Thu, 26 Oct 2023 17:30:36 +0100 Subject: AArch64: Remove Falkor memcpy The latest implementations of memcpy are actually faster than the Falkor implementations [1], so remove the falkor/phecda ifuncs for memcpy and the now unused IS_FALKOR/IS_PHECDA defines. [1] https://sourceware.org/pipermail/libc-alpha/2022-December/144227.html Reviewed-by: Adhemerval Zanella (cherry picked from commit 2f5524cc5381eb75fef55f7901bb907bd5628333) --- manual/tunables.texi | 2 +- sysdeps/aarch64/multiarch/Makefile | 1 - sysdeps/aarch64/multiarch/ifunc-impl-list.c | 2 - sysdeps/aarch64/multiarch/memcpy.c | 4 - sysdeps/aarch64/multiarch/memcpy_falkor.S | 313 ------------------------- sysdeps/aarch64/multiarch/memmove.c | 4 - sysdeps/unix/sysv/linux/aarch64/cpu-features.c | 2 - sysdeps/unix/sysv/linux/aarch64/cpu-features.h | 5 - 8 files changed, 1 insertion(+), 332 deletions(-) delete mode 100644 sysdeps/aarch64/multiarch/memcpy_falkor.S diff --git a/manual/tunables.texi b/manual/tunables.texi index 83cdcdac6d..ab5145ce0c 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -502,7 +502,7 @@ This tunable is specific to powerpc, powerpc64 and powerpc64le. @deftp Tunable glibc.cpu.name The @code{glibc.cpu.name=xxx} tunable allows the user to tell @theglibc{} to assume that the CPU is @code{xxx} where xxx may have one of these values: -@code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99}, +@code{generic}, @code{thunderxt88}, @code{thunderx2t99}, @code{thunderx2t99p1}, @code{ares}, @code{emag}, @code{kunpeng}, @code{a64fx}. diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile index 171ca5e4cf..e4720b7468 100644 --- a/sysdeps/aarch64/multiarch/Makefile +++ b/sysdeps/aarch64/multiarch/Makefile @@ -3,7 +3,6 @@ sysdep_routines += \ memchr_generic \ memchr_nosimd \ memcpy_a64fx \ - memcpy_falkor \ memcpy_generic \ memcpy_mops \ memcpy_sve \ diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c index e9076f8081..1c712ce913 100644 --- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c +++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c @@ -36,7 +36,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, memcpy, IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx) IFUNC_IMPL_ADD (array, i, memcpy, !bti, __memcpy_thunderx2) - IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor) #if HAVE_AARCH64_SVE_ASM IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx) IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_sve) @@ -46,7 +45,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_IMPL (i, name, memmove, IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx) IFUNC_IMPL_ADD (array, i, memmove, !bti, __memmove_thunderx2) - IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor) #if HAVE_AARCH64_SVE_ASM IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_a64fx) IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_sve) diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c index 2c279c254d..d1cf5bec16 100644 --- a/sysdeps/aarch64/multiarch/memcpy.c +++ b/sysdeps/aarch64/multiarch/memcpy.c @@ -31,7 +31,6 @@ extern __typeof (__redirect_memcpy) __libc_memcpy; extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden; -extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_a64fx attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_sve attribute_hidden; extern __typeof (__redirect_memcpy) __memcpy_mops attribute_hidden; @@ -57,9 +56,6 @@ select_memcpy_ifunc (void) if (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)) return __memcpy_thunderx2; - if (IS_FALKOR (midr) || IS_PHECDA (midr)) - return __memcpy_falkor; - return __memcpy_generic; } diff --git a/sysdeps/aarch64/multiarch/memcpy_falkor.S b/sysdeps/aarch64/multiarch/memcpy_falkor.S deleted file mode 100644 index 38db52e837..0000000000 --- a/sysdeps/aarch64/multiarch/memcpy_falkor.S +++ /dev/null @@ -1,313 +0,0 @@ -/* Optimized memcpy for Qualcomm Falkor processor. - Copyright (C) 2017-2022 Free Software Foundation, Inc. - - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#include - -/* Assumptions: - - ARMv8-a, AArch64, falkor, unaligned accesses. */ - -#define dstin x0 -#define src x1 -#define count x2 -#define dst x3 -#define srcend x4 -#define dstend x5 -#define tmp1 x14 -#define A_x x6 -#define B_x x7 -#define A_w w6 -#define B_w w7 - -#define A_q q0 -#define B_q q1 -#define C_q q2 -#define D_q q3 -#define E_q q4 -#define F_q q5 -#define G_q q6 -#define H_q q7 -#define Q_q q6 -#define S_q q22 - -/* Copies are split into 3 main cases: - - 1. Small copies of up to 32 bytes - 2. Medium copies of 33..128 bytes which are fully unrolled - 3. Large copies of more than 128 bytes. - - Large copies align the source to a quad word and use an unrolled loop - processing 64 bytes per iteration. - - FALKOR-SPECIFIC DESIGN: - - The smallest copies (32 bytes or less) focus on optimal pipeline usage, - which is why the redundant copies of 0-3 bytes have been replaced with - conditionals, since the former would unnecessarily break across multiple - issue groups. The medium copy group has been enlarged to 128 bytes since - bumping up the small copies up to 32 bytes allows us to do that without - cost and also allows us to reduce the size of the prep code before loop64. - - The copy loop uses only one register q0. This is to ensure that all loads - hit a single hardware prefetcher which can get correctly trained to prefetch - a single stream. - - The non-temporal stores help optimize cache utilization. */ - -#if IS_IN (libc) -ENTRY (__memcpy_falkor) - - PTR_ARG (0) - PTR_ARG (1) - SIZE_ARG (2) - - cmp count, 32 - add srcend, src, count - add dstend, dstin, count - b.ls L(copy32) - cmp count, 128 - b.hi L(copy_long) - - /* Medium copies: 33..128 bytes. */ -L(copy128): - sub tmp1, count, 1 - ldr A_q, [src] - ldr B_q, [src, 16] - ldr C_q, [srcend, -32] - ldr D_q, [srcend, -16] - tbz tmp1, 6, 1f - ldr E_q, [src, 32] - ldr F_q, [src, 48] - ldr G_q, [srcend, -64] - ldr H_q, [srcend, -48] - str G_q, [dstend, -64] - str H_q, [dstend, -48] - str E_q, [dstin, 32] - str F_q, [dstin, 48] -1: - str A_q, [dstin] - str B_q, [dstin, 16] - str C_q, [dstend, -32] - str D_q, [dstend, -16] - ret - - .p2align 4 - /* Small copies: 0..32 bytes. */ -L(copy32): - /* 16-32 */ - cmp count, 16 - b.lo 1f - ldr A_q, [src] - ldr B_q, [srcend, -16] - str A_q, [dstin] - str B_q, [dstend, -16] - ret - .p2align 4 -1: - /* 8-15 */ - tbz count, 3, 1f - ldr A_x, [src] - ldr B_x, [srcend, -8] - str A_x, [dstin] - str B_x, [dstend, -8] - ret - .p2align 4 -1: - /* 4-7 */ - tbz count, 2, 1f - ldr A_w, [src] - ldr B_w, [srcend, -4] - str A_w, [dstin] - str B_w, [dstend, -4] - ret - .p2align 4 -1: - /* 2-3 */ - tbz count, 1, 1f - ldrh A_w, [src] - ldrh B_w, [srcend, -2] - strh A_w, [dstin] - strh B_w, [dstend, -2] - ret - .p2align 4 -1: - /* 0-1 */ - tbz count, 0, 1f - ldrb A_w, [src] - strb A_w, [dstin] -1: - ret - - /* Align SRC to 16 bytes and copy; that way at least one of the - accesses is aligned throughout the copy sequence. - - The count is off by 0 to 15 bytes, but this is OK because we trim - off the last 64 bytes to copy off from the end. Due to this the - loop never runs out of bounds. */ - - .p2align 4 - nop /* Align loop64 below. */ -L(copy_long): - ldr A_q, [src] - sub count, count, 64 + 16 - and tmp1, src, 15 - str A_q, [dstin] - bic src, src, 15 - sub dst, dstin, tmp1 - add count, count, tmp1 - -L(loop64): - ldr A_q, [src, 16]! - str A_q, [dst, 16] - ldr A_q, [src, 16]! - subs count, count, 64 - str A_q, [dst, 32] - ldr A_q, [src, 16]! - str A_q, [dst, 48] - ldr A_q, [src, 16]! - str A_q, [dst, 64]! - b.hi L(loop64) - - /* Write the last full set of 64 bytes. The remainder is at most 64 - bytes, so it is safe to always copy 64 bytes from the end even if - there is just 1 byte left. */ - ldr E_q, [srcend, -64] - str E_q, [dstend, -64] - ldr D_q, [srcend, -48] - str D_q, [dstend, -48] - ldr C_q, [srcend, -32] - str C_q, [dstend, -32] - ldr B_q, [srcend, -16] - str B_q, [dstend, -16] - ret - -END (__memcpy_falkor) - - -/* RATIONALE: - - The move has 4 distinct parts: - * Small moves of 32 bytes and under. - * Medium sized moves of 33-128 bytes (fully unrolled). - * Large moves where the source address is higher than the destination - (forward copies) - * Large moves where the destination address is higher than the source - (copy backward, or move). - - We use only two registers q6 and q22 for the moves and move 32 bytes at a - time to correctly train the hardware prefetcher for better throughput. - - For small and medium cases memcpy is used. */ - -ENTRY (__memmove_falkor) - - PTR_ARG (0) - PTR_ARG (1) - SIZE_ARG (2) - - cmp count, 32 - add srcend, src, count - add dstend, dstin, count - b.ls L(copy32) - cmp count, 128 - b.ls L(copy128) - sub tmp1, dstin, src - ccmp tmp1, count, 2, hi - b.lo L(move_long) - - /* CASE: Copy Forwards - - Align src to 16 byte alignment so that we don't cross cache line - boundaries on both loads and stores. There are at least 128 bytes - to copy, so copy 16 bytes unaligned and then align. The loop - copies 32 bytes per iteration and prefetches one iteration ahead. */ - - ldr S_q, [src] - and tmp1, src, 15 - bic src, src, 15 - sub dst, dstin, tmp1 - add count, count, tmp1 /* Count is now 16 too large. */ - ldr Q_q, [src, 16]! - str S_q, [dstin] - ldr S_q, [src, 16]! - sub count, count, 32 + 32 + 16 /* Test and readjust count. */ - - .p2align 4 -1: - subs count, count, 32 - str Q_q, [dst, 16] - ldr Q_q, [src, 16]! - str S_q, [dst, 32]! - ldr S_q, [src, 16]! - b.hi 1b - - /* Copy 32 bytes from the end before writing the data prefetched in the - last loop iteration. */ -2: - ldr B_q, [srcend, -32] - ldr C_q, [srcend, -16] - str Q_q, [dst, 16] - str S_q, [dst, 32] - str B_q, [dstend, -32] - str C_q, [dstend, -16] - ret - - /* CASE: Copy Backwards - - Align srcend to 16 byte alignment so that we don't cross cache line - boundaries on both loads and stores. There are at least 128 bytes - to copy, so copy 16 bytes unaligned and then align. The loop - copies 32 bytes per iteration and prefetches one iteration ahead. */ - - .p2align 4 - nop - nop -L(move_long): - cbz tmp1, 3f /* Return early if src == dstin */ - ldr S_q, [srcend, -16] - and tmp1, srcend, 15 - sub srcend, srcend, tmp1 - ldr Q_q, [srcend, -16]! - str S_q, [dstend, -16] - sub count, count, tmp1 - ldr S_q, [srcend, -16]! - sub dstend, dstend, tmp1 - sub count, count, 32 + 32 - -1: - subs count, count, 32 - str Q_q, [dstend, -16] - ldr Q_q, [srcend, -16]! - str S_q, [dstend, -32]! - ldr S_q, [srcend, -16]! - b.hi 1b - - /* Copy 32 bytes from the start before writing the data prefetched in the - last loop iteration. */ - - ldr B_q, [src, 16] - ldr C_q, [src] - str Q_q, [dstend, -16] - str S_q, [dstend, -32] - str B_q, [dstin, 16] - str C_q, [dstin] -3: ret - -END (__memmove_falkor) -#endif diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c index 6b19d0a560..90729e0275 100644 --- a/sysdeps/aarch64/multiarch/memmove.c +++ b/sysdeps/aarch64/multiarch/memmove.c @@ -31,7 +31,6 @@ extern __typeof (__redirect_memmove) __libc_memmove; extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden; extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden; extern __typeof (__redirect_memmove) __memmove_thunderx2 attribute_hidden; -extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden; extern __typeof (__redirect_memmove) __memmove_a64fx attribute_hidden; extern __typeof (__redirect_memmove) __memmove_sve attribute_hidden; extern __typeof (__redirect_memmove) __memmove_mops attribute_hidden; @@ -57,9 +56,6 @@ select_memmove_ifunc (void) if (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)) return __memmove_thunderx2; - if (IS_FALKOR (midr) || IS_PHECDA (midr)) - return __memmove_falkor; - return __memmove_generic; } diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c index 77549b0bdf..6ee1cb4bc2 100644 --- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c @@ -38,11 +38,9 @@ struct cpu_list }; static struct cpu_list cpu_list[] = { - {"falkor", 0x510FC000}, {"thunderxt88", 0x430F0A10}, {"thunderx2t99", 0x431F0AF0}, {"thunderx2t99p1", 0x420F5160}, - {"phecda", 0x680F0000}, {"ares", 0x411FD0C0}, {"emag", 0x503F0001}, {"kunpeng920", 0x481FD010}, diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h index 7e18062aa2..b4bd43a228 100644 --- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h +++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h @@ -47,11 +47,6 @@ #define IS_THUNDERX2(midr) (MIDR_IMPLEMENTOR(midr) == 'C' \ && MIDR_PARTNUM(midr) == 0xaf) -#define IS_FALKOR(midr) (MIDR_IMPLEMENTOR(midr) == 'Q' \ - && MIDR_PARTNUM(midr) == 0xc00) - -#define IS_PHECDA(midr) (MIDR_IMPLEMENTOR(midr) == 'h' \ - && MIDR_PARTNUM(midr) == 0x000) #define IS_NEOVERSE_N1(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \ && MIDR_PARTNUM(midr) == 0xd0c) #define IS_NEOVERSE_N2(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \ -- cgit 1.4.1 From 88e96e7b5fc8c80ef22b08022dd327a546066aae Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 23 Nov 2023 18:23:46 +0100 Subject: aarch64: correct CFI in rawmemchr (bug 31113) The .cfi_return_column directive changes the return column for the whole FDE range. But the actual intent is to tell the unwinder that the value in x30 (lr) now resides in x15 after the move, and that is expressed by the .cfi_register directive. (cherry picked from commit 3f798427884fa57770e8e2291cf58d5918254bb5) --- sysdeps/aarch64/rawmemchr.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysdeps/aarch64/rawmemchr.S b/sysdeps/aarch64/rawmemchr.S index 55d9e34d4f..f90ce2bf86 100644 --- a/sysdeps/aarch64/rawmemchr.S +++ b/sysdeps/aarch64/rawmemchr.S @@ -31,7 +31,7 @@ ENTRY (__rawmemchr) L(do_strlen): mov x15, x30 - cfi_return_column (x15) + cfi_register (x30, x15) mov x14, x0 bl __strlen add x0, x14, x0 -- cgit 1.4.1 From b77e357bf9bf9972fc33bfbde4269d911eb9b682 Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Wed, 13 Mar 2024 14:34:14 +0000 Subject: aarch64: fix check for SVE support in assembler Due to GCC bug 110901 -mcpu can override -march setting when compiling asm code and thus a compiler targetting a specific cpu can fail the configure check even when binutils gas supports SVE. The workaround is that explicit .arch directive overrides both -mcpu and -march, and since that's what the actual SVE memcpy uses the configure check should use that too even if the GCC issue is fixed independently. Reviewed-by: Florian Weimer (cherry picked from commit 73c26018ed0ecd9c807bb363cc2c2ab4aca66a82) --- sysdeps/aarch64/configure | 5 +++-- sysdeps/aarch64/configure.ac | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) mode change 100644 => 100755 sysdeps/aarch64/configure diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure old mode 100644 new mode 100755 index 2130f6b8f8..19d2b46cbf --- a/sysdeps/aarch64/configure +++ b/sysdeps/aarch64/configure @@ -307,9 +307,10 @@ if ${libc_cv_aarch64_sve_asm+:} false; then : $as_echo_n "(cached) " >&6 else cat > conftest.s <<\EOF - ptrue p0.b + .arch armv8.2-a+sve + ptrue p0.b EOF -if { ac_try='${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&5' +if { ac_try='${CC-cc} -c conftest.s 1>&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 ac_status=$? diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac index 85c6f76508..bb5adb1782 100644 --- a/sysdeps/aarch64/configure.ac +++ b/sysdeps/aarch64/configure.ac @@ -90,9 +90,10 @@ LIBC_CONFIG_VAR([aarch64-variant-pcs], [$libc_cv_aarch64_variant_pcs]) # Check if asm support armv8.2-a+sve AC_CACHE_CHECK([for SVE support in assembler], [libc_cv_aarch64_sve_asm], [dnl cat > conftest.s <<\EOF - ptrue p0.b + .arch armv8.2-a+sve + ptrue p0.b EOF -if AC_TRY_COMMAND(${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&AS_MESSAGE_LOG_FD); then +if AC_TRY_COMMAND(${CC-cc} -c conftest.s 1>&AS_MESSAGE_LOG_FD); then libc_cv_aarch64_sve_asm=yes else libc_cv_aarch64_sve_asm=no -- cgit 1.4.1 From 24de733967029fd902c34073d2ab25b900887352 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Thu, 21 Mar 2024 16:48:33 +0000 Subject: AArch64: Check kernel version for SVE ifuncs Old Linux kernels disable SVE after every system call. Calling the SVE-optimized memcpy afterwards will then cause a trap to reenable SVE. As a result, applications with a high use of syscalls may run slower with the SVE memcpy. This is true for kernels between 4.15.0 and before 6.2.0, except for 5.14.0 which was patched. Avoid this by checking the kernel version and selecting the SVE ifunc on modern kernels. Parse the kernel version reported by uname() into a 24-bit kernel.major.minor value without calling any library functions. If uname() is not supported or if the version format is not recognized, assume the kernel is modern. Tested-by: Florian Weimer Reviewed-by: Szabolcs Nagy (cherry picked from commit 2e94e2f5d2bf2de124c8ad7da85463355e54ccb2) --- sysdeps/aarch64/multiarch/init-arch.h | 2 ++ sysdeps/aarch64/multiarch/memcpy.c | 2 +- sysdeps/aarch64/multiarch/memmove.c | 2 +- sysdeps/unix/sysv/linux/aarch64/cpu-features.c | 48 ++++++++++++++++++++++++++ sysdeps/unix/sysv/linux/aarch64/cpu-features.h | 1 + 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/sysdeps/aarch64/multiarch/init-arch.h b/sysdeps/aarch64/multiarch/init-arch.h index 5da1656954..5b2cf5cb12 100644 --- a/sysdeps/aarch64/multiarch/init-arch.h +++ b/sysdeps/aarch64/multiarch/init-arch.h @@ -36,5 +36,7 @@ MTE_ENABLED (); \ bool __attribute__((unused)) sve = \ GLRO(dl_aarch64_cpu_features).sve; \ + bool __attribute__((unused)) prefer_sve_ifuncs = \ + GLRO(dl_aarch64_cpu_features).prefer_sve_ifuncs; \ bool __attribute__((unused)) mops = \ GLRO(dl_aarch64_cpu_features).mops; diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c index d1cf5bec16..3de66c14d4 100644 --- a/sysdeps/aarch64/multiarch/memcpy.c +++ b/sysdeps/aarch64/multiarch/memcpy.c @@ -47,7 +47,7 @@ select_memcpy_ifunc (void) { if (IS_A64FX (midr)) return __memcpy_a64fx; - return __memcpy_sve; + return prefer_sve_ifuncs ? __memcpy_sve : __memcpy_generic; } if (IS_THUNDERX (midr)) diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c index 90729e0275..fdcf418820 100644 --- a/sysdeps/aarch64/multiarch/memmove.c +++ b/sysdeps/aarch64/multiarch/memmove.c @@ -47,7 +47,7 @@ select_memmove_ifunc (void) { if (IS_A64FX (midr)) return __memmove_a64fx; - return __memmove_sve; + return prefer_sve_ifuncs ? __memmove_sve : __memmove_generic; } if (IS_THUNDERX (midr)) diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c index 6ee1cb4bc2..2543128352 100644 --- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c @@ -20,6 +20,7 @@ #include #include #include +#include #define DCZID_DZP_MASK (1 << 4) #define DCZID_BS_MASK (0xf) @@ -59,6 +60,46 @@ get_midr_from_mcpu (const char *mcpu) } #endif +#if __LINUX_KERNEL_VERSION < 0x060200 + +/* Return true if we prefer using SVE in string ifuncs. Old kernels disable + SVE after every system call which results in unnecessary traps if memcpy + uses SVE. This is true for kernels between 4.15.0 and before 6.2.0, except + for 5.14.0 which was patched. For these versions return false to avoid using + SVE ifuncs. + Parse the kernel version into a 24-bit kernel.major.minor value without + calling any library functions. If uname() is not supported or if the version + format is not recognized, assume the kernel is modern and return true. */ + +static inline bool +prefer_sve_ifuncs (void) +{ + struct utsname buf; + const char *p = &buf.release[0]; + int kernel = 0; + int val; + + if (__uname (&buf) < 0) + return true; + + for (int shift = 16; shift >= 0; shift -= 8) + { + for (val = 0; *p >= '0' && *p <= '9'; p++) + val = val * 10 + *p - '0'; + kernel |= (val & 255) << shift; + if (*p++ != '.') + break; + } + + if (kernel >= 0x060200 || kernel == 0x050e00) + return true; + if (kernel >= 0x040f00) + return false; + return true; +} + +#endif + static inline void init_cpu_features (struct cpu_features *cpu_features) { @@ -125,6 +166,13 @@ init_cpu_features (struct cpu_features *cpu_features) /* Check if SVE is supported. */ cpu_features->sve = GLRO (dl_hwcap) & HWCAP_SVE; + cpu_features->prefer_sve_ifuncs = cpu_features->sve; + +#if __LINUX_KERNEL_VERSION < 0x060200 + if (cpu_features->sve) + cpu_features->prefer_sve_ifuncs = prefer_sve_ifuncs (); +#endif + /* Check if MOPS is supported. */ cpu_features->mops = GLRO (dl_hwcap2) & HWCAP2_MOPS; } diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h index b4bd43a228..d51597b923 100644 --- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h +++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h @@ -71,6 +71,7 @@ struct cpu_features /* Currently, the GLIBC memory tagging tunable only defines 8 bits. */ uint8_t mte_state; bool sve; + bool prefer_sve_ifuncs; bool mops; }; -- cgit 1.4.1 From 78ad1b1b0d42b95c2c75463dc413bfd162a778e8 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Sun, 14 Apr 2024 08:24:51 +0200 Subject: powerpc: Fix ld.so address determination for PCREL mode (bug 31640) This seems to have stopped working with some GCC 14 versions, which clobber r2. With other compilers, the kernel-provided r2 value is still available at this point. Reviewed-by: Peter Bergner (cherry picked from commit 14e56bd4ce15ac2d1cc43f762eb2e6b83fec1afe) --- sysdeps/powerpc/powerpc64/dl-machine.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h index bb0ccd0811..3868bcc2f7 100644 --- a/sysdeps/powerpc/powerpc64/dl-machine.h +++ b/sysdeps/powerpc/powerpc64/dl-machine.h @@ -79,6 +79,7 @@ elf_host_tolerates_class (const Elf64_Ehdr *ehdr) static inline Elf64_Addr elf_machine_load_address (void) __attribute__ ((const)); +#ifndef __PCREL__ static inline Elf64_Addr elf_machine_load_address (void) { @@ -106,6 +107,24 @@ elf_machine_dynamic (void) /* Then subtract off the load address offset. */ return runtime_dynamic - elf_machine_load_address() ; } +#else /* __PCREL__ */ +/* In PCREL mode, r2 may have been clobbered. Rely on relative + relocations instead. */ + +static inline ElfW(Addr) +elf_machine_load_address (void) +{ + extern const ElfW(Ehdr) __ehdr_start attribute_hidden; + return (ElfW(Addr)) &__ehdr_start; +} + +static inline ElfW(Addr) +elf_machine_dynamic (void) +{ + extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; + return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); +} +#endif /* __PCREL__ */ /* The PLT uses Elf64_Rela relocs. */ #define elf_machine_relplt elf_machine_rela -- cgit 1.4.1 From 4ed98540a7fd19f458287e783ae59c41e64df7b5 Mon Sep 17 00:00:00 2001 From: Charles Fol Date: Thu, 28 Mar 2024 12:25:38 -0300 Subject: iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence (CVE-2024-2961) ISO-2022-CN-EXT uses escape sequences to indicate character set changes (as specified by RFC 1922). While the SOdesignation has the expected bounds checks, neither SS2designation nor SS3designation have its; allowing a write overflow of 1, 2, or 3 bytes with fixed values: '$+I', '$+J', '$+K', '$+L', '$+M', or '$*H'. Checked on aarch64-linux-gnu. Co-authored-by: Adhemerval Zanella Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit f9dc609e06b1136bb0408be9605ce7973a767ada) --- iconvdata/Makefile | 5 +- iconvdata/iso-2022-cn-ext.c | 12 ++++ iconvdata/tst-iconv-iso-2022-cn-ext.c | 128 ++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 iconvdata/tst-iconv-iso-2022-cn-ext.c diff --git a/iconvdata/Makefile b/iconvdata/Makefile index f4c089ed5d..d01b3fcab6 100644 --- a/iconvdata/Makefile +++ b/iconvdata/Makefile @@ -75,7 +75,8 @@ ifeq (yes,$(build-shared)) tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \ - bug-iconv13 bug-iconv14 bug-iconv15 + bug-iconv13 bug-iconv14 bug-iconv15 \ + tst-iconv-iso-2022-cn-ext ifeq ($(have-thread-library),yes) tests += bug-iconv3 endif @@ -330,6 +331,8 @@ $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \ $(addprefix $(objpfx),$(modules.so)) $(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \ $(addprefix $(objpfx),$(modules.so)) +$(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) $(objpfx)iconv-test.out: run-iconv-test.sh \ $(addprefix $(objpfx), $(gconv-modules)) \ diff --git a/iconvdata/iso-2022-cn-ext.c b/iconvdata/iso-2022-cn-ext.c index e09f358cad..2cc478a8c6 100644 --- a/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"); { \ const char *escseq; \ \ + if (outptr + 4 > outend) \ + { \ + result = __GCONV_FULL_OUTPUT; \ + break; \ + } \ + \ assert (used == CNS11643_2_set); /* XXX */ \ escseq = "*H"; \ *outptr++ = ESC; \ @@ -587,6 +593,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); { \ const char *escseq; \ \ + if (outptr + 4 > outend) \ + { \ + result = __GCONV_FULL_OUTPUT; \ + break; \ + } \ + \ assert ((used >> 5) >= 3 && (used >> 5) <= 7); \ escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2; \ *outptr++ = ESC; \ diff --git a/iconvdata/tst-iconv-iso-2022-cn-ext.c b/iconvdata/tst-iconv-iso-2022-cn-ext.c new file mode 100644 index 0000000000..96a8765fd5 --- /dev/null +++ b/iconvdata/tst-iconv-iso-2022-cn-ext.c @@ -0,0 +1,128 @@ +/* Verify ISO-2022-CN-EXT does not write out of the bounds. + 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 + . */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* The test sets up a two memory page buffer with the second page marked + PROT_NONE to trigger a fault if the conversion writes beyond the exact + expected amount. Then we carry out various conversions and precisely + place the start of the output buffer in order to trigger a SIGSEGV if the + process writes anywhere between 1 and page sized bytes more (only one + PROT_NONE page is setup as a canary) than expected. These tests exercise + all three of the cases in ISO-2022-CN-EXT where the converter must switch + character sets and may run out of buffer space while doing the + operation. */ + +static int +do_test (void) +{ + iconv_t cd = iconv_open ("ISO-2022-CN-EXT", "UTF-8"); + TEST_VERIFY_EXIT (cd != (iconv_t) -1); + + char *ntf; + size_t ntfsize; + char *outbufbase; + { + int pgz = getpagesize (); + TEST_VERIFY_EXIT (pgz > 0); + ntfsize = 2 * pgz; + + ntf = xmmap (NULL, ntfsize, PROT_READ | PROT_WRITE, MAP_PRIVATE + | MAP_ANONYMOUS, -1); + xmprotect (ntf + pgz, pgz, PROT_NONE); + + outbufbase = ntf + pgz; + } + + /* Check if SOdesignation escape sequence does not trigger an OOB write. */ + { + char inbuf[] = "\xe4\xba\xa4\xe6\x8d\xa2"; + + for (int i = 0; i < 9; i++) + { + char *inp = inbuf; + size_t inleft = sizeof (inbuf) - 1; + + char *outp = outbufbase - i; + size_t outleft = i; + + TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) + == (size_t) -1); + TEST_COMPARE (errno, E2BIG); + + TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); + } + } + + /* Same as before for SS2designation. */ + { + char inbuf[] = "㴽 \xe3\xb4\xbd"; + + for (int i = 0; i < 14; i++) + { + char *inp = inbuf; + size_t inleft = sizeof (inbuf) - 1; + + char *outp = outbufbase - i; + size_t outleft = i; + + TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) + == (size_t) -1); + TEST_COMPARE (errno, E2BIG); + + TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); + } + } + + /* Same as before for SS3designation. */ + { + char inbuf[] = "劄 \xe5\x8a\x84"; + + for (int i = 0; i < 14; i++) + { + char *inp = inbuf; + size_t inleft = sizeof (inbuf) - 1; + + char *outp = outbufbase - i; + size_t outleft = i; + + TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) + == (size_t) -1); + TEST_COMPARE (errno, E2BIG); + + TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); + } + } + + TEST_VERIFY_EXIT (iconv_close (cd) != -1); + + xmunmap (ntf, ntfsize); + + return 0; +} + +#include -- cgit 1.4.1 From caa3151ca460bdd9330adeedd68c3112d97bffe4 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 25 Apr 2024 15:00:45 +0200 Subject: CVE-2024-33599: nscd: Stack-based buffer overflow in netgroup cache (bug 31677) Using alloca matches what other caches do. The request length is bounded by MAXKEYLEN. Reviewed-by: Carlos O'Donell (cherry picked from commit 87801a8fd06db1d654eea3e4f7626ff476a9bdaa) --- nscd/netgroupcache.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index 85977521a6..f0de064368 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -502,12 +502,13 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, = (struct indataset *) mempool_alloc (db, sizeof (*dataset) + req->key_len, 1); - struct indataset dataset_mem; bool cacheable = true; if (__glibc_unlikely (dataset == NULL)) { cacheable = false; - dataset = &dataset_mem; + /* The alloca is safe because nscd_run_worker verfies that + key_len is not larger than MAXKEYLEN. */ + dataset = alloca (sizeof (*dataset) + req->key_len); } datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len, -- cgit 1.4.1 From c34f470a615b136170abd16142da5dd0c024f7d1 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 25 Apr 2024 15:01:07 +0200 Subject: CVE-2024-33600: nscd: Do not send missing not-found response in addgetnetgrentX (bug 31678) If we failed to add a not-found response to the cache, the dataset point can be null, resulting in a null pointer dereference. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit 7835b00dbce53c3c87bbbb1754a95fb5e58187aa) --- nscd/netgroupcache.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index f0de064368..a64b5930d5 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -147,7 +147,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, /* No such service. */ cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout, &key_copy); - goto writeout; + goto maybe_cache_add; } memset (&data, '\0', sizeof (data)); @@ -348,7 +348,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, { cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout, &key_copy); - goto writeout; + goto maybe_cache_add; } total = buffilled; @@ -410,14 +410,12 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, } if (he == NULL && fd != -1) - { - /* We write the dataset before inserting it to the database - since while inserting this thread might block and so would - unnecessarily let the receiver wait. */ - writeout: + /* We write the dataset before inserting it to the database since + while inserting this thread might block and so would + unnecessarily let the receiver wait. */ writeall (fd, &dataset->resp, dataset->head.recsize); - } + maybe_cache_add: if (cacheable) { /* If necessary, we also propagate the data to disk. */ -- cgit 1.4.1 From f205b3af56740e3b014915b1bd3b162afe3407ef Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 25 Apr 2024 15:01:07 +0200 Subject: CVE-2024-33600: nscd: Avoid null pointer crashes after notfound response (bug 31678) The addgetnetgrentX call in addinnetgrX may have failed to produce a result, so the result variable in addinnetgrX can be NULL. Use db->negtimeout as the fallback value if there is no result data; the timeout is also overwritten below. Also avoid sending a second not-found response. (The client disconnects after receiving the first response, so the data stream did not go out of sync even without this fix.) It is still beneficial to add the negative response to the mapping, so that the client can get it from there in the future, instead of going through the socket. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit b048a482f088e53144d26a61c390bed0210f49f2) --- nscd/netgroupcache.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index a64b5930d5..787e44d851 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -511,14 +511,15 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len, sizeof (innetgroup_response_header), - he == NULL ? 0 : dh->nreloads + 1, result->head.ttl); + he == NULL ? 0 : dh->nreloads + 1, + result == NULL ? db->negtimeout : result->head.ttl); /* Set the notfound status and timeout based on the result from getnetgrent. */ - dataset->head.notfound = result->head.notfound; + dataset->head.notfound = result == NULL || result->head.notfound; dataset->head.timeout = timeout; dataset->resp.version = NSCD_VERSION; - dataset->resp.found = result->resp.found; + dataset->resp.found = result != NULL && result->resp.found; /* Until we find a matching entry the result is 0. */ dataset->resp.result = 0; @@ -566,7 +567,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, goto out; } - if (he == NULL) + /* addgetnetgrentX may have already sent a notfound response. Do + not send another one. */ + if (he == NULL && dataset->resp.found) { /* We write the dataset before inserting it to the database since while inserting this thread might block and so would -- cgit 1.4.1 From b6742463694b1dfdd5120b91ee21cf05d15ec2e2 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 25 Apr 2024 15:01:07 +0200 Subject: CVE-2024-33601, CVE-2024-33602: nscd: netgroup: Use two buffers in addgetnetgrentX (bug 31680) This avoids potential memory corruption when the underlying NSS callback function does not use the buffer space to store all strings (e.g., for constant strings). Instead of custom buffer management, two scratch buffers are used. This increases stack usage somewhat. Scratch buffer allocation failure is handled by return -1 (an invalid timeout value) instead of terminating the process. This fixes bug 31679. Reviewed-by: Siddhesh Poyarekar (cherry picked from commit c04a21e050d64a1193a6daab872bca2528bda44b) --- nscd/netgroupcache.c | 219 ++++++++++++++++++++++++++++----------------------- 1 file changed, 121 insertions(+), 98 deletions(-) diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index 787e44d851..aaabbbb003 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../inet/netgroup.h" #include "nscd.h" @@ -65,6 +66,16 @@ struct dataset char strdata[0]; }; +/* Send a notfound response to FD. Always returns -1 to indicate an + ephemeral error. */ +static time_t +send_notfound (int fd) +{ + if (fd != -1) + TEMP_FAILURE_RETRY (send (fd, ¬found, sizeof (notfound), MSG_NOSIGNAL)); + return -1; +} + /* 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 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, total = sizeof (notfound); timeout = time (NULL) + db->negtimeout; - if (fd != -1) - TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL)); + send_notfound (fd); dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1); /* 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, return cacheable; } +struct addgetnetgrentX_scratch +{ + /* This is the result that the caller should use. It can be NULL, + point into buffer, or it can be in the cache. */ + struct dataset *dataset; + + struct scratch_buffer buffer; + + /* Used internally in addgetnetgrentX as a staging area. */ + struct scratch_buffer tmp; + + /* Number of bytes in buffer that are actually used. */ + size_t buffer_used; +}; + +static void +addgetnetgrentX_scratch_init (struct addgetnetgrentX_scratch *scratch) +{ + scratch->dataset = NULL; + scratch_buffer_init (&scratch->buffer); + scratch_buffer_init (&scratch->tmp); + + /* Reserve space for the header. */ + scratch->buffer_used = sizeof (struct dataset); + static_assert (sizeof (struct dataset) < sizeof (scratch->tmp.__space), + "initial buffer space"); + memset (scratch->tmp.data, 0, sizeof (struct dataset)); +} + +static void +addgetnetgrentX_scratch_free (struct addgetnetgrentX_scratch *scratch) +{ + scratch_buffer_free (&scratch->buffer); + scratch_buffer_free (&scratch->tmp); +} + +/* Copy LENGTH bytes from S into SCRATCH. Returns NULL if SCRATCH + could not be resized, otherwise a pointer to the copy. */ +static char * +addgetnetgrentX_append_n (struct addgetnetgrentX_scratch *scratch, + const char *s, size_t length) +{ + while (true) + { + size_t remaining = scratch->buffer.length - scratch->buffer_used; + if (remaining >= length) + break; + if (!scratch_buffer_grow_preserve (&scratch->buffer)) + return NULL; + } + char *copy = scratch->buffer.data + scratch->buffer_used; + memcpy (copy, s, length); + scratch->buffer_used += length; + return copy; +} + +/* Copy S into SCRATCH, including its null terminator. Returns false + if SCRATCH could not be resized. */ +static bool +addgetnetgrentX_append (struct addgetnetgrentX_scratch *scratch, const char *s) +{ + if (s == NULL) + s = ""; + return addgetnetgrentX_append_n (scratch, s, strlen (s) + 1) != NULL; +} + +/* Caller must initialize and free *SCRATCH. If the return value is + negative, this function has sent a notfound response. */ static time_t addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, const char *key, uid_t uid, struct hashentry *he, - struct datahead *dh, struct dataset **resultp, - void **tofreep) + struct datahead *dh, struct addgetnetgrentX_scratch *scratch) { if (__glibc_unlikely (debug_level > 0)) { @@ -132,14 +209,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, char *key_copy = NULL; struct __netgrent data; - size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len); - size_t buffilled = sizeof (*dataset); - char *buffer = NULL; size_t nentries = 0; size_t group_len = strlen (key) + 1; struct name_list *first_needed = alloca (sizeof (struct name_list) + group_len); - *tofreep = NULL; if (netgroup_database == NULL && !__nss_database_get (nss_database_netgroup, &netgroup_database)) @@ -151,8 +224,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, } memset (&data, '\0', sizeof (data)); - buffer = xmalloc (buflen); - *tofreep = buffer; first_needed->next = first_needed; memcpy (first_needed->name, key, group_len); data.needed_groups = first_needed; @@ -195,8 +266,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, while (1) { int e; - status = getfct.f (&data, buffer + buffilled, - buflen - buffilled - req->key_len, &e); + status = getfct.f (&data, scratch->tmp.data, + scratch->tmp.length, &e); if (status == NSS_STATUS_SUCCESS) { if (data.type == triple_val) @@ -204,68 +275,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, const char *nhost = data.val.triple.host; const char *nuser = data.val.triple.user; const char *ndomain = data.val.triple.domain; - - size_t hostlen = strlen (nhost ?: "") + 1; - size_t userlen = strlen (nuser ?: "") + 1; - size_t domainlen = strlen (ndomain ?: "") + 1; - - if (nhost == NULL || nuser == NULL || ndomain == NULL - || nhost > nuser || nuser > ndomain) - { - const char *last = nhost; - if (last == NULL - || (nuser != NULL && nuser > last)) - last = nuser; - if (last == NULL - || (ndomain != NULL && ndomain > last)) - last = ndomain; - - size_t bufused - = (last == NULL - ? buffilled - : last + strlen (last) + 1 - buffer); - - /* We have to make temporary copies. */ - size_t needed = hostlen + userlen + domainlen; - - if (buflen - req->key_len - bufused < needed) - { - buflen += MAX (buflen, 2 * needed); - /* Save offset in the old buffer. We don't - bother with the NULL check here since - we'll do that later anyway. */ - size_t nhostdiff = nhost - buffer; - size_t nuserdiff = nuser - buffer; - size_t ndomaindiff = ndomain - buffer; - - char *newbuf = xrealloc (buffer, buflen); - /* Fix up the triplet pointers into the new - buffer. */ - nhost = (nhost ? newbuf + nhostdiff - : NULL); - nuser = (nuser ? newbuf + nuserdiff - : NULL); - ndomain = (ndomain ? newbuf + ndomaindiff - : NULL); - *tofreep = buffer = newbuf; - } - - nhost = memcpy (buffer + bufused, - nhost ?: "", hostlen); - nuser = memcpy ((char *) nhost + hostlen, - nuser ?: "", userlen); - ndomain = memcpy ((char *) nuser + userlen, - ndomain ?: "", domainlen); - } - - char *wp = buffer + buffilled; - wp = memmove (wp, nhost ?: "", hostlen); - wp += hostlen; - wp = memmove (wp, nuser ?: "", userlen); - wp += userlen; - wp = memmove (wp, ndomain ?: "", domainlen); - wp += domainlen; - buffilled = wp - buffer; + if (!(addgetnetgrentX_append (scratch, nhost) + && addgetnetgrentX_append (scratch, nuser) + && addgetnetgrentX_append (scratch, ndomain))) + return send_notfound (fd); ++nentries; } else @@ -317,8 +330,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, } else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE) { - buflen *= 2; - *tofreep = buffer = xrealloc (buffer, buflen); + if (!scratch_buffer_grow (&scratch->tmp)) + return send_notfound (fd); } else if (status == NSS_STATUS_RETURN || status == NSS_STATUS_NOTFOUND @@ -351,10 +364,17 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, goto maybe_cache_add; } - total = buffilled; + /* Capture the result size without the key appended. */ + total = scratch->buffer_used; + + /* Make a copy of the key. The scratch buffer must not move after + this point. */ + key_copy = addgetnetgrentX_append_n (scratch, key, req->key_len); + if (key_copy == NULL) + return send_notfound (fd); /* Fill in the dataset. */ - dataset = (struct dataset *) buffer; + dataset = scratch->buffer.data; timeout = datahead_init_pos (&dataset->head, total + req->key_len, total - offsetof (struct dataset, resp), he == NULL ? 0 : dh->nreloads + 1, @@ -363,11 +383,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, dataset->resp.version = NSCD_VERSION; dataset->resp.found = 1; dataset->resp.nresults = nentries; - dataset->resp.result_len = buffilled - sizeof (*dataset); - - assert (buflen - buffilled >= req->key_len); - key_copy = memcpy (buffer + buffilled, key, req->key_len); - buffilled += req->key_len; + dataset->resp.result_len = total - sizeof (*dataset); /* Now we can determine whether on refill we have to create a new record or not. */ @@ -398,7 +414,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, if (__glibc_likely (newp != NULL)) { /* Adjust pointer into the memory block. */ - key_copy = (char *) newp + (key_copy - buffer); + key_copy = (char *) newp + (key_copy - (char *) dataset); dataset = memcpy (newp, dataset, total + req->key_len); cacheable = true; @@ -439,7 +455,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, } out: - *resultp = dataset; + scratch->dataset = dataset; return timeout; } @@ -460,6 +476,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, if (user != NULL) key = (char *) rawmemchr (key, '\0') + 1; const char *domain = *key++ ? key : NULL; + struct addgetnetgrentX_scratch scratch; + + addgetnetgrentX_scratch_init (&scratch); if (__glibc_unlikely (debug_level > 0)) { @@ -475,12 +494,8 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, group, group_len, db, uid); time_t timeout; - void *tofree; if (result != NULL) - { - timeout = result->head.timeout; - tofree = NULL; - } + timeout = result->head.timeout; else { request_header req_get = @@ -489,7 +504,10 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, .key_len = group_len }; timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL, - &result, &tofree); + &scratch); + result = scratch.dataset; + if (timeout < 0) + goto out; } struct indataset @@ -603,7 +621,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, } out: - free (tofree); + addgetnetgrentX_scratch_free (&scratch); return timeout; } @@ -613,11 +631,12 @@ addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req, const char *key, uid_t uid, struct hashentry *he, struct datahead *dh) { - struct dataset *ignore; - void *tofree; - time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, - &ignore, &tofree); - free (tofree); + struct addgetnetgrentX_scratch scratch; + addgetnetgrentX_scratch_init (&scratch); + time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, &scratch); + addgetnetgrentX_scratch_free (&scratch); + if (timeout < 0) + timeout = 0; return timeout; } @@ -661,5 +680,9 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he, .key_len = he->len }; - return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh); + int timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner, + he, dh); + if (timeout < 0) + timeout = 0; + return timeout; } -- cgit 1.4.1 From d31c4d38a34c609acef6e61cfd272b11a9b625eb Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 25 Apr 2024 08:06:52 -0700 Subject: elf: Also compile dl-misc.os with $(rtld-early-cflags) Also compile dl-misc.os with $(rtld-early-cflags) to avoid Program received signal SIGILL, Illegal instruction. 0x00007ffff7fd36ea in _dl_strtoul (nptr=nptr@entry=0x7fffffffe2c9 "2", endptr=endptr@entry=0x7fffffffd728) at dl-misc.c:156 156 bool positive = true; (gdb) bt #0 0x00007ffff7fd36ea in _dl_strtoul (nptr=nptr@entry=0x7fffffffe2c9 "2", endptr=endptr@entry=0x7fffffffd728) at dl-misc.c:156 #1 0x00007ffff7fdb1a9 in tunable_initialize ( cur=cur@entry=0x7ffff7ffbc00 , strval=strval@entry=0x7fffffffe2c9 "2", len=len@entry=1) at dl-tunables.c:131 #2 0x00007ffff7fdb3a2 in parse_tunables (valstring=) at dl-tunables.c:258 #3 0x00007ffff7fdb5d9 in __GI___tunables_init (envp=0x7fffffffdd58) at dl-tunables.c:288 #4 0x00007ffff7fe44c3 in _dl_sysdep_start ( start_argptr=start_argptr@entry=0x7fffffffdcb0, dl_main=dl_main@entry=0x7ffff7fe5f80 ) at ../sysdeps/unix/sysv/linux/dl-sysdep.c:110 #5 0x00007ffff7fe5cae in _dl_start_final (arg=0x7fffffffdcb0) at rtld.c:494 #6 _dl_start (arg=0x7fffffffdcb0) at rtld.c:581 #7 0x00007ffff7fe4b38 in _start () (gdb) when setting GLIBC_TUNABLES in glibc compiled with APX. Reviewed-by: Florian Weimer (cherry picked from commit 049b7684c912dd32b67b1b15b0f43bf07d5f512e) --- elf/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/elf/Makefile b/elf/Makefile index 30c9af1de9..cea9c1b29d 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -177,6 +177,7 @@ CFLAGS-.op += $(call elide-stack-protector,.op,$(elide-routines.os)) CFLAGS-.os += $(call elide-stack-protector,.os,$(all-rtld-routines)) # Add the requested compiler flags to the early startup code. +CFLAGS-dl-misc.os += $(rtld-early-cflags) CFLAGS-dl-printf.os += $(rtld-early-cflags) CFLAGS-dl-setup_hash.os += $(rtld-early-cflags) CFLAGS-dl-sysdep.os += $(rtld-early-cflags) -- cgit 1.4.1 From 5b48737556a4928ec2cf8641c83e197671acdf00 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 17 Jan 2024 10:13:06 -0300 Subject: sparc: Remove 64 bit check on sparc32 wordsize (BZ 27574) The sparc32 is always 32 bits. Checked on sparcv9-linux-gnu. (cherry picked from commit dd57f5e7b652772499cb220d78157c1038d24f06) --- sysdeps/sparc/sparc32/bits/wordsize.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sysdeps/sparc/sparc32/bits/wordsize.h b/sysdeps/sparc/sparc32/bits/wordsize.h index 2f66f10d72..4bbd2e63b4 100644 --- a/sysdeps/sparc/sparc32/bits/wordsize.h +++ b/sysdeps/sparc/sparc32/bits/wordsize.h @@ -1,11 +1,6 @@ /* Determine the wordsize from the preprocessor defines. */ -#if defined __arch64__ || defined __sparcv9 -# define __WORDSIZE 64 -# define __WORDSIZE_TIME64_COMPAT32 1 -#else -# define __WORDSIZE 32 -# define __WORDSIZE_TIME64_COMPAT32 0 -# define __WORDSIZE32_SIZE_ULONG 0 -# define __WORDSIZE32_PTRDIFF_LONG 0 -#endif +#define __WORDSIZE 32 +#define __WORDSIZE_TIME64_COMPAT32 0 +#define __WORDSIZE32_SIZE_ULONG 0 +#define __WORDSIZE32_PTRDIFF_LONG 0 -- cgit 1.4.1 From eeeaf0fe2df339889f30f166c0b3c488535700cb Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 19 Apr 2024 14:38:17 +0200 Subject: login: Check default sizes of structs utmp, utmpx, lastlog The default is for ports with a 64-bit time_t. Ports with a 32-bit time_t or with __WORDSIZE_TIME64_COMPAT32=1 need to override it. Reviewed-by: Adhemerval Zanella (cherry picked from commit 4d4da5aab936504b2d3eca3146e109630d9093c4) --- login/Makefile | 2 +- login/tst-utmp-size.c | 33 +++++++++++++++++++++++++++++++++ sysdeps/arc/utmp-size.h | 3 +++ sysdeps/arm/utmp-size.h | 2 ++ sysdeps/csky/utmp-size.h | 2 ++ sysdeps/generic/utmp-size.h | 23 +++++++++++++++++++++++ sysdeps/hppa/utmp-size.h | 2 ++ sysdeps/m68k/utmp-size.h | 3 +++ sysdeps/microblaze/utmp-size.h | 2 ++ sysdeps/mips/utmp-size.h | 2 ++ sysdeps/nios2/utmp-size.h | 2 ++ sysdeps/or1k/utmp-size.h | 3 +++ sysdeps/powerpc/utmp-size.h | 2 ++ sysdeps/riscv/utmp-size.h | 2 ++ sysdeps/sh/utmp-size.h | 2 ++ sysdeps/sparc/utmp-size.h | 2 ++ sysdeps/x86/utmp-size.h | 2 ++ 17 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 login/tst-utmp-size.c create mode 100644 sysdeps/arc/utmp-size.h create mode 100644 sysdeps/arm/utmp-size.h create mode 100644 sysdeps/csky/utmp-size.h create mode 100644 sysdeps/generic/utmp-size.h create mode 100644 sysdeps/hppa/utmp-size.h create mode 100644 sysdeps/m68k/utmp-size.h create mode 100644 sysdeps/microblaze/utmp-size.h create mode 100644 sysdeps/mips/utmp-size.h create mode 100644 sysdeps/nios2/utmp-size.h create mode 100644 sysdeps/or1k/utmp-size.h create mode 100644 sysdeps/powerpc/utmp-size.h create mode 100644 sysdeps/riscv/utmp-size.h create mode 100644 sysdeps/sh/utmp-size.h create mode 100644 sysdeps/sparc/utmp-size.h create mode 100644 sysdeps/x86/utmp-size.h diff --git a/login/Makefile b/login/Makefile index 62440499bc..ffe9f38114 100644 --- a/login/Makefile +++ b/login/Makefile @@ -44,7 +44,7 @@ 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-pututxline-lockfail tst-pututxline-cache tst-utmp-size # Empty compatibility library for old binaries. extra-libs := libutil diff --git a/login/tst-utmp-size.c b/login/tst-utmp-size.c new file mode 100644 index 0000000000..1b7f7ff042 --- /dev/null +++ b/login/tst-utmp-size.c @@ -0,0 +1,33 @@ +/* Check expected sizes of struct utmp, struct utmpx, struct lastlog. + 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 + . */ + +#include +#include +#include + +static int +do_test (void) +{ + _Static_assert (sizeof (struct utmp) == UTMP_SIZE, "struct utmp size"); + _Static_assert (sizeof (struct utmpx) == UTMP_SIZE, "struct utmpx size"); + _Static_assert (sizeof (struct lastlog) == LASTLOG_SIZE, + "struct lastlog size"); + return 0; +} + +#include diff --git a/sysdeps/arc/utmp-size.h b/sysdeps/arc/utmp-size.h new file mode 100644 index 0000000000..a247fcd3da --- /dev/null +++ b/sysdeps/arc/utmp-size.h @@ -0,0 +1,3 @@ +/* arc has less padding than other architectures with 64-bit time_t. */ +#define UTMP_SIZE 392 +#define LASTLOG_SIZE 296 diff --git a/sysdeps/arm/utmp-size.h b/sysdeps/arm/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/arm/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/csky/utmp-size.h b/sysdeps/csky/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/csky/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/generic/utmp-size.h b/sysdeps/generic/utmp-size.h new file mode 100644 index 0000000000..89dbe878b0 --- /dev/null +++ b/sysdeps/generic/utmp-size.h @@ -0,0 +1,23 @@ +/* Expected sizes of utmp-related structures stored in files. 64-bit 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 + . */ + +/* Expected size, in bytes, of struct utmp and struct utmpx. */ +#define UTMP_SIZE 400 + +/* Expected size, in bytes, of struct lastlog. */ +#define LASTLOG_SIZE 296 diff --git a/sysdeps/hppa/utmp-size.h b/sysdeps/hppa/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/hppa/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/m68k/utmp-size.h b/sysdeps/m68k/utmp-size.h new file mode 100644 index 0000000000..5946685819 --- /dev/null +++ b/sysdeps/m68k/utmp-size.h @@ -0,0 +1,3 @@ +/* m68k has 2-byte alignment. */ +#define UTMP_SIZE 382 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/microblaze/utmp-size.h b/sysdeps/microblaze/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/microblaze/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/mips/utmp-size.h b/sysdeps/mips/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/mips/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/nios2/utmp-size.h b/sysdeps/nios2/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/nios2/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/or1k/utmp-size.h b/sysdeps/or1k/utmp-size.h new file mode 100644 index 0000000000..6b3653aa4d --- /dev/null +++ b/sysdeps/or1k/utmp-size.h @@ -0,0 +1,3 @@ +/* or1k has less padding than other architectures with 64-bit time_t. */ +#define UTMP_SIZE 392 +#define LASTLOG_SIZE 296 diff --git a/sysdeps/powerpc/utmp-size.h b/sysdeps/powerpc/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/powerpc/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/riscv/utmp-size.h b/sysdeps/riscv/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/riscv/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/sh/utmp-size.h b/sysdeps/sh/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/sh/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/sparc/utmp-size.h b/sysdeps/sparc/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/sparc/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 diff --git a/sysdeps/x86/utmp-size.h b/sysdeps/x86/utmp-size.h new file mode 100644 index 0000000000..8f21ebe1b6 --- /dev/null +++ b/sysdeps/x86/utmp-size.h @@ -0,0 +1,2 @@ +#define UTMP_SIZE 384 +#define LASTLOG_SIZE 292 -- cgit 1.4.1 From 85242ed63a33cac458eae3ffe504693680b686d9 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 19 Apr 2024 14:38:17 +0200 Subject: login: structs utmp, utmpx, lastlog _TIME_BITS independence (bug 30701) These structs describe file formats under /var/log, and should not depend on the definition of _TIME_BITS. This is achieved by defining __WORDSIZE_TIME64_COMPAT32 to 1 on 32-bit ports that support 32-bit time_t values (where __time_t is 32 bits). Reviewed-by: Adhemerval Zanella (cherry picked from commit 9abdae94c7454c45e02e97e4ed1eb1b1915d13d8) --- bits/wordsize.h | 6 ++++-- login/Makefile | 4 +++- login/tst-utmp-size-64.c | 2 ++ sysdeps/arm/bits/wordsize.h | 21 +++++++++++++++++++++ sysdeps/csky/bits/wordsize.h | 21 +++++++++++++++++++++ sysdeps/m68k/bits/wordsize.h | 21 +++++++++++++++++++++ sysdeps/microblaze/bits/wordsize.h | 21 +++++++++++++++++++++ sysdeps/mips/bits/wordsize.h | 6 +----- sysdeps/nios2/bits/wordsize.h | 21 +++++++++++++++++++++ sysdeps/powerpc/powerpc32/bits/wordsize.h | 3 +-- sysdeps/powerpc/powerpc64/bits/wordsize.h | 3 +-- sysdeps/sh/bits/wordsize.h | 21 +++++++++++++++++++++ sysdeps/sparc/sparc32/bits/wordsize.h | 2 +- sysdeps/sparc/sparc64/bits/wordsize.h | 3 +-- sysdeps/unix/sysv/linux/hppa/bits/wordsize.h | 21 +++++++++++++++++++++ sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h | 3 +-- sysdeps/unix/sysv/linux/sparc/bits/wordsize.h | 3 +-- sysdeps/x86/bits/wordsize.h | 5 ++--- 18 files changed, 165 insertions(+), 22 deletions(-) create mode 100644 login/tst-utmp-size-64.c create mode 100644 sysdeps/arm/bits/wordsize.h create mode 100644 sysdeps/csky/bits/wordsize.h create mode 100644 sysdeps/m68k/bits/wordsize.h create mode 100644 sysdeps/microblaze/bits/wordsize.h create mode 100644 sysdeps/nios2/bits/wordsize.h create mode 100644 sysdeps/sh/bits/wordsize.h create mode 100644 sysdeps/unix/sysv/linux/hppa/bits/wordsize.h diff --git a/bits/wordsize.h b/bits/wordsize.h index 14edae3a11..53013a9275 100644 --- a/bits/wordsize.h +++ b/bits/wordsize.h @@ -21,7 +21,9 @@ #define __WORDSIZE32_PTRDIFF_LONG /* Set to 1 in order to force time types to be 32 bits instead of 64 bits in - struct lastlog and struct utmp{,x} on 64-bit ports. This may be done in + struct lastlog and struct utmp{,x}. This may be done in order to make 64-bit ports compatible with 32-bit ports. Set to 0 for - 64-bit ports where the time types are 64-bits or for any 32-bit ports. */ + 64-bit ports where the time types are 64-bits and new 32-bit ports + where time_t is 64 bits, and there is no companion architecture with + 32-bit time_t. */ #define __WORDSIZE_TIME64_COMPAT32 diff --git a/login/Makefile b/login/Makefile index ffe9f38114..0b6b962c06 100644 --- a/login/Makefile +++ b/login/Makefile @@ -44,7 +44,9 @@ 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-pututxline-lockfail tst-pututxline-cache tst-utmp-size tst-utmp-size-64 + +CFLAGS-tst-utmp-size-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-size-64.c b/login/tst-utmp-size-64.c new file mode 100644 index 0000000000..7a581a4c12 --- /dev/null +++ b/login/tst-utmp-size-64.c @@ -0,0 +1,2 @@ +/* The on-disk layout must not change in time64 mode. */ +#include "tst-utmp-size.c" diff --git a/sysdeps/arm/bits/wordsize.h b/sysdeps/arm/bits/wordsize.h new file mode 100644 index 0000000000..6ecbfe7c86 --- /dev/null +++ b/sysdeps/arm/bits/wordsize.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1999-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 + . */ + +#define __WORDSIZE 32 +#define __WORDSIZE_TIME64_COMPAT32 1 +#define __WORDSIZE32_SIZE_ULONG 0 +#define __WORDSIZE32_PTRDIFF_LONG 0 diff --git a/sysdeps/csky/bits/wordsize.h b/sysdeps/csky/bits/wordsize.h new file mode 100644 index 0000000000..6ecbfe7c86 --- /dev/null +++ b/sysdeps/csky/bits/wordsize.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1999-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 + . */ + +#define __WORDSIZE 32 +#define __WORDSIZE_TIME64_COMPAT32 1 +#define __WORDSIZE32_SIZE_ULONG 0 +#define __WORDSIZE32_PTRDIFF_LONG 0 diff --git a/sysdeps/m68k/bits/wordsize.h b/sysdeps/m68k/bits/wordsize.h new file mode 100644 index 0000000000..6ecbfe7c86 --- /dev/null +++ b/sysdeps/m68k/bits/wordsize.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1999-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 + . */ + +#define __WORDSIZE 32 +#define __WORDSIZE_TIME64_COMPAT32 1 +#define __WORDSIZE32_SIZE_ULONG 0 +#define __WORDSIZE32_PTRDIFF_LONG 0 diff --git a/sysdeps/microblaze/bits/wordsize.h b/sysdeps/microblaze/bits/wordsize.h new file mode 100644 index 0000000000..6ecbfe7c86 --- /dev/null +++ b/sysdeps/microblaze/bits/wordsize.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1999-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 + . */ + +#define __WORDSIZE 32 +#define __WORDSIZE_TIME64_COMPAT32 1 +#define __WORDSIZE32_SIZE_ULONG 0 +#define __WORDSIZE32_PTRDIFF_LONG 0 diff --git a/sysdeps/mips/bits/wordsize.h b/sysdeps/mips/bits/wordsize.h index e521dc589c..c6a4a4270b 100644 --- a/sysdeps/mips/bits/wordsize.h +++ b/sysdeps/mips/bits/wordsize.h @@ -19,11 +19,7 @@ #define __WORDSIZE _MIPS_SZPTR -#if _MIPS_SIM == _ABI64 -# define __WORDSIZE_TIME64_COMPAT32 1 -#else -# define __WORDSIZE_TIME64_COMPAT32 0 -#endif +#define __WORDSIZE_TIME64_COMPAT32 1 #if __WORDSIZE == 32 #define __WORDSIZE32_SIZE_ULONG 0 diff --git a/sysdeps/nios2/bits/wordsize.h b/sysdeps/nios2/bits/wordsize.h new file mode 100644 index 0000000000..6ecbfe7c86 --- /dev/null +++ b/sysdeps/nios2/bits/wordsize.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1999-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 + . */ + +#define __WORDSIZE 32 +#define __WORDSIZE_TIME64_COMPAT32 1 +#define __WORDSIZE32_SIZE_ULONG 0 +#define __WORDSIZE32_PTRDIFF_LONG 0 diff --git a/sysdeps/powerpc/powerpc32/bits/wordsize.h b/sysdeps/powerpc/powerpc32/bits/wordsize.h index 04ca9debf0..6993fb6b29 100644 --- a/sysdeps/powerpc/powerpc32/bits/wordsize.h +++ b/sysdeps/powerpc/powerpc32/bits/wordsize.h @@ -2,10 +2,9 @@ #if defined __powerpc64__ # define __WORDSIZE 64 -# define __WORDSIZE_TIME64_COMPAT32 1 #else # define __WORDSIZE 32 -# define __WORDSIZE_TIME64_COMPAT32 0 # define __WORDSIZE32_SIZE_ULONG 0 # define __WORDSIZE32_PTRDIFF_LONG 0 #endif +#define __WORDSIZE_TIME64_COMPAT32 1 diff --git a/sysdeps/powerpc/powerpc64/bits/wordsize.h b/sysdeps/powerpc/powerpc64/bits/wordsize.h index 04ca9debf0..6993fb6b29 100644 --- a/sysdeps/powerpc/powerpc64/bits/wordsize.h +++ b/sysdeps/powerpc/powerpc64/bits/wordsize.h @@ -2,10 +2,9 @@ #if defined __powerpc64__ # define __WORDSIZE 64 -# define __WORDSIZE_TIME64_COMPAT32 1 #else # define __WORDSIZE 32 -# define __WORDSIZE_TIME64_COMPAT32 0 # define __WORDSIZE32_SIZE_ULONG 0 # define __WORDSIZE32_PTRDIFF_LONG 0 #endif +#define __WORDSIZE_TIME64_COMPAT32 1 diff --git a/sysdeps/sh/bits/wordsize.h b/sysdeps/sh/bits/wordsize.h new file mode 100644 index 0000000000..6ecbfe7c86 --- /dev/null +++ b/sysdeps/sh/bits/wordsize.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1999-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 + . */ + +#define __WORDSIZE 32 +#define __WORDSIZE_TIME64_COMPAT32 1 +#define __WORDSIZE32_SIZE_ULONG 0 +#define __WORDSIZE32_PTRDIFF_LONG 0 diff --git a/sysdeps/sparc/sparc32/bits/wordsize.h b/sysdeps/sparc/sparc32/bits/wordsize.h index 4bbd2e63b4..a2e79e0fa9 100644 --- a/sysdeps/sparc/sparc32/bits/wordsize.h +++ b/sysdeps/sparc/sparc32/bits/wordsize.h @@ -1,6 +1,6 @@ /* Determine the wordsize from the preprocessor defines. */ #define __WORDSIZE 32 -#define __WORDSIZE_TIME64_COMPAT32 0 +#define __WORDSIZE_TIME64_COMPAT32 1 #define __WORDSIZE32_SIZE_ULONG 0 #define __WORDSIZE32_PTRDIFF_LONG 0 diff --git a/sysdeps/sparc/sparc64/bits/wordsize.h b/sysdeps/sparc/sparc64/bits/wordsize.h index 2f66f10d72..ea103e5970 100644 --- a/sysdeps/sparc/sparc64/bits/wordsize.h +++ b/sysdeps/sparc/sparc64/bits/wordsize.h @@ -2,10 +2,9 @@ #if defined __arch64__ || defined __sparcv9 # define __WORDSIZE 64 -# define __WORDSIZE_TIME64_COMPAT32 1 #else # define __WORDSIZE 32 -# define __WORDSIZE_TIME64_COMPAT32 0 # define __WORDSIZE32_SIZE_ULONG 0 # define __WORDSIZE32_PTRDIFF_LONG 0 #endif +#define __WORDSIZE_TIME64_COMPAT32 1 diff --git a/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h b/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h new file mode 100644 index 0000000000..6ecbfe7c86 --- /dev/null +++ b/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1999-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 + . */ + +#define __WORDSIZE 32 +#define __WORDSIZE_TIME64_COMPAT32 1 +#define __WORDSIZE32_SIZE_ULONG 0 +#define __WORDSIZE32_PTRDIFF_LONG 0 diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h b/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h index 04ca9debf0..6993fb6b29 100644 --- a/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h +++ b/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h @@ -2,10 +2,9 @@ #if defined __powerpc64__ # define __WORDSIZE 64 -# define __WORDSIZE_TIME64_COMPAT32 1 #else # define __WORDSIZE 32 -# define __WORDSIZE_TIME64_COMPAT32 0 # define __WORDSIZE32_SIZE_ULONG 0 # define __WORDSIZE32_PTRDIFF_LONG 0 #endif +#define __WORDSIZE_TIME64_COMPAT32 1 diff --git a/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h b/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h index 7562875ee2..ea103e5970 100644 --- a/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h +++ b/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h @@ -2,10 +2,9 @@ #if defined __arch64__ || defined __sparcv9 # define __WORDSIZE 64 -# define __WORDSIZE_TIME64_COMPAT32 1 #else # define __WORDSIZE 32 # define __WORDSIZE32_SIZE_ULONG 0 # define __WORDSIZE32_PTRDIFF_LONG 0 -# define __WORDSIZE_TIME64_COMPAT32 0 #endif +#define __WORDSIZE_TIME64_COMPAT32 1 diff --git a/sysdeps/x86/bits/wordsize.h b/sysdeps/x86/bits/wordsize.h index 70f652bca1..3f40aa76f9 100644 --- a/sysdeps/x86/bits/wordsize.h +++ b/sysdeps/x86/bits/wordsize.h @@ -8,10 +8,9 @@ #define __WORDSIZE32_PTRDIFF_LONG 0 #endif +#define __WORDSIZE_TIME64_COMPAT32 1 + #ifdef __x86_64__ -# define __WORDSIZE_TIME64_COMPAT32 1 /* Both x86-64 and x32 use the 64-bit system call interface. */ # define __SYSCALL_WORDSIZE 64 -#else -# define __WORDSIZE_TIME64_COMPAT32 0 #endif -- cgit 1.4.1 From ce639236cabfaeb50d98c444d38297ffe70ae9ca Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 2 May 2024 17:06:19 +0200 Subject: nscd: Use time_t for return type of addgetnetgrentX Using int may give false results for future dates (timeouts after the year 2028). Fixes commit 04a21e050d64a1193a6daab872bca2528bda44b ("CVE-2024-33601, CVE-2024-33602: nscd: netgroup: Use two buffers in addgetnetgrentX (bug 31680)"). Reviewed-by: Carlos O'Donell (cherry picked from commit 4bbca1a44691a6e9adcee5c6798a707b626bc331) --- nscd/netgroupcache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index aaabbbb003..adc34ba6b4 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -680,8 +680,8 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he, .key_len = he->len }; - int timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner, - he, dh); + time_t timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner, + he, dh); if (timeout < 0) timeout = 0; return timeout; -- cgit 1.4.1 From 6c9e3708912ef1a0a2148b2719aa1533dfa68aa8 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 4 Nov 2022 18:37:16 +0100 Subject: elf: Disable some subtests of ifuncmain1, ifuncmain5 for !PIE (cherry picked from commit 9cc9d61ee12f2f8620d8e0ea3c42af02bf07fe1e) --- elf/ifuncmain1.c | 13 +++++++++++++ elf/ifuncmain5.c | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/elf/ifuncmain1.c b/elf/ifuncmain1.c index 747fc02648..6effce3d77 100644 --- a/elf/ifuncmain1.c +++ b/elf/ifuncmain1.c @@ -19,7 +19,14 @@ typedef int (*foo_p) (void); #endif foo_p foo_ptr = foo; + +/* Address-significant access to protected symbols is not supported in + position-dependent mode on several architectures because GCC + generates relocations that assume that the address is local to the + main program. */ +#ifdef __PIE__ foo_p foo_procted_ptr = foo_protected; +#endif extern foo_p get_foo_p (void); extern foo_p get_foo_hidden_p (void); @@ -37,12 +44,16 @@ main (void) if ((*foo_ptr) () != -1) abort (); +#ifdef __PIE__ if (foo_procted_ptr != foo_protected) abort (); +#endif if (foo_protected () != 0) abort (); +#ifdef __PIE__ if ((*foo_procted_ptr) () != 0) abort (); +#endif p = get_foo_p (); if (p != foo) @@ -55,8 +66,10 @@ main (void) abort (); p = get_foo_protected_p (); +#ifdef __PIE__ if (p != foo_protected) abort (); +#endif if (ret_foo_protected != 0 || (*p) () != ret_foo_protected) abort (); diff --git a/elf/ifuncmain5.c b/elf/ifuncmain5.c index f398085cb4..6fda768fb6 100644 --- a/elf/ifuncmain5.c +++ b/elf/ifuncmain5.c @@ -14,12 +14,19 @@ get_foo (void) return foo; } + +/* Address-significant access to protected symbols is not supported in + position-dependent mode on several architectures because GCC + generates relocations that assume that the address is local to the + main program. */ +#ifdef __PIE__ foo_p __attribute__ ((noinline)) get_foo_protected (void) { return foo_protected; } +#endif int main (void) @@ -30,9 +37,11 @@ main (void) if ((*p) () != -1) abort (); +#ifdef __PIE__ p = get_foo_protected (); if ((*p) () != 0) abort (); +#endif return 0; } -- cgit 1.4.1 From ee65bc1df6268c561e6c62dcc4435fbbf705bc67 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 9 May 2024 20:07:01 -0700 Subject: Force DT_RPATH for --enable-hardcoded-path-in-tests On Fedora 40/x86-64, linker enables --enable-new-dtags by default which generates DT_RUNPATH instead of DT_RPATH. Unlike DT_RPATH, DT_RUNPATH only applies to DT_NEEDED entries in the executable and doesn't applies to DT_NEEDED entries in shared libraries which are loaded via DT_NEEDED entries in the executable. Some glibc tests have libstdc++.so.6 in DT_NEEDED, which has libm.so.6 in DT_NEEDED. When DT_RUNPATH is generated, /lib64/libm.so.6 is loaded for such tests. If the newly built glibc is older than glibc 2.36, these tests fail with assert/tst-assert-c++: /export/build/gnu/tools-build/glibc-gitlab-release/build-x86_64-linux/libc.so.6: version `GLIBC_2.36' not found (required by /lib64/libm.so.6) assert/tst-assert-c++: /export/build/gnu/tools-build/glibc-gitlab-release/build-x86_64-linux/libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /lib64/libm.so.6) Pass -Wl,--disable-new-dtags to linker when building glibc tests with --enable-hardcoded-path-in-tests. This fixes BZ #31719. Signed-off-by: H.J. Lu (cherry picked from commit 2dcaf70643710e22f92a351e36e3cff8b48c60dc) --- Makeconfig | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makeconfig b/Makeconfig index 9dd058e04b..151f542c27 100644 --- a/Makeconfig +++ b/Makeconfig @@ -585,10 +585,13 @@ link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link) # before the expansion of LDLIBS-* variables). # Tests use -Wl,-rpath instead of -Wl,-rpath-link for -# build-hardcoded-path-in-tests. +# build-hardcoded-path-in-tests. Add -Wl,--disable-new-dtags to force +# DT_RPATH instead of DT_RUNPATH which only applies to DT_NEEDED entries +# in the executable and doesn't applies to DT_NEEDED entries in shared +# libraries which are loaded via DT_NEEDED entries in the executable. ifeq (yes,$(build-hardcoded-path-in-tests)) -link-libc-tests-rpath-link = $(link-libc-rpath) -link-test-modules-rpath-link = $(link-libc-rpath) +link-libc-tests-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags +link-test-modules-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags else link-libc-tests-rpath-link = $(link-libc-rpath-link) link-test-modules-rpath-link = -- cgit 1.4.1