diff -pruN glibc-2.32.orig/debug/Makefile glibc-2.32/debug/Makefile --- glibc-2.32.orig/debug/Makefile 2021-09-18 21:02:32.642182626 +1000 +++ glibc-2.32/debug/Makefile 2021-09-18 21:03:05.310302219 +1000 @@ -51,7 +51,7 @@ routines = backtrace backtracesyms back explicit_bzero_chk \ stack_chk_fail fortify_fail \ $(static-only-routines) -static-only-routines := warning-nop stack_chk_fail_local +static-only-routines := stack_chk_fail_local # Don't add stack_chk_fail_local.o to libc.a since __stack_chk_fail_local # is an alias of __stack_chk_fail in stack_chk_fail.o. diff -pruN glibc-2.32.orig/debug/warning-nop.c glibc-2.32/debug/warning-nop.c --- glibc-2.32.orig/debug/warning-nop.c 2021-09-18 21:02:32.642182626 +1000 +++ glibc-2.32/debug/warning-nop.c 1970-01-01 10:00:00.000000000 +1000 @@ -1,70 +0,0 @@ -/* Dummy nop functions to elicit link-time warnings. - Copyright (C) 2005-2020 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. - - In addition to the permissions in the GNU Lesser General Public - License, the Free Software Foundation gives you unlimited - permission to link the compiled version of this file with other - programs, and to distribute those programs without any restriction - coming from the use of this file. (The GNU Lesser General Public - License restrictions do apply in other respects; for example, they - cover modification of the file, and distribution when not linked - into another program.) - - Note that people who make modified versions of this file are not - obligated to grant this special exception for their modified - versions; it is their choice whether to do so. The GNU Lesser - General Public License gives permission to release a modified - version without this exception; this exception also makes it - possible to release a modified version which carries forward this - exception. - - 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__ ((used)) -nop (void) -{ -} - -/* Don't insert any other #include's before this #undef! */ - -#undef __warndecl -#define __warndecl(name, msg) \ - extern void name (void) __attribute__ ((alias ("nop"))) attribute_hidden; \ - link_warning (name, msg) - -#undef __USE_FORTIFY_LEVEL -#define __USE_FORTIFY_LEVEL 99 - -/* Following here we need an #include for each public header file - that uses __warndecl. */ - -/* Define away to avoid warnings with compilers that do not have these - builtins. */ -#define __builtin___memcpy_chk(dest, src, len, bos) NULL -#define __builtin___memmove_chk(dest, src, len, bos) NULL -#define __builtin___mempcpy_chk(dest, src, len, bos) NULL -#define __builtin___memset_chk(dest, ch, len, bos) NULL -#define __builtin___stpcpy_chk(dest, src, bos) NULL -#define __builtin___strcat_chk(dest, src, bos) NULL -#define __builtin___strcpy_chk(dest, src, bos) NULL -#define __builtin___strncat_chk(dest, src, len, bos) NULL -#define __builtin___strncpy_chk(dest, src, len, bos) NULL -#define __builtin_object_size(bos, level) 0 - -#include diff -pruN glibc-2.32.orig/elf/dl-load.c glibc-2.32/elf/dl-load.c --- glibc-2.32.orig/elf/dl-load.c 2021-09-18 21:02:32.643182660 +1000 +++ glibc-2.32/elf/dl-load.c 2021-09-18 21:03:05.311302253 +1000 @@ -855,10 +855,12 @@ lose (int code, int fd, const char *name /* Process PT_GNU_PROPERTY program header PH in module L after PT_LOAD segments are mapped. Only one NT_GNU_PROPERTY_TYPE_0 - note is handled which contains processor specific properties. */ + note is handled which contains processor specific properties. + FD is -1 for the kernel mapped main executable otherwise it is + the fd used for loading module L. */ void -_dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph) +_dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph) { const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr); const ElfW(Addr) size = ph->p_memsz; @@ -905,7 +907,7 @@ _dl_process_pt_gnu_property (struct link last_type = type; /* Target specific property processing. */ - if (_dl_process_gnu_property (l, type, datasz, ptr) == 0) + if (_dl_process_gnu_property (l, fd, type, datasz, ptr) == 0) return; /* Check the next property item. */ @@ -1251,21 +1253,6 @@ _dl_map_object_from_fd (const char *name maplength, has_holes, loader); if (__glibc_unlikely (errstring != NULL)) goto call_lose; - - /* Process program headers again after load segments are mapped in - case processing requires accessing those segments. Scan program - headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY - exits. */ - for (ph = &phdr[l->l_phnum]; ph != phdr; --ph) - switch (ph[-1].p_type) - { - case PT_NOTE: - _dl_process_pt_note (l, &ph[-1]); - break; - case PT_GNU_PROPERTY: - _dl_process_pt_gnu_property (l, &ph[-1]); - break; - } } if (l->l_ld == 0) @@ -1377,6 +1364,21 @@ cannot enable executable stack as shared if (l->l_tls_initimage != NULL) l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr; + /* Process program headers again after load segments are mapped in + case processing requires accessing those segments. Scan program + headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY + exits. */ + for (ph = &l->l_phdr[l->l_phnum]; ph != l->l_phdr; --ph) + switch (ph[-1].p_type) + { + case PT_NOTE: + _dl_process_pt_note (l, fd, &ph[-1]); + break; + case PT_GNU_PROPERTY: + _dl_process_pt_gnu_property (l, fd, &ph[-1]); + break; + } + /* We are done mapping in the file. We no longer need the descriptor. */ if (__glibc_unlikely (__close_nocancel (fd) != 0)) { diff -pruN glibc-2.32.orig/elf/dl-tunables.c glibc-2.32/elf/dl-tunables.c --- glibc-2.32.orig/elf/dl-tunables.c 2021-09-18 21:02:32.643182660 +1000 +++ glibc-2.32/elf/dl-tunables.c 2021-09-18 21:03:05.311302253 +1000 @@ -177,6 +177,7 @@ parse_tunables (char *tunestr, char *val return; char *p = tunestr; + size_t off = 0; while (true) { @@ -190,7 +191,11 @@ parse_tunables (char *tunestr, char *val /* If we reach the end of the string before getting a valid name-value pair, bail out. */ if (p[len] == '\0') - return; + { + if (__libc_enable_secure) + tunestr[off] = '\0'; + return; + } /* We did not find a valid name-value pair before encountering the colon. */ @@ -216,35 +221,28 @@ parse_tunables (char *tunestr, char *val if (tunable_is_name (cur->name, name)) { - /* If we are in a secure context (AT_SECURE) then ignore the tunable - unless it is explicitly marked as secure. Tunable values take - precedence over their envvar aliases. */ + /* If we are in a secure context (AT_SECURE) then ignore the + tunable unless it is explicitly marked as secure. Tunable + values take precedence over their envvar aliases. We write + the tunables that are not SXID_ERASE back to TUNESTR, thus + dropping all SXID_ERASE tunables and any invalid or + unrecognized tunables. */ if (__libc_enable_secure) { - if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE) + if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE) { - if (p[len] == '\0') - { - /* Last tunable in the valstring. Null-terminate and - return. */ - *name = '\0'; - return; - } - else - { - /* Remove the current tunable from the string. We do - this by overwriting the string starting from NAME - (which is where the current tunable begins) with - the remainder of the string. We then have P point - to NAME so that we continue in the correct - position in the valstring. */ - char *q = &p[len + 1]; - p = name; - while (*q != '\0') - *name++ = *q++; - name[0] = '\0'; - len = 0; - } + if (off > 0) + tunestr[off++] = ':'; + + const char *n = cur->name; + + while (*n != '\0') + tunestr[off++] = *n++; + + tunestr[off++] = '='; + + for (size_t j = 0; j < len; j++) + tunestr[off++] = value[j]; } if (cur->security_level != TUNABLE_SECLEVEL_NONE) @@ -257,9 +255,7 @@ parse_tunables (char *tunestr, char *val } } - if (p[len] == '\0') - return; - else + if (p[len] != '\0') p += len + 1; } } diff -pruN glibc-2.32.orig/elf/ifuncmain6pie.c glibc-2.32/elf/ifuncmain6pie.c --- glibc-2.32.orig/elf/ifuncmain6pie.c 2021-09-18 21:02:32.643182660 +1000 +++ glibc-2.32/elf/ifuncmain6pie.c 2021-09-18 21:03:05.311302253 +1000 @@ -9,7 +9,6 @@ #include "ifunc-sel.h" typedef int (*foo_p) (void); -extern foo_p foo_ptr; static int one (void) @@ -28,20 +27,17 @@ foo_ifunc (void) } extern int foo (void); -extern foo_p get_foo (void); +extern int call_foo (void); extern foo_p get_foo_p (void); -foo_p my_foo_ptr = foo; +foo_p foo_ptr = foo; int main (void) { foo_p p; - p = get_foo (); - if (p != foo) - abort (); - if ((*p) () != -30) + if (call_foo () != -30) abort (); p = get_foo_p (); @@ -52,12 +48,8 @@ main (void) if (foo_ptr != foo) abort (); - if (my_foo_ptr != foo) - abort (); if ((*foo_ptr) () != -30) abort (); - if ((*my_foo_ptr) () != -30) - abort (); if (foo () != -30) abort (); diff -pruN glibc-2.32.orig/elf/ifuncmod6.c glibc-2.32/elf/ifuncmod6.c --- glibc-2.32.orig/elf/ifuncmod6.c 2021-09-18 21:02:32.643182660 +1000 +++ glibc-2.32/elf/ifuncmod6.c 2021-09-18 21:03:05.311302253 +1000 @@ -4,7 +4,7 @@ extern int foo (void); typedef int (*foo_p) (void); -foo_p foo_ptr = foo; +extern foo_p foo_ptr; foo_p get_foo_p (void) @@ -12,8 +12,8 @@ get_foo_p (void) return foo_ptr; } -foo_p -get_foo (void) +int +call_foo (void) { - return foo; + return foo (); } diff -pruN glibc-2.32.orig/elf/Makefile glibc-2.32/elf/Makefile --- glibc-2.32.orig/elf/Makefile 2021-09-18 21:02:32.643182660 +1000 +++ glibc-2.32/elf/Makefile 2021-09-18 21:03:05.311302253 +1000 @@ -1381,6 +1381,8 @@ CFLAGS-ifuncmain7pie.c += $(pie-ccflag) CFLAGS-ifuncmain9pie.c += $(pie-ccflag) CFLAGS-tst-ifunc-textrel.c += $(pic-ccflag) +LDFLAGS-ifuncmain6pie = -Wl,-z,lazy + $(objpfx)ifuncmain1pie: $(objpfx)ifuncmod1.so $(objpfx)ifuncmain1staticpie: $(objpfx)ifuncdep1pic.o $(objpfx)ifuncmain1vispie: $(objpfx)ifuncmod1.so @@ -1630,8 +1632,6 @@ $(objpfx)tst-nodelete-dlclose.out: $(obj tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \ LD_HWCAP_MASK=0x1 -tst-env-setuid-tunables-ENV = \ - GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096 $(objpfx)tst-debug1: $(libdl) $(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so diff -pruN glibc-2.32.orig/elf/rtld.c glibc-2.32/elf/rtld.c --- glibc-2.32.orig/elf/rtld.c 2021-09-18 21:02:32.644182694 +1000 +++ glibc-2.32/elf/rtld.c 2021-09-18 21:03:05.311302253 +1000 @@ -1534,10 +1534,10 @@ of this helper program; chances are you switch (ph[-1].p_type) { case PT_NOTE: - _dl_process_pt_note (main_map, &ph[-1]); + _dl_process_pt_note (main_map, -1, &ph[-1]); break; case PT_GNU_PROPERTY: - _dl_process_pt_gnu_property (main_map, &ph[-1]); + _dl_process_pt_gnu_property (main_map, -1, &ph[-1]); break; } diff -pruN glibc-2.32.orig/elf/tst-env-setuid.c glibc-2.32/elf/tst-env-setuid.c --- glibc-2.32.orig/elf/tst-env-setuid.c 2021-09-18 21:02:32.644182694 +1000 +++ glibc-2.32/elf/tst-env-setuid.c 2021-09-18 21:03:05.311302253 +1000 @@ -29,173 +29,12 @@ #include #include +#include #include #include +#include static char SETGID_CHILD[] = "setgid-child"; -#define CHILD_STATUS 42 - -/* Return a GID which is not our current GID, but is present in the - supplementary group list. */ -static gid_t -choose_gid (void) -{ - const int count = 64; - gid_t groups[count]; - int ret = getgroups (count, groups); - if (ret < 0) - { - printf ("getgroups: %m\n"); - exit (1); - } - gid_t current = getgid (); - for (int i = 0; i < ret; ++i) - { - if (groups[i] != current) - return groups[i]; - } - return 0; -} - -/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */ -static pid_t -do_execve (char **args) -{ - pid_t kid = vfork (); - - if (kid < 0) - { - printf ("vfork: %m\n"); - return -1; - } - - if (kid == 0) - { - /* Child process. */ - execve (args[0], args, environ); - _exit (-errno); - } - - if (kid < 0) - return 1; - - int status; - - if (waitpid (kid, &status, 0) < 0) - { - printf ("waitpid: %m\n"); - return 1; - } - - if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) - return EXIT_UNSUPPORTED; - - if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS) - { - printf ("Unexpected exit status %d from child process\n", - WEXITSTATUS (status)); - return 1; - } - return 0; -} - -/* Copies the executable into a restricted directory, so that we can - safely make it SGID with the TARGET group ID. Then runs the - executable. */ -static int -run_executable_sgid (gid_t target) -{ - char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd", - test_dir, (intmax_t) getpid ()); - char *execname = xasprintf ("%s/bin", dirname); - int infd = -1; - int outfd = -1; - int ret = 0; - if (mkdir (dirname, 0700) < 0) - { - printf ("mkdir: %m\n"); - goto err; - } - infd = open ("/proc/self/exe", O_RDONLY); - if (infd < 0) - { - printf ("open (/proc/self/exe): %m\n"); - goto err; - } - outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); - if (outfd < 0) - { - printf ("open (%s): %m\n", execname); - goto err; - } - char buf[4096]; - for (;;) - { - ssize_t rdcount = read (infd, buf, sizeof (buf)); - if (rdcount < 0) - { - printf ("read: %m\n"); - goto err; - } - if (rdcount == 0) - break; - char *p = buf; - char *end = buf + rdcount; - while (p != end) - { - ssize_t wrcount = write (outfd, buf, end - p); - if (wrcount == 0) - errno = ENOSPC; - if (wrcount <= 0) - { - printf ("write: %m\n"); - goto err; - } - p += wrcount; - } - } - if (fchown (outfd, getuid (), target) < 0) - { - printf ("fchown (%s): %m\n", execname); - goto err; - } - if (fchmod (outfd, 02750) < 0) - { - printf ("fchmod (%s): %m\n", execname); - goto err; - } - if (close (outfd) < 0) - { - printf ("close (outfd): %m\n"); - goto err; - } - if (close (infd) < 0) - { - printf ("close (infd): %m\n"); - goto err; - } - - char *args[] = {execname, SETGID_CHILD, NULL}; - - ret = do_execve (args); - -err: - if (outfd >= 0) - close (outfd); - if (infd >= 0) - close (infd); - if (execname) - { - unlink (execname); - free (execname); - } - if (dirname) - { - rmdir (dirname); - free (dirname); - } - return ret; -} #ifndef test_child static int @@ -256,40 +95,32 @@ do_test (int argc, char **argv) if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0) { if (getgid () == getegid ()) - { - /* This can happen if the file system is mounted nosuid. */ - fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n", - (intmax_t) getgid ()); - exit (EXIT_UNSUPPORTED); - } + /* This can happen if the file system is mounted nosuid. */ + FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", + (intmax_t) getgid ()); int ret = test_child (); if (ret != 0) exit (1); - exit (CHILD_STATUS); + exit (EXIT_SUCCESS); } else { if (test_parent () != 0) exit (1); - /* Try running a setgid program. */ - gid_t target = choose_gid (); - if (target == 0) - { - fprintf (stderr, - "Could not find a suitable GID for user %jd, skipping test\n", - (intmax_t) getuid ()); - exit (0); - } + int status = support_capture_subprogram_self_sgid (SETGID_CHILD); - return run_executable_sgid (target); - } + if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) + return EXIT_UNSUPPORTED; + + if (!WIFEXITED (status)) + FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status); - /* Something went wrong and our argv was corrupted. */ - _exit (1); + return 0; + } } #define TEST_FUNCTION_ARGV do_test diff -pruN glibc-2.32.orig/elf/tst-env-setuid-tunables.c glibc-2.32/elf/tst-env-setuid-tunables.c --- glibc-2.32.orig/elf/tst-env-setuid-tunables.c 2021-09-18 21:02:32.644182694 +1000 +++ glibc-2.32/elf/tst-env-setuid-tunables.c 2021-09-18 21:03:05.311302253 +1000 @@ -25,35 +25,76 @@ #include "config.h" #undef _LIBC -#define test_parent test_parent_tunables -#define test_child test_child_tunables +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include -static int test_child_tunables (void); -static int test_parent_tunables (void); - -#include "tst-env-setuid.c" +const char *teststrings[] = +{ + "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2", + "glibc.malloc.perturb=0x800", + "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", + "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.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", + "glibc.malloc.check=1:glibc.malloc.check=2", + "not_valid.malloc.check=2", + "glibc.not_valid.check=2", +}; -#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096" -#define PARENT_VALSTRING_VALUE \ - "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096" +const char *resultstrings[] = +{ + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.perturb=0x800", + "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "", + "", + "", + "", + "", + "", +}; static int -test_child_tunables (void) +test_child (int off) { const char *val = getenv ("GLIBC_TUNABLES"); #if HAVE_TUNABLES - if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0) + if (val != NULL && strcmp (val, resultstrings[off]) == 0) return 0; if (val != NULL) - printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val); + printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); return 1; #else if (val != NULL) { - printf ("GLIBC_TUNABLES not cleared\n"); + printf ("[%d] GLIBC_TUNABLES not cleared\n", off); return 1; } return 0; @@ -61,15 +102,48 @@ test_child_tunables (void) } static int -test_parent_tunables (void) +do_test (int argc, char **argv) { - const char *val = getenv ("GLIBC_TUNABLES"); + /* Setgid child process. */ + if (argc == 2) + { + if (getgid () == getegid ()) + /* This can happen if the file system is mounted nosuid. */ + FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", + (intmax_t) getgid ()); - if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0) - return 0; + int ret = test_child (atoi (argv[1])); - if (val != NULL) - printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val); + if (ret != 0) + exit (1); - return 1; + exit (EXIT_SUCCESS); + } + 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); + snprintf (buf, sizeof (buf), "%d\n", i); + if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) + exit (1); + + int status = support_capture_subprogram_self_sgid (buf); + + /* Bail out early if unsupported. */ + if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) + return EXIT_UNSUPPORTED; + + ret |= status; + } + return ret; + } } + +#define TEST_FUNCTION_ARGV do_test +#include diff -pruN glibc-2.32.orig/iconv/gconv_charset.c glibc-2.32/iconv/gconv_charset.c --- glibc-2.32.orig/iconv/gconv_charset.c 2021-09-18 21:02:32.646182763 +1000 +++ glibc-2.32/iconv/gconv_charset.c 2021-09-18 21:03:05.311302253 +1000 @@ -216,3 +216,13 @@ out: return ret; } libc_hidden_def (__gconv_create_spec) + + +void +__gconv_destroy_spec (struct gconv_spec *conv_spec) +{ + free (conv_spec->fromcode); + free (conv_spec->tocode); + return; +} +libc_hidden_def (__gconv_destroy_spec) diff -pruN glibc-2.32.orig/iconv/gconv_charset.h glibc-2.32/iconv/gconv_charset.h --- glibc-2.32.orig/iconv/gconv_charset.h 2021-09-18 21:02:32.646182763 +1000 +++ glibc-2.32/iconv/gconv_charset.h 2021-09-18 21:03:05.311302253 +1000 @@ -48,33 +48,6 @@ #define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE" -/* This function accepts the charset names of the source and destination of the - conversion and populates *conv_spec with an equivalent conversion - specification that may later be used by __gconv_open. The charset names - might contain options in the form of suffixes that alter the conversion, - e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring - and truncating any suffix options in fromcode, and processing and truncating - any suffix options in tocode. Supported suffix options ("TRANSLIT" or - "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec - to be set to true. Unrecognized suffix options are silently discarded. If - the function succeeds, it returns conv_spec back to the caller. It returns - NULL upon failure. */ -struct gconv_spec * -__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, - const char *tocode); -libc_hidden_proto (__gconv_create_spec) - - -/* This function frees all heap memory allocated by __gconv_create_spec. */ -static void __attribute__ ((unused)) -gconv_destroy_spec (struct gconv_spec *conv_spec) -{ - free (conv_spec->fromcode); - free (conv_spec->tocode); - return; -} - - /* This function copies in-order, characters from the source 's' that are either alpha-numeric or one in one of these: "_-.,:/" - into the destination 'wp' while dropping all other characters. In the process, it converts all diff -pruN glibc-2.32.orig/iconv/gconv_int.h glibc-2.32/iconv/gconv_int.h --- glibc-2.32.orig/iconv/gconv_int.h 2021-09-18 21:02:32.646182763 +1000 +++ glibc-2.32/iconv/gconv_int.h 2021-09-18 21:03:05.311302253 +1000 @@ -152,6 +152,27 @@ extern int __gconv_open (struct gconv_sp __gconv_t *handle, int flags); libc_hidden_proto (__gconv_open) +/* This function accepts the charset names of the source and destination of the + conversion and populates *conv_spec with an equivalent conversion + specification that may later be used by __gconv_open. The charset names + might contain options in the form of suffixes that alter the conversion, + e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring + and truncating any suffix options in fromcode, and processing and truncating + any suffix options in tocode. Supported suffix options ("TRANSLIT" or + "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec + to be set to true. Unrecognized suffix options are silently discarded. If + the function succeeds, it returns conv_spec back to the caller. It returns + NULL upon failure. */ +extern struct gconv_spec * +__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, + const char *tocode); +libc_hidden_proto (__gconv_create_spec) + +/* This function frees all heap memory allocated by __gconv_create_spec. */ +extern void +__gconv_destroy_spec (struct gconv_spec *conv_spec); +libc_hidden_proto (__gconv_destroy_spec) + /* Free resources associated with transformation descriptor CD. */ extern int __gconv_close (__gconv_t cd) attribute_hidden; diff -pruN glibc-2.32.orig/iconv/iconv_open.c glibc-2.32/iconv/iconv_open.c --- glibc-2.32.orig/iconv/iconv_open.c 2021-09-18 21:02:32.646182763 +1000 +++ glibc-2.32/iconv/iconv_open.c 2021-09-18 21:03:05.311302253 +1000 @@ -39,7 +39,7 @@ iconv_open (const char *tocode, const ch int res = __gconv_open (&conv_spec, &cd, 0); - gconv_destroy_spec (&conv_spec); + __gconv_destroy_spec (&conv_spec); if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK) { diff -pruN glibc-2.32.orig/iconv/iconv_prog.c glibc-2.32/iconv/iconv_prog.c --- glibc-2.32.orig/iconv/iconv_prog.c 2021-09-18 21:02:32.646182763 +1000 +++ glibc-2.32/iconv/iconv_prog.c 2021-09-18 21:03:05.311302253 +1000 @@ -184,7 +184,7 @@ main (int argc, char *argv[]) /* Let's see whether we have these coded character sets. */ res = __gconv_open (&conv_spec, &cd, 0); - gconv_destroy_spec (&conv_spec); + __gconv_destroy_spec (&conv_spec); if (res != __GCONV_OK) { diff -pruN glibc-2.32.orig/iconv/tst-iconv_prog.sh glibc-2.32/iconv/tst-iconv_prog.sh --- glibc-2.32.orig/iconv/tst-iconv_prog.sh 2021-09-18 21:02:32.646182763 +1000 +++ glibc-2.32/iconv/tst-iconv_prog.sh 2021-09-18 21:03:05.311302253 +1000 @@ -102,12 +102,16 @@ hangarray=( "\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE" "\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE" "\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE" -# These are known hangs that are yet to be fixed: -# "\x00\x0f;-c;IBM1364;UTF-8" -# "\x00\x0f;-c;IBM1371;UTF-8" -# "\x00\x0f;-c;IBM1388;UTF-8" -# "\x00\x0f;-c;IBM1390;UTF-8" -# "\x00\x0f;-c;IBM1399;UTF-8" +"\x00\x0f;-c;IBM1364;UTF-8" +"\x0e\x0e;-c;IBM1364;UTF-8" +"\x00\x0f;-c;IBM1371;UTF-8" +"\x0e\x0e;-c;IBM1371;UTF-8" +"\x00\x0f;-c;IBM1388;UTF-8" +"\x0e\x0e;-c;IBM1388;UTF-8" +"\x00\x0f;-c;IBM1390;UTF-8" +"\x0e\x0e;-c;IBM1390;UTF-8" +"\x00\x0f;-c;IBM1399;UTF-8" +"\x0e\x0e;-c;IBM1399;UTF-8" "\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE" "\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE" "\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE" diff -pruN glibc-2.32.orig/iconv/Versions glibc-2.32/iconv/Versions --- glibc-2.32.orig/iconv/Versions 2021-09-18 21:02:32.646182763 +1000 +++ glibc-2.32/iconv/Versions 2021-09-18 21:03:05.311302253 +1000 @@ -6,7 +6,9 @@ libc { GLIBC_PRIVATE { # functions shared with iconv program __gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db; - __gconv_open; __gconv_create_spec; + + # functions used elsewhere in glibc + __gconv_open; __gconv_create_spec; __gconv_destroy_spec; # function used by the gconv modules __gconv_transliterate; diff -pruN glibc-2.32.orig/iconvdata/bug-iconv13.c glibc-2.32/iconvdata/bug-iconv13.c --- glibc-2.32.orig/iconvdata/bug-iconv13.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/iconvdata/bug-iconv13.c 2021-09-18 21:03:05.311302253 +1000 @@ -0,0 +1,53 @@ +/* bug 24973: Test EUC-KR module + Copyright (C) 2020 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 + +static int +do_test (void) +{ + iconv_t cd = iconv_open ("UTF-8//IGNORE", "EUC-KR"); + TEST_VERIFY_EXIT (cd != (iconv_t) -1); + + /* 0xfe (->0x7e : row 94) and 0xc9 (->0x49 : row 41) are user-defined + areas, which are not allowed and should be skipped over due to + //IGNORE. The trailing 0xfe also is an incomplete sequence, which + should be checked first. */ + char input[4] = { '\xc9', '\xa1', '\0', '\xfe' }; + char *inptr = input; + size_t insize = sizeof (input); + char output[4]; + char *outptr = output; + size_t outsize = sizeof (output); + + /* This used to crash due to buffer overrun. */ + TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) -1); + TEST_VERIFY (errno == EINVAL); + /* The conversion should produce one character, the converted null + character. */ + TEST_VERIFY (sizeof (output) - outsize == 1); + + TEST_VERIFY_EXIT (iconv_close (cd) != -1); + + return 0; +} + +#include diff -pruN glibc-2.32.orig/iconvdata/bug-iconv14.c glibc-2.32/iconvdata/bug-iconv14.c --- glibc-2.32.orig/iconvdata/bug-iconv14.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/iconvdata/bug-iconv14.c 2021-09-18 21:03:05.311302253 +1000 @@ -0,0 +1,127 @@ +/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256). + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +/* Use an escape sequence to return to the initial state. */ +static void +with_escape_sequence (void) +{ + iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3"); + TEST_VERIFY_EXIT (c != (iconv_t) -1); + + char in[] = "\e$(O+D\e(B"; + char *inbuf = in; + size_t inleft = strlen (in); + char out[3]; /* Space for one output character. */ + char *outbuf; + size_t outleft; + + outbuf = out; + outleft = sizeof (out); + TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1); + TEST_COMPARE (errno, E2BIG); + TEST_COMPARE (inleft, 3); + TEST_COMPARE (inbuf - in, strlen (in) - 3); + TEST_COMPARE (outleft, sizeof (out) - 2); + TEST_COMPARE (outbuf - out, 2); + TEST_COMPARE (out[0] & 0xff, 0xc3); + TEST_COMPARE (out[1] & 0xff, 0xa6); + + /* Return to the initial shift state, producing the pending + character. */ + outbuf = out; + outleft = sizeof (out); + TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0); + TEST_COMPARE (inleft, 0); + TEST_COMPARE (inbuf - in, strlen (in)); + TEST_COMPARE (outleft, sizeof (out) - 2); + TEST_COMPARE (outbuf - out, 2); + TEST_COMPARE (out[0] & 0xff, 0xcc); + TEST_COMPARE (out[1] & 0xff, 0x80); + + /* Nothing should be flushed the second time. */ + outbuf = out; + outleft = sizeof (out); + TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); + TEST_COMPARE (outleft, sizeof (out)); + TEST_COMPARE (outbuf - out, 0); + TEST_COMPARE (out[0] & 0xff, 0xcc); + TEST_COMPARE (out[1] & 0xff, 0x80); + + TEST_COMPARE (iconv_close (c), 0); +} + +/* Use an explicit flush to return to the initial state. */ +static void +with_flush (void) +{ + iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3"); + TEST_VERIFY_EXIT (c != (iconv_t) -1); + + char in[] = "\e$(O+D"; + char *inbuf = in; + size_t inleft = strlen (in); + char out[3]; /* Space for one output character. */ + char *outbuf; + size_t outleft; + + outbuf = out; + outleft = sizeof (out); + TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1); + TEST_COMPARE (errno, E2BIG); + TEST_COMPARE (inleft, 0); + TEST_COMPARE (inbuf - in, strlen (in)); + TEST_COMPARE (outleft, sizeof (out) - 2); + TEST_COMPARE (outbuf - out, 2); + TEST_COMPARE (out[0] & 0xff, 0xc3); + TEST_COMPARE (out[1] & 0xff, 0xa6); + + /* Flush the pending character. */ + outbuf = out; + outleft = sizeof (out); + TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); + TEST_COMPARE (outleft, sizeof (out) - 2); + TEST_COMPARE (outbuf - out, 2); + TEST_COMPARE (out[0] & 0xff, 0xcc); + TEST_COMPARE (out[1] & 0xff, 0x80); + + /* Nothing should be flushed the second time. */ + outbuf = out; + outleft = sizeof (out); + TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); + TEST_COMPARE (outleft, sizeof (out)); + TEST_COMPARE (outbuf - out, 0); + TEST_COMPARE (out[0] & 0xff, 0xcc); + TEST_COMPARE (out[1] & 0xff, 0x80); + + TEST_COMPARE (iconv_close (c), 0); +} + +static int +do_test (void) +{ + with_escape_sequence (); + with_flush (); + return 0; +} + +#include diff -pruN glibc-2.32.orig/iconvdata/euc-kr.c glibc-2.32/iconvdata/euc-kr.c --- glibc-2.32.orig/iconvdata/euc-kr.c 2021-09-18 21:02:32.648182831 +1000 +++ glibc-2.32/iconvdata/euc-kr.c 2021-09-18 21:03:05.311302253 +1000 @@ -80,11 +80,7 @@ euckr_from_ucs4 (uint32_t ch, unsigned c \ if (ch <= 0x9f) \ ++inptr; \ - /* 0xfe(->0x7e : row 94) and 0xc9(->0x59 : row 41) are \ - user-defined areas. */ \ - else if (__builtin_expect (ch == 0xa0, 0) \ - || __builtin_expect (ch > 0xfe, 0) \ - || __builtin_expect (ch == 0xc9, 0)) \ + else if (__glibc_unlikely (ch == 0xa0)) \ { \ /* This is illegal. */ \ STANDARD_FROM_LOOP_ERR_HANDLER (1); \ diff -pruN glibc-2.32.orig/iconvdata/ibm1364.c glibc-2.32/iconvdata/ibm1364.c --- glibc-2.32.orig/iconvdata/ibm1364.c 2021-09-18 21:02:32.649182866 +1000 +++ glibc-2.32/iconvdata/ibm1364.c 2021-09-18 21:03:05.311302253 +1000 @@ -158,24 +158,14 @@ enum \ if (__builtin_expect (ch, 0) == SO) \ { \ - /* Shift OUT, change to DBCS converter. */ \ - if (curcs == db) \ - { \ - result = __GCONV_ILLEGAL_INPUT; \ - break; \ - } \ + /* Shift OUT, change to DBCS converter (redundant escape okay). */ \ curcs = db; \ ++inptr; \ continue; \ } \ if (__builtin_expect (ch, 0) == SI) \ { \ - /* Shift IN, change to SBCS converter. */ \ - if (curcs == sb) \ - { \ - result = __GCONV_ILLEGAL_INPUT; \ - break; \ - } \ + /* Shift IN, change to SBCS converter (redundant escape okay). */ \ curcs = sb; \ ++inptr; \ continue; \ diff -pruN glibc-2.32.orig/iconvdata/iso-2022-jp-3.c glibc-2.32/iconvdata/iso-2022-jp-3.c --- glibc-2.32.orig/iconvdata/iso-2022-jp-3.c 2021-09-18 21:02:32.651182934 +1000 +++ glibc-2.32/iconvdata/iso-2022-jp-3.c 2021-09-18 21:03:05.311302253 +1000 @@ -67,23 +67,34 @@ enum CURRENT_SEL_MASK = 7 << 3 }; -/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state - also contains the last two bytes to be output, shifted by 6 bits, and a - one-bit indicator whether they must be preceded by the shift sequence, - in bit 22. */ +/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the + state also contains the last two bytes to be output, shifted by 6 + bits, and a one-bit indicator whether they must be preceded by the + shift sequence, in bit 22. During ISO-2022-JP-3 to UCS-4 + conversion, COUNT may also contain a non-zero pending wide + character, shifted by six bits. This happens for certain inputs in + JISX0213_1_2004_set and JISX0213_2_set if the second wide character + in a combining sequence cannot be written because the buffer is + full. */ /* Since this is a stateful encoding we have to provide code which resets the output state to the initial state. This has to be done during the flushing. */ #define EMIT_SHIFT_TO_INIT \ - if ((data->__statep->__count & ~7) != ASCII_set) \ + if (data->__statep->__count != ASCII_set) \ { \ if (FROM_DIRECTION) \ { \ - /* It's easy, we don't have to emit anything, we just reset the \ - state for the input. */ \ - data->__statep->__count &= 7; \ - data->__statep->__count |= ASCII_set; \ + if (__glibc_likely (outbuf + 4 <= outend)) \ + { \ + /* Write out the last character. */ \ + *((uint32_t *) outbuf) = data->__statep->__count >> 6; \ + outbuf += sizeof (uint32_t); \ + data->__statep->__count = ASCII_set; \ + } \ + else \ + /* We don't have enough room in the output buffer. */ \ + status = __GCONV_FULL_OUTPUT; \ } \ else \ { \ @@ -151,7 +162,21 @@ enum #define LOOPFCT FROM_LOOP #define BODY \ { \ - uint32_t ch = *inptr; \ + uint32_t ch; \ + \ + /* Output any pending character. */ \ + ch = set >> 6; \ + if (__glibc_unlikely (ch != 0)) \ + { \ + put32 (outptr, ch); \ + outptr += 4; \ + /* Remove the pending character, but preserve state bits. */ \ + set &= (1 << 6) - 1; \ + continue; \ + } \ + \ + /* Otherwise read the next input byte. */ \ + ch = *inptr; \ \ /* Recognize escape sequences. */ \ if (__glibc_unlikely (ch == ESC)) \ @@ -297,21 +322,25 @@ enum uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0]; \ uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1]; \ \ + inptr += 2; \ + \ + put32 (outptr, u1); \ + outptr += 4; \ + \ /* See whether we have room for two characters. */ \ - if (outptr + 8 <= outend) \ + if (outptr + 4 <= outend) \ { \ - inptr += 2; \ - put32 (outptr, u1); \ - outptr += 4; \ put32 (outptr, u2); \ outptr += 4; \ continue; \ } \ - else \ - { \ - result = __GCONV_FULL_OUTPUT; \ - break; \ - } \ + \ + /* Otherwise store only the first character now, and \ + put the second one into the queue. */ \ + set |= u2 << 6; \ + /* Tell the caller why we terminate the loop. */ \ + result = __GCONV_FULL_OUTPUT; \ + break; \ } \ \ inptr += 2; \ diff -pruN glibc-2.32.orig/iconvdata/ksc5601.h glibc-2.32/iconvdata/ksc5601.h --- glibc-2.32.orig/iconvdata/ksc5601.h 2021-09-18 21:02:32.652182968 +1000 +++ glibc-2.32/iconvdata/ksc5601.h 2021-09-18 21:03:05.311302253 +1000 @@ -50,15 +50,15 @@ ksc5601_to_ucs4 (const unsigned char **s unsigned char ch2; int idx; + if (avail < 2) + return 0; + /* row 94(0x7e) and row 41(0x49) are user-defined area in KS C 5601 */ if (ch < offset || (ch - offset) <= 0x20 || (ch - offset) >= 0x7e || (ch - offset) == 0x49) return __UNKNOWN_10646_CHAR; - if (avail < 2) - return 0; - ch2 = (*s)[1]; if (ch2 < offset || (ch2 - offset) <= 0x20 || (ch2 - offset) >= 0x7f) return __UNKNOWN_10646_CHAR; diff -pruN glibc-2.32.orig/iconvdata/Makefile glibc-2.32/iconvdata/Makefile --- glibc-2.32.orig/iconvdata/Makefile 2021-09-18 21:02:32.647182797 +1000 +++ glibc-2.32/iconvdata/Makefile 2021-09-18 21:03:05.311302253 +1000 @@ -73,7 +73,8 @@ modules.so := $(addsuffix .so, $(modules 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-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \ + bug-iconv13 bug-iconv14 ifeq ($(have-thread-library),yes) tests += bug-iconv3 endif @@ -321,6 +322,8 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv $(addprefix $(objpfx),$(modules.so)) $(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \ $(addprefix $(objpfx),$(modules.so)) +$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \ + $(addprefix $(objpfx),$(modules.so)) $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \ $(addprefix $(objpfx),$(modules.so)) \ diff -pruN glibc-2.32.orig/intl/dcigettext.c glibc-2.32/intl/dcigettext.c --- glibc-2.32.orig/intl/dcigettext.c 2021-09-18 21:02:32.656183106 +1000 +++ glibc-2.32/intl/dcigettext.c 2021-09-18 21:03:05.311302253 +1000 @@ -1120,15 +1120,18 @@ _nl_find_msg (struct loaded_l10nfile *do # ifdef _LIBC - struct gconv_spec conv_spec - = { .fromcode = norm_add_slashes (charset, ""), - .tocode = norm_add_slashes (outcharset, ""), - /* We always want to use transliteration. */ - .translit = true, - .ignore = false - }; + struct gconv_spec conv_spec; + + __gconv_create_spec (&conv_spec, charset, outcharset); + + /* We always want to use transliteration. */ + conv_spec.translit = true; + int r = __gconv_open (&conv_spec, &convd->conv, GCONV_AVOID_NOCONV); + + __gconv_destroy_spec (&conv_spec); + if (__builtin_expect (r != __GCONV_OK, 0)) { /* If the output encoding is the same there is diff -pruN glibc-2.32.orig/intl/tst-codeset.c glibc-2.32/intl/tst-codeset.c --- glibc-2.32.orig/intl/tst-codeset.c 2021-09-18 21:02:32.656183106 +1000 +++ glibc-2.32/intl/tst-codeset.c 2021-09-18 21:03:05.311302253 +1000 @@ -22,13 +22,11 @@ #include #include #include +#include static int do_test (void) { - char *s; - int result = 0; - unsetenv ("LANGUAGE"); unsetenv ("OUTPUT_CHARSET"); setlocale (LC_ALL, "de_DE.ISO-8859-1"); @@ -36,25 +34,21 @@ do_test (void) bindtextdomain ("codeset", OBJPFX "domaindir"); /* Here we expect output in ISO-8859-1. */ - s = gettext ("cheese"); - if (strcmp (s, "K\344se")) - { - printf ("call 1 returned: %s\n", s); - result = 1; - } + TEST_COMPARE_STRING (gettext ("cheese"), "K\344se"); + /* Here we expect output in UTF-8. */ bind_textdomain_codeset ("codeset", "UTF-8"); + TEST_COMPARE_STRING (gettext ("cheese"), "K\303\244se"); - /* Here we expect output in UTF-8. */ - s = gettext ("cheese"); - if (strcmp (s, "K\303\244se")) - { - printf ("call 2 returned: %s\n", s); - result = 1; - } + /* `a with umlaut' is transliterated to `ae'. */ + bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT"); + TEST_COMPARE_STRING (gettext ("cheese"), "Kaese"); + + /* Transliteration also works by default even if not set. */ + bind_textdomain_codeset ("codeset", "ASCII"); + TEST_COMPARE_STRING (gettext ("cheese"), "Kaese"); - return result; + return 0; } -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include diff -pruN glibc-2.32.orig/malloc/Makefile glibc-2.32/malloc/Makefile --- glibc-2.32.orig/malloc/Makefile 2021-09-18 21:02:32.670183585 +1000 +++ glibc-2.32/malloc/Makefile 2021-09-18 21:03:05.312302287 +1000 @@ -62,6 +62,16 @@ endif tests += $(tests-static) test-srcs = tst-mtrace +# These tests either are run with MALLOC_CHECK_=3 by default or do not work +# with MALLOC_CHECK_=3 because they expect a specific failure. +tests-exclude-mcheck = tst-mcheck tst-malloc-usable \ + tst-interpose-nothread tst-interpose-static-nothread \ + tst-interpose-static-thread tst-malloc-too-large \ + tst-mxfast tst-safe-linking + +# Run all tests with MALLOC_CHECK_=3 +tests-mcheck = $(filter-out $(tests-exclude-mcheck),$(tests)) + routines = malloc morecore mcheck mtrace obstack reallocarray \ scratch_buffer_grow scratch_buffer_grow_preserve \ scratch_buffer_set_array_size \ @@ -100,6 +110,11 @@ $(objpfx)tst-malloc-thread-exit: $(share $(objpfx)tst-malloc-thread-fail: $(shared-thread-library) $(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library) $(objpfx)tst-malloc-stats-cancellation: $(shared-thread-library) +$(objpfx)tst-malloc-backtrace-mcheck: $(shared-thread-library) +$(objpfx)tst-malloc-thread-exit-mcheck: $(shared-thread-library) +$(objpfx)tst-malloc-thread-fail-mcheck: $(shared-thread-library) +$(objpfx)tst-malloc-fork-deadlock-mcheck: $(shared-thread-library) +$(objpfx)tst-malloc-stats-cancellation-mcheck: $(shared-thread-library) # Export the __malloc_initialize_hook variable to libc.so. LDFLAGS-tst-mallocstate = -rdynamic @@ -239,6 +254,8 @@ $(tests:%=$(objpfx)%.o): CPPFLAGS += -DT $(objpfx)tst-interpose-nothread: $(objpfx)tst-interpose-aux-nothread.o $(objpfx)tst-interpose-thread: \ $(objpfx)tst-interpose-aux-thread.o $(shared-thread-library) +$(objpfx)tst-interpose-thread-mcheck: \ + $(objpfx)tst-interpose-aux-thread.o $(shared-thread-library) $(objpfx)tst-interpose-static-nothread: $(objpfx)tst-interpose-aux-nothread.o $(objpfx)tst-interpose-static-thread: \ $(objpfx)tst-interpose-aux-thread.o $(static-thread-library) @@ -256,3 +273,6 @@ $(objpfx)tst-dynarray-fail-mem.out: $(ob $(objpfx)tst-malloc-tcache-leak: $(shared-thread-library) $(objpfx)tst-malloc_info: $(shared-thread-library) $(objpfx)tst-mallocfork2: $(shared-thread-library) +$(objpfx)tst-malloc-tcache-leak-mcheck: $(shared-thread-library) +$(objpfx)tst-malloc_info-mcheck: $(shared-thread-library) +$(objpfx)tst-mallocfork2-mcheck: $(shared-thread-library) diff -pruN glibc-2.32.orig/manual/tunables.texi glibc-2.32/manual/tunables.texi --- glibc-2.32.orig/manual/tunables.texi 2021-09-18 21:02:32.672183654 +1000 +++ glibc-2.32/manual/tunables.texi 2021-09-18 21:03:05.312302287 +1000 @@ -432,7 +432,11 @@ set shared cache size in bytes for use i @deftp Tunable glibc.cpu.x86_non_temporal_threshold The @code{glibc.cpu.x86_non_temporal_threshold} tunable allows the user -to set threshold in bytes for non temporal store. +to set threshold in bytes for non temporal store. Non temporal stores +give a hint to the hardware to move data directly to memory without +displacing other data from the cache. This tunable is used by some +platforms to determine when to use non temporal stores in operations +like memmove and memcpy. This tunable is specific to i386 and x86-64. @end deftp diff -pruN glibc-2.32.orig/misc/sys/cdefs.h glibc-2.32/misc/sys/cdefs.h --- glibc-2.32.orig/misc/sys/cdefs.h 2021-09-18 21:02:32.690184271 +1000 +++ glibc-2.32/misc/sys/cdefs.h 2021-09-18 21:03:05.312302287 +1000 @@ -124,13 +124,10 @@ #define __bos0(ptr) __builtin_object_size (ptr, 0) #if __GNUC_PREREQ (4,3) -# define __warndecl(name, msg) \ - extern void name (void) __attribute__((__warning__ (msg))) # define __warnattr(msg) __attribute__((__warning__ (msg))) # define __errordecl(name, msg) \ extern void name (void) __attribute__((__error__ (msg))) #else -# define __warndecl(name, msg) extern void name (void) # define __warnattr(msg) # define __errordecl(name, msg) extern void name (void) #endif diff -pruN glibc-2.32.orig/NEWS glibc-2.32/NEWS --- glibc-2.32.orig/NEWS 2021-09-18 21:02:32.639182523 +1000 +++ glibc-2.32/NEWS 2021-09-18 21:30:11.284117111 +1000 @@ -5,6 +5,33 @@ See the end for copying conditions. Please send GNU C library bug reports via using `glibc' in the "product" field. +The following bugs are resolved with this release: + + [20019] NULL pointer dereference in libc.so.6 IFUNC due to uninitialized GOT + [25399] Remove __warn_memset_zero_len + [26224] iconv hangs when converting some invalid inputs from several IBM + character sets (CVE-2020-27618) + [26534] libm.so 2.32 SIGILL in pow() due to FMA4 instruction on non-FMA4 + system + [26555] string: strerrorname_np does not return the documented value + [26600] Transaction ID collisions cause slow DNS lookups in getaddrinfo + [26636] libc: 32-bit shmctl(IPC_INFO) crashes when shminfo struct is + at the end of a memory mapping + [26637] libc: semctl SEM_STAT_ANY fails to pass the buffer specified + by the caller to the kernel + [26639] libc: msgctl IPC_INFO and MSG_INFO return garbage + [26690] __vfscanf_internal: fix aliasing violation + [26853] aarch64: Missing unwind information in statically linked startup code + [26932] libc: sh: Multiple floating point functions defined as stubs only + [27024] posix: Correct attribute access mode on readlinkat + [27130] "rep movsb" performance issue + [27177] GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on doesn't work + [27256] gconv: Fix assertion failure in ISO-2022-JP-3 module + [27462] nscd: Fix double free in netgroupcache + [27471] Fix SXID_ERASE behavior in setuid programs + [27896] Use __pthread_attr_copy in mq_notify (CVE-2021-33574) + [28213] librt: fix NULL pointer dereference + Version 2.32 Major new features: @@ -185,6 +212,14 @@ Security related changes: Dytrych of the Cisco Security Assessment and Penetration Team (See TALOS-2020-1019). + CVE-2020-27618: An infinite loop has been fixed in the iconv program when + invoked with input containing redundant shift sequences in the IBM1364, + IBM1371, IBM1388, IBM1390, or IBM1399 character sets. + + CVE-2021-33574: The mq_notify function has a potential use-after-free + issue when using a notification type of SIGEV_THREAD and a thread + attribute with a non-default affinity mask. + The following bugs are resolved with this release: [9809] localedata: ckb_IQ: new Kurdish Sorani locale diff -pruN glibc-2.32.orig/nscd/netgroupcache.c glibc-2.32/nscd/netgroupcache.c --- glibc-2.32.orig/nscd/netgroupcache.c 2021-09-18 21:02:32.692184339 +1000 +++ glibc-2.32/nscd/netgroupcache.c 2021-09-18 21:03:05.312302287 +1000 @@ -248,7 +248,7 @@ addgetnetgrentX (struct database_dyn *db : NULL); ndomain = (ndomain ? newbuf + ndomaindiff : NULL); - buffer = newbuf; + *tofreep = buffer = newbuf; } nhost = memcpy (buffer + bufused, @@ -319,7 +319,7 @@ addgetnetgrentX (struct database_dyn *db else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE) { buflen *= 2; - buffer = xrealloc (buffer, buflen); + *tofreep = buffer = xrealloc (buffer, buflen); } else if (status == NSS_STATUS_RETURN || status == NSS_STATUS_NOTFOUND diff -pruN glibc-2.32.orig/posix/unistd.h glibc-2.32/posix/unistd.h --- glibc-2.32.orig/posix/unistd.h 2021-09-18 21:02:32.696184476 +1000 +++ glibc-2.32/posix/unistd.h 2021-09-18 21:04:13.411636170 +1000 @@ -831,7 +831,7 @@ extern int symlinkat (const char *__from /* Like readlink but a relative PATH is interpreted relative to FD. */ extern ssize_t readlinkat (int __fd, const char *__restrict __path, char *__restrict __buf, size_t __len) - __THROW __nonnull ((2, 3)) __wur __attr_access ((__read_only__, 3, 4)); + __THROW __nonnull ((2, 3)) __wur __attr_access ((__write_only__, 3, 4)); #endif /* Remove the link NAME. */ diff -pruN glibc-2.32.orig/posix/wordexp.c glibc-2.32/posix/wordexp.c --- glibc-2.32.orig/posix/wordexp.c 2021-09-18 21:02:32.696184476 +1000 +++ glibc-2.32/posix/wordexp.c 2021-09-18 21:03:05.312302287 +1000 @@ -1399,7 +1399,7 @@ envsubst: /* Is it a numeric parameter? */ else if (isdigit (env[0])) { - int n = atoi (env); + unsigned long n = strtoul (env, NULL, 10); if (n >= __libc_argc) /* Substitute NULL. */ diff -pruN glibc-2.32.orig/posix/wordexp-test.c glibc-2.32/posix/wordexp-test.c --- glibc-2.32.orig/posix/wordexp-test.c 2021-09-18 21:02:32.696184476 +1000 +++ glibc-2.32/posix/wordexp-test.c 2021-09-18 21:03:05.312302287 +1000 @@ -183,6 +183,7 @@ struct test_case_struct { 0, NULL, "$var", 0, 0, { NULL, }, IFS }, { 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS }, { 0, NULL, "", 0, 0, { NULL, }, IFS }, + { 0, NULL, "${1234567890123456789012}", 0, 0, { NULL, }, IFS }, /* Flags not already covered (testit() has special handling for these) */ { 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS }, diff -pruN glibc-2.32.orig/resolv/Makefile glibc-2.32/resolv/Makefile --- glibc-2.32.orig/resolv/Makefile 2021-09-18 21:02:32.696184476 +1000 +++ glibc-2.32/resolv/Makefile 2021-09-18 21:03:05.312302287 +1000 @@ -61,6 +61,11 @@ tests += \ tst-resolv-search \ tst-resolv-trailing \ +# This test calls __res_context_send directly, which is not exported +# from libresolv. +tests-internal += tst-resolv-txnid-collision +tests-static += tst-resolv-txnid-collision + # These tests need libdl. ifeq (yes,$(build-shared)) tests += \ @@ -191,6 +196,8 @@ $(objpfx)tst-resolv-search: $(objpfx)lib $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-threads: \ $(libdl) $(objpfx)libresolv.so $(shared-thread-library) +$(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \ + $(static-thread-library) $(objpfx)tst-resolv-canonname: \ $(libdl) $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-trustad: $(objpfx)libresolv.so $(shared-thread-library) diff -pruN glibc-2.32.orig/resolv/res_send.c glibc-2.32/resolv/res_send.c --- glibc-2.32.orig/resolv/res_send.c 2021-09-18 21:02:32.696184476 +1000 +++ glibc-2.32/resolv/res_send.c 2021-09-18 21:03:05.312302287 +1000 @@ -1342,15 +1342,6 @@ send_dg(res_state statp, *terrno = EMSGSIZE; return close_and_return_error (statp, resplen2); } - if ((recvresp1 || hp->id != anhp->id) - && (recvresp2 || hp2->id != anhp->id)) { - /* - * response from old query, ignore it. - * XXX - potential security hazard could - * be detected here. - */ - goto wait; - } /* Paranoia check. Due to the connected UDP socket, the kernel has already filtered invalid addresses @@ -1360,15 +1351,24 @@ send_dg(res_state statp, /* Check for the correct header layout and a matching question. */ - if ((recvresp1 || !res_queriesmatch(buf, buf + buflen, - *thisansp, - *thisansp - + *thisanssizp)) - && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2, - *thisansp, - *thisansp - + *thisanssizp))) - goto wait; + int matching_query = 0; /* Default to no matching query. */ + if (!recvresp1 + && anhp->id == hp->id + && res_queriesmatch (buf, buf + buflen, + *thisansp, *thisansp + *thisanssizp)) + matching_query = 1; + if (!recvresp2 + && anhp->id == hp2->id + && res_queriesmatch (buf2, buf2 + buflen2, + *thisansp, *thisansp + *thisanssizp)) + matching_query = 2; + if (matching_query == 0) + /* Spurious UDP packet. Drop it and continue + waiting. */ + { + need_recompute = 1; + goto wait; + } if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || @@ -1383,7 +1383,7 @@ send_dg(res_state statp, /* No data from the first reply. */ resplen = 0; /* We are waiting for a possible second reply. */ - if (hp->id == anhp->id) + if (matching_query == 1) recvresp1 = 1; else recvresp2 = 1; @@ -1414,7 +1414,7 @@ send_dg(res_state statp, return (1); } /* Mark which reply we received. */ - if (recvresp1 == 0 && hp->id == anhp->id) + if (matching_query == 1) recvresp1 = 1; else recvresp2 = 1; diff -pruN glibc-2.32.orig/resolv/tst-resolv-txnid-collision.c glibc-2.32/resolv/tst-resolv-txnid-collision.c --- glibc-2.32.orig/resolv/tst-resolv-txnid-collision.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/resolv/tst-resolv-txnid-collision.c 2021-09-18 21:03:05.312302287 +1000 @@ -0,0 +1,334 @@ +/* Test parallel queries with transaction ID collisions. + Copyright (C) 2020 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 + +/* Result of parsing a DNS question name. + + A question name has the form reorder-N-M-rcode-C.example.net, where + N and M are either 0 and 1, corresponding to the reorder member, + and C is a number that will be stored in the rcode field. + + Also see parse_qname below. */ +struct parsed_qname +{ + /* The DNS response code requested from the first server. The + second server always responds with RCODE zero. */ + int rcode; + + /* Indicates whether to perform reordering in the responses from the + respective server. */ + bool reorder[2]; +}; + +/* Fills *PARSED based on QNAME. */ +static void +parse_qname (struct parsed_qname *parsed, const char *qname) +{ + int reorder0; + int reorder1; + int rcode; + char *suffix; + if (sscanf (qname, "reorder-%d-%d.rcode-%d.%ms", + &reorder0, &reorder1, &rcode, &suffix) == 4) + { + if (reorder0 != 0) + TEST_COMPARE (reorder0, 1); + if (reorder1 != 0) + TEST_COMPARE (reorder1, 1); + TEST_VERIFY (rcode >= 0 && rcode <= 15); + TEST_COMPARE_STRING (suffix, "example.net"); + free (suffix); + + parsed->rcode = rcode; + parsed->reorder[0] = reorder0; + parsed->reorder[1] = reorder1; + } + else + FAIL_EXIT1 ("unexpected query: %s", qname); +} + +/* Used to construct a response. The first server responds with an + error, the second server succeeds. */ +static void +build_response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + struct parsed_qname parsed; + parse_qname (&parsed, qname); + + switch (ctx->server_index) + { + case 0: + { + struct resolv_response_flags flags = { 0 }; + if (parsed.rcode == 0) + /* Simulate a delegation in case a NODATA (RCODE zero) + response is requested. */ + flags.clear_ra = true; + else + flags.rcode = parsed.rcode; + + resolv_response_init (b, flags); + resolv_response_add_question (b, qname, qclass, qtype); + } + break; + + case 1: + { + struct resolv_response_flags flags = { 0, }; + resolv_response_init (b, flags); + resolv_response_add_question (b, qname, qclass, qtype); + + resolv_response_section (b, ns_s_an); + resolv_response_open_record (b, qname, qclass, qtype, 0); + if (qtype == T_A) + { + char ipv4[4] = { 192, 0, 2, 1 }; + resolv_response_add_data (b, &ipv4, sizeof (ipv4)); + } + else + { + char ipv6[16] + = { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + resolv_response_add_data (b, &ipv6, sizeof (ipv6)); + } + resolv_response_close_record (b); + } + break; + } +} + +/* Used to reorder responses. */ +struct resolv_response_context *previous_query; + +/* Used to keep track of the queries received. */ +static int previous_server_index = -1; +static uint16_t previous_qtype; + +/* For each server, buffer the first query and then send both answers + to the second query, reordered if requested. */ +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + TEST_VERIFY (qtype == T_A || qtype == T_AAAA); + if (ctx->server_index != 0) + TEST_COMPARE (ctx->server_index, 1); + + struct parsed_qname parsed; + parse_qname (&parsed, qname); + + if (previous_query == NULL) + { + /* No buffered query. Record this query and do not send a + response. */ + TEST_COMPARE (previous_qtype, 0); + previous_query = resolv_response_context_duplicate (ctx); + previous_qtype = qtype; + resolv_response_drop (b); + previous_server_index = ctx->server_index; + + if (test_verbose) + printf ("info: buffering first query for: %s\n", qname); + } + else + { + TEST_VERIFY (previous_query != 0); + TEST_COMPARE (ctx->server_index, previous_server_index); + TEST_VERIFY (previous_qtype != qtype); /* Not a duplicate. */ + + /* If reordering, send a response for this query explicitly, and + then skip the implicit send. */ + if (parsed.reorder[ctx->server_index]) + { + if (test_verbose) + printf ("info: sending reordered second response for: %s\n", + qname); + build_response (ctx, b, qname, qclass, qtype); + resolv_response_send_udp (ctx, b); + resolv_response_drop (b); + } + + /* Build a response for the previous query and send it, thus + reordering the two responses. */ + { + if (test_verbose) + printf ("info: sending first response for: %s\n", qname); + struct resolv_response_builder *btmp + = resolv_response_builder_allocate (previous_query->query_buffer, + previous_query->query_length); + build_response (ctx, btmp, qname, qclass, previous_qtype); + resolv_response_send_udp (ctx, btmp); + resolv_response_builder_free (btmp); + } + + /* If not reordering, send the reply as usual. */ + if (!parsed.reorder[ctx->server_index]) + { + if (test_verbose) + printf ("info: sending non-reordered second response for: %s\n", + qname); + build_response (ctx, b, qname, qclass, qtype); + } + + /* Unbuffer the response and prepare for the next query. */ + resolv_response_context_free (previous_query); + previous_query = NULL; + previous_qtype = 0; + previous_server_index = -1; + } +} + +/* Runs a query for QNAME and checks for the expected reply. See + struct parsed_qname for the expected format for QNAME. */ +static void +test_qname (const char *qname, int rcode) +{ + struct resolv_context *ctx = __resolv_context_get (); + TEST_VERIFY_EXIT (ctx != NULL); + + unsigned char q1[512]; + int q1len = res_mkquery (QUERY, qname, C_IN, T_A, NULL, 0, NULL, + q1, sizeof (q1)); + TEST_VERIFY_EXIT (q1len > 12); + + unsigned char q2[512]; + int q2len = res_mkquery (QUERY, qname, C_IN, T_AAAA, NULL, 0, NULL, + q2, sizeof (q2)); + TEST_VERIFY_EXIT (q2len > 12); + + /* Produce a transaction ID collision. */ + memcpy (q2, q1, 2); + + unsigned char ans1[512]; + unsigned char *ans1p = ans1; + unsigned char *ans2p = NULL; + int nans2p = 0; + int resplen2 = 0; + int ans2p_malloced = 0; + + /* Perform a parallel A/AAAA query. */ + int resplen1 = __res_context_send (ctx, q1, q1len, q2, q2len, + ans1, sizeof (ans1), &ans1p, + &ans2p, &nans2p, + &resplen2, &ans2p_malloced); + + TEST_VERIFY (resplen1 > 12); + TEST_VERIFY (resplen2 > 12); + if (resplen1 <= 12 || resplen2 <= 12) + return; + + if (rcode == 1 || rcode == 3) + { + /* Format Error and Name Error responses does not trigger + switching to the next server. */ + TEST_COMPARE (ans1p[3] & 0x0f, rcode); + TEST_COMPARE (ans2p[3] & 0x0f, rcode); + return; + } + + /* The response should be successful. */ + TEST_COMPARE (ans1p[3] & 0x0f, 0); + TEST_COMPARE (ans2p[3] & 0x0f, 0); + + /* Due to bug 19691, the answer may not be in the slot matching the + query. Assume that the AAAA response is the longer one. */ + unsigned char *a_answer; + int a_answer_length; + unsigned char *aaaa_answer; + int aaaa_answer_length; + if (resplen2 > resplen1) + { + a_answer = ans1p; + a_answer_length = resplen1; + aaaa_answer = ans2p; + aaaa_answer_length = resplen2; + } + else + { + a_answer = ans2p; + a_answer_length = resplen2; + aaaa_answer = ans1p; + aaaa_answer_length = resplen1; + } + + { + char *expected = xasprintf ("name: %s\n" + "address: 192.0.2.1\n", + qname); + check_dns_packet (qname, a_answer, a_answer_length, expected); + free (expected); + } + { + char *expected = xasprintf ("name: %s\n" + "address: 2001:db8::1\n", + qname); + check_dns_packet (qname, aaaa_answer, aaaa_answer_length, expected); + free (expected); + } + + if (ans2p_malloced) + free (ans2p); + + __resolv_context_put (ctx); +} + +static int +do_test (void) +{ + struct resolv_test *aux = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + + /* The response callback use global state (the previous_* + variables), and query processing must therefore be + serialized. */ + .single_thread_udp = true, + }); + + for (int rcode = 0; rcode <= 5; ++rcode) + for (int do_reorder_0 = 0; do_reorder_0 < 2; ++do_reorder_0) + for (int do_reorder_1 = 0; do_reorder_1 < 2; ++do_reorder_1) + { + char *qname = xasprintf ("reorder-%d-%d.rcode-%d.example.net", + do_reorder_0, do_reorder_1, rcode); + test_qname (qname, rcode); + free (qname); + } + + resolv_test_end (aux); + + return 0; +} + +#include diff -pruN glibc-2.32.orig/Rules glibc-2.32/Rules --- glibc-2.32.orig/Rules 2021-09-18 21:02:32.639182523 +1000 +++ glibc-2.32/Rules 2021-09-18 21:03:05.310302219 +1000 @@ -155,6 +155,7 @@ xtests: tests $(xtests-special) else tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \ $(tests-container:%=$(objpfx)%.out) \ + $(tests-mcheck:%=$(objpfx)%-mcheck.out) \ $(tests-special) $(tests-printers-out) xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special) endif @@ -165,7 +166,7 @@ ifeq ($(run-built-tests),no) tests-expected = else tests-expected = $(tests) $(tests-internal) $(tests-printers) \ - $(tests-container) + $(tests-container) $(tests-mcheck:%=%-mcheck) endif tests: $(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \ @@ -191,6 +192,7 @@ else binaries-pie-tests = binaries-pie-notests = endif +binaries-mcheck-tests = $(tests-mcheck:%=%-mcheck) else binaries-all-notests = binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) @@ -200,6 +202,7 @@ binaries-static-tests = binaries-static = binaries-pie-tests = binaries-pie-notests = +binaries-mcheck-tests = endif binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests) @@ -223,6 +226,14 @@ $(addprefix $(objpfx),$(binaries-shared- $(+link-tests) endif +ifneq "$(strip $(binaries-mcheck-tests))" "" +$(addprefix $(objpfx),$(binaries-mcheck-tests)): %-mcheck: %.o \ + $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-tests) +endif + ifneq "$(strip $(binaries-pie-tests))" "" $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \ $(link-extra-libs-tests) \ @@ -253,6 +264,12 @@ $(addprefix $(objpfx),$(binaries-static- $(+link-static-tests) endif +# All mcheck tests will be run with MALLOC_CHECK_=3 +define mcheck-ENVS +$(1)-mcheck-ENV = MALLOC_CHECK_=3 +endef +$(foreach t,$(tests-mcheck),$(eval $(call mcheck-ENVS,$(t)))) + ifneq "$(strip $(tests) $(tests-internal) $(xtests) $(test-srcs))" "" # These are the implicit rules for making test outputs # from the test programs and whatever input files are present. diff -pruN glibc-2.32.orig/stdio-common/errlist.c glibc-2.32/stdio-common/errlist.c --- glibc-2.32.orig/stdio-common/errlist.c 2021-09-18 21:02:32.698184545 +1000 +++ glibc-2.32/stdio-common/errlist.c 2021-09-18 21:03:05.312302287 +1000 @@ -20,9 +20,13 @@ #include #include +#ifndef ERR_MAP +# define ERR_MAP(n) n +#endif + const char *const _sys_errlist_internal[] = { -#define _S(n, str) [n] = str, +#define _S(n, str) [ERR_MAP(n)] = str, #include #undef _S }; @@ -41,20 +45,21 @@ static const union sys_errname_t { #define MSGSTRFIELD1(line) str##line #define MSGSTRFIELD(line) MSGSTRFIELD1(line) -#define _S(n, str) char MSGSTRFIELD(__LINE__)[sizeof(str)]; +#define _S(n, str) char MSGSTRFIELD(__LINE__)[sizeof(#n)]; #include #undef _S }; char str[0]; } _sys_errname = { { -#define _S(n, s) s, +#define _S(n, s) #n, #include #undef _S } }; static const unsigned short _sys_errnameidx[] = { -#define _S(n, s) [n] = offsetof(union sys_errname_t, MSGSTRFIELD(__LINE__)), +#define _S(n, s) \ + [ERR_MAP(n)] = offsetof(union sys_errname_t, MSGSTRFIELD(__LINE__)), #include #undef _S }; diff -pruN glibc-2.32.orig/stdio-common/Makefile glibc-2.32/stdio-common/Makefile --- glibc-2.32.orig/stdio-common/Makefile 2021-09-18 21:02:32.698184545 +1000 +++ glibc-2.32/stdio-common/Makefile 2021-09-18 21:03:05.312302287 +1000 @@ -69,7 +69,8 @@ tests := tstscanf test_rdwr test-popen t tst-printf-bz25691 \ tst-vfprintf-width-prec-alloc \ tst-printf-fp-free \ - tst-printf-fp-leak + tst-printf-fp-leak \ + test-strerr test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble diff -pruN glibc-2.32.orig/stdio-common/test-strerr.c glibc-2.32/stdio-common/test-strerr.c --- glibc-2.32.orig/stdio-common/test-strerr.c 2021-09-18 21:02:32.698184545 +1000 +++ glibc-2.32/stdio-common/test-strerr.c 2021-09-18 21:03:05.312302287 +1000 @@ -18,46 +18,672 @@ #include #include -#include #include #include -#define N_(name) name - -static const char *const errlist[] = - { -/* This file is auto-generated from errlist.def. */ -#include - }; - -#define MSGSTR_T errname_t -#define MSGSTR errname -#define MSGIDX errnameidx -#include -#undef MSGSTR -#undef MSGIDX - static int do_test (void) { - TEST_VERIFY (strerrordesc_np (-1) == NULL); - TEST_VERIFY (strerrordesc_np (array_length (errlist)) == NULL); - for (size_t i = 0; i < array_length (errlist); i++) - { - if (errlist[i] == NULL) - continue; - TEST_COMPARE_STRING (strerrordesc_np (i), errlist[i]); - } + TEST_COMPARE_STRING (strerrordesc_np (0), "Success"); + TEST_COMPARE_STRING (strerrorname_np (0), "0"); - TEST_VERIFY (strerrorname_np (-1) == NULL); - TEST_VERIFY (strerrorname_np (array_length (errlist)) == NULL); - for (size_t i = 0; i < array_length (errlist); i++) - { - if (errlist[i] == NULL) - continue; - TEST_COMPARE_STRING (strerrorname_np (i), errname.str + errnameidx[i]); - } +#ifdef EPERM + TEST_COMPARE_STRING (strerrordesc_np (EPERM), "Operation not permitted"); + TEST_COMPARE_STRING (strerrorname_np (EPERM), "EPERM"); +#endif +#ifdef ENOENT + TEST_COMPARE_STRING (strerrordesc_np (ENOENT), + "No such file or directory"); + TEST_COMPARE_STRING (strerrorname_np (ENOENT), "ENOENT"); +#endif +#ifdef ESRCH + TEST_COMPARE_STRING (strerrordesc_np (ESRCH), "No such process"); + TEST_COMPARE_STRING (strerrorname_np (ESRCH), "ESRCH"); +#endif +#ifdef EINTR + TEST_COMPARE_STRING (strerrordesc_np (EINTR), "Interrupted system call"); + TEST_COMPARE_STRING (strerrorname_np (EINTR), "EINTR"); +#endif +#ifdef EIO + TEST_COMPARE_STRING (strerrordesc_np (EIO), "Input/output error"); + TEST_COMPARE_STRING (strerrorname_np (EIO), "EIO"); +#endif +#ifdef ENXIO + TEST_COMPARE_STRING (strerrordesc_np (ENXIO), "No such device or address"); + TEST_COMPARE_STRING (strerrorname_np (ENXIO), "ENXIO"); +#endif +#ifdef E2BIG + TEST_COMPARE_STRING (strerrordesc_np (E2BIG), "Argument list too long"); + TEST_COMPARE_STRING (strerrorname_np (E2BIG), "E2BIG"); +#endif +#ifdef ENOEXEC + TEST_COMPARE_STRING (strerrordesc_np (ENOEXEC), "Exec format error"); + TEST_COMPARE_STRING (strerrorname_np (ENOEXEC), "ENOEXEC"); +#endif +#ifdef EBADF + TEST_COMPARE_STRING (strerrordesc_np (EBADF), "Bad file descriptor"); + TEST_COMPARE_STRING (strerrorname_np (EBADF), "EBADF"); +#endif +#ifdef ECHILD + TEST_COMPARE_STRING (strerrordesc_np (ECHILD), "No child processes"); + TEST_COMPARE_STRING (strerrorname_np (ECHILD), "ECHILD"); +#endif +#ifdef EDEADLK + TEST_COMPARE_STRING (strerrordesc_np (EDEADLK), + "Resource deadlock avoided"); + TEST_COMPARE_STRING (strerrorname_np (EDEADLK), "EDEADLK"); +#endif +#ifdef ENOMEM + TEST_COMPARE_STRING (strerrordesc_np (ENOMEM), "Cannot allocate memory"); + TEST_COMPARE_STRING (strerrorname_np (ENOMEM), "ENOMEM"); +#endif +#ifdef EACCES + TEST_COMPARE_STRING (strerrordesc_np (EACCES), "Permission denied"); + TEST_COMPARE_STRING (strerrorname_np (EACCES), "EACCES"); +#endif +#ifdef EFAULT + TEST_COMPARE_STRING (strerrordesc_np (EFAULT), "Bad address"); + TEST_COMPARE_STRING (strerrorname_np (EFAULT), "EFAULT"); +#endif +#ifdef ENOTBLK + TEST_COMPARE_STRING (strerrordesc_np (ENOTBLK), "Block device required"); + TEST_COMPARE_STRING (strerrorname_np (ENOTBLK), "ENOTBLK"); +#endif +#ifdef EBUSY + TEST_COMPARE_STRING (strerrordesc_np (EBUSY), "Device or resource busy"); + TEST_COMPARE_STRING (strerrorname_np (EBUSY), "EBUSY"); +#endif +#ifdef EEXIST + TEST_COMPARE_STRING (strerrordesc_np (EEXIST), "File exists"); + TEST_COMPARE_STRING (strerrorname_np (EEXIST), "EEXIST"); +#endif +#ifdef EXDEV + TEST_COMPARE_STRING (strerrordesc_np (EXDEV), "Invalid cross-device link"); + TEST_COMPARE_STRING (strerrorname_np (EXDEV), "EXDEV"); +#endif +#ifdef ENODEV + TEST_COMPARE_STRING (strerrordesc_np (ENODEV), "No such device"); + TEST_COMPARE_STRING (strerrorname_np (ENODEV), "ENODEV"); +#endif +#ifdef ENOTDIR + TEST_COMPARE_STRING (strerrordesc_np (ENOTDIR), "Not a directory"); + TEST_COMPARE_STRING (strerrorname_np (ENOTDIR), "ENOTDIR"); +#endif +#ifdef EISDIR + TEST_COMPARE_STRING (strerrordesc_np (EISDIR), "Is a directory"); + TEST_COMPARE_STRING (strerrorname_np (EISDIR), "EISDIR"); +#endif +#ifdef EINVAL + TEST_COMPARE_STRING (strerrordesc_np (EINVAL), "Invalid argument"); + TEST_COMPARE_STRING (strerrorname_np (EINVAL), "EINVAL"); +#endif +#ifdef EMFILE + TEST_COMPARE_STRING (strerrordesc_np (EMFILE), "Too many open files"); + TEST_COMPARE_STRING (strerrorname_np (EMFILE), "EMFILE"); +#endif +#ifdef ENFILE + TEST_COMPARE_STRING (strerrordesc_np (ENFILE), + "Too many open files in system"); + TEST_COMPARE_STRING (strerrorname_np (ENFILE), "ENFILE"); +#endif +#ifdef ENOTTY + TEST_COMPARE_STRING (strerrordesc_np (ENOTTY), + "Inappropriate ioctl for device"); + TEST_COMPARE_STRING (strerrorname_np (ENOTTY), "ENOTTY"); +#endif +#ifdef ETXTBSY + TEST_COMPARE_STRING (strerrordesc_np (ETXTBSY), "Text file busy"); + TEST_COMPARE_STRING (strerrorname_np (ETXTBSY), "ETXTBSY"); +#endif +#ifdef EFBIG + TEST_COMPARE_STRING (strerrordesc_np (EFBIG), "File too large"); + TEST_COMPARE_STRING (strerrorname_np (EFBIG), "EFBIG"); +#endif +#ifdef ENOSPC + TEST_COMPARE_STRING (strerrordesc_np (ENOSPC), "No space left on device"); + TEST_COMPARE_STRING (strerrorname_np (ENOSPC), "ENOSPC"); +#endif +#ifdef ESPIPE + TEST_COMPARE_STRING (strerrordesc_np (ESPIPE), "Illegal seek"); + TEST_COMPARE_STRING (strerrorname_np (ESPIPE), "ESPIPE"); +#endif +#ifdef EROFS + TEST_COMPARE_STRING (strerrordesc_np (EROFS), "Read-only file system"); + TEST_COMPARE_STRING (strerrorname_np (EROFS), "EROFS"); +#endif +#ifdef EMLINK + TEST_COMPARE_STRING (strerrordesc_np (EMLINK), "Too many links"); + TEST_COMPARE_STRING (strerrorname_np (EMLINK), "EMLINK"); +#endif +#ifdef EPIPE + TEST_COMPARE_STRING (strerrordesc_np (EPIPE), "Broken pipe"); + TEST_COMPARE_STRING (strerrorname_np (EPIPE), "EPIPE"); +#endif +#ifdef EDOM + TEST_COMPARE_STRING (strerrordesc_np (EDOM), + "Numerical argument out of domain"); + TEST_COMPARE_STRING (strerrorname_np (EDOM), "EDOM"); +#endif +#ifdef ERANGE + TEST_COMPARE_STRING (strerrordesc_np (ERANGE), + "Numerical result out of range"); + TEST_COMPARE_STRING (strerrorname_np (ERANGE), "ERANGE"); +#endif +#ifdef EAGAIN + TEST_COMPARE_STRING (strerrordesc_np (EAGAIN), + "Resource temporarily unavailable"); + TEST_COMPARE_STRING (strerrorname_np (EAGAIN), "EAGAIN"); +#endif +#ifdef EINPROGRESS + TEST_COMPARE_STRING (strerrordesc_np (EINPROGRESS), + "Operation now in progress"); + TEST_COMPARE_STRING (strerrorname_np (EINPROGRESS), "EINPROGRESS"); +#endif +#ifdef EALREADY + TEST_COMPARE_STRING (strerrordesc_np (EALREADY), + "Operation already in progress"); + TEST_COMPARE_STRING (strerrorname_np (EALREADY), "EALREADY"); +#endif +#ifdef ENOTSOCK + TEST_COMPARE_STRING (strerrordesc_np (ENOTSOCK), + "Socket operation on non-socket"); + TEST_COMPARE_STRING (strerrorname_np (ENOTSOCK), "ENOTSOCK"); +#endif +#ifdef EMSGSIZE + TEST_COMPARE_STRING (strerrordesc_np (EMSGSIZE), "Message too long"); + TEST_COMPARE_STRING (strerrorname_np (EMSGSIZE), "EMSGSIZE"); +#endif +#ifdef EPROTOTYPE + TEST_COMPARE_STRING (strerrordesc_np (EPROTOTYPE), + "Protocol wrong type for socket"); + TEST_COMPARE_STRING (strerrorname_np (EPROTOTYPE), "EPROTOTYPE"); +#endif +#ifdef ENOPROTOOPT + TEST_COMPARE_STRING (strerrordesc_np (ENOPROTOOPT), + "Protocol not available"); + TEST_COMPARE_STRING (strerrorname_np (ENOPROTOOPT), "ENOPROTOOPT"); +#endif +#ifdef EPROTONOSUPPORT + TEST_COMPARE_STRING (strerrordesc_np (EPROTONOSUPPORT), + "Protocol not supported"); + TEST_COMPARE_STRING (strerrorname_np (EPROTONOSUPPORT), "EPROTONOSUPPORT"); +#endif +#ifdef ESOCKTNOSUPPORT + TEST_COMPARE_STRING (strerrordesc_np (ESOCKTNOSUPPORT), + "Socket type not supported"); + TEST_COMPARE_STRING (strerrorname_np (ESOCKTNOSUPPORT), "ESOCKTNOSUPPORT"); +#endif +#ifdef EOPNOTSUPP + TEST_COMPARE_STRING (strerrordesc_np (EOPNOTSUPP), + "Operation not supported"); + TEST_COMPARE_STRING (strerrorname_np (EOPNOTSUPP), "EOPNOTSUPP"); +#endif +#ifdef EPFNOSUPPORT + TEST_COMPARE_STRING (strerrordesc_np (EPFNOSUPPORT), + "Protocol family not supported"); + TEST_COMPARE_STRING (strerrorname_np (EPFNOSUPPORT), "EPFNOSUPPORT"); +#endif +#ifdef EAFNOSUPPORT + TEST_COMPARE_STRING (strerrordesc_np (EAFNOSUPPORT), + "Address family not supported by protocol"); + TEST_COMPARE_STRING (strerrorname_np (EAFNOSUPPORT), "EAFNOSUPPORT"); +#endif +#ifdef EADDRINUSE + TEST_COMPARE_STRING (strerrordesc_np (EADDRINUSE), + "Address already in use"); + TEST_COMPARE_STRING (strerrorname_np (EADDRINUSE), "EADDRINUSE"); +#endif +#ifdef EADDRNOTAVAIL + TEST_COMPARE_STRING (strerrordesc_np (EADDRNOTAVAIL), + "Cannot assign requested address"); + TEST_COMPARE_STRING (strerrorname_np (EADDRNOTAVAIL), "EADDRNOTAVAIL"); +#endif +#ifdef ENETDOWN + TEST_COMPARE_STRING (strerrordesc_np (ENETDOWN), "Network is down"); + TEST_COMPARE_STRING (strerrorname_np (ENETDOWN), "ENETDOWN"); +#endif +#ifdef ENETUNREACH + TEST_COMPARE_STRING (strerrordesc_np (ENETUNREACH), + "Network is unreachable"); + TEST_COMPARE_STRING (strerrorname_np (ENETUNREACH), "ENETUNREACH"); +#endif +#ifdef ENETRESET + TEST_COMPARE_STRING (strerrordesc_np (ENETRESET), + "Network dropped connection on reset"); + TEST_COMPARE_STRING (strerrorname_np (ENETRESET), "ENETRESET"); +#endif +#ifdef ECONNABORTED + TEST_COMPARE_STRING (strerrordesc_np (ECONNABORTED), + "Software caused connection abort"); + TEST_COMPARE_STRING (strerrorname_np (ECONNABORTED), "ECONNABORTED"); +#endif +#ifdef ECONNRESET + TEST_COMPARE_STRING (strerrordesc_np (ECONNRESET), + "Connection reset by peer"); + TEST_COMPARE_STRING (strerrorname_np (ECONNRESET), "ECONNRESET"); +#endif +#ifdef ENOBUFS + TEST_COMPARE_STRING (strerrordesc_np (ENOBUFS), + "No buffer space available"); + TEST_COMPARE_STRING (strerrorname_np (ENOBUFS), "ENOBUFS"); +#endif +#ifdef EISCONN + TEST_COMPARE_STRING (strerrordesc_np (EISCONN), + "Transport endpoint is already connected"); + TEST_COMPARE_STRING (strerrorname_np (EISCONN), "EISCONN"); +#endif +#ifdef ENOTCONN + TEST_COMPARE_STRING (strerrordesc_np (ENOTCONN), + "Transport endpoint is not connected"); + TEST_COMPARE_STRING (strerrorname_np (ENOTCONN), "ENOTCONN"); +#endif +#ifdef EDESTADDRREQ + TEST_COMPARE_STRING (strerrordesc_np (EDESTADDRREQ), + "Destination address required"); + TEST_COMPARE_STRING (strerrorname_np (EDESTADDRREQ), "EDESTADDRREQ"); +#endif +#ifdef ESHUTDOWN + TEST_COMPARE_STRING (strerrordesc_np (ESHUTDOWN), + "Cannot send after transport endpoint shutdown"); + TEST_COMPARE_STRING (strerrorname_np (ESHUTDOWN), "ESHUTDOWN"); +#endif +#ifdef ETOOMANYREFS + TEST_COMPARE_STRING (strerrordesc_np (ETOOMANYREFS), + "Too many references: cannot splice"); + TEST_COMPARE_STRING (strerrorname_np (ETOOMANYREFS), "ETOOMANYREFS"); +#endif +#ifdef ETIMEDOUT + TEST_COMPARE_STRING (strerrordesc_np (ETIMEDOUT), "Connection timed out"); + TEST_COMPARE_STRING (strerrorname_np (ETIMEDOUT), "ETIMEDOUT"); +#endif +#ifdef ECONNREFUSED + TEST_COMPARE_STRING (strerrordesc_np (ECONNREFUSED), "Connection refused"); + TEST_COMPARE_STRING (strerrorname_np (ECONNREFUSED), "ECONNREFUSED"); +#endif +#ifdef ELOOP + TEST_COMPARE_STRING (strerrordesc_np (ELOOP), + "Too many levels of symbolic links"); + TEST_COMPARE_STRING (strerrorname_np (ELOOP), "ELOOP"); +#endif +#ifdef ENAMETOOLONG + TEST_COMPARE_STRING (strerrordesc_np (ENAMETOOLONG), "File name too long"); + TEST_COMPARE_STRING (strerrorname_np (ENAMETOOLONG), "ENAMETOOLONG"); +#endif +#ifdef EHOSTDOWN + TEST_COMPARE_STRING (strerrordesc_np (EHOSTDOWN), "Host is down"); + TEST_COMPARE_STRING (strerrorname_np (EHOSTDOWN), "EHOSTDOWN"); +#endif +#ifdef EHOSTUNREACH + TEST_COMPARE_STRING (strerrordesc_np (EHOSTUNREACH), "No route to host"); + TEST_COMPARE_STRING (strerrorname_np (EHOSTUNREACH), "EHOSTUNREACH"); +#endif +#ifdef ENOTEMPTY + TEST_COMPARE_STRING (strerrordesc_np (ENOTEMPTY), "Directory not empty"); + TEST_COMPARE_STRING (strerrorname_np (ENOTEMPTY), "ENOTEMPTY"); +#endif +#ifdef EUSERS + TEST_COMPARE_STRING (strerrordesc_np (EUSERS), "Too many users"); + TEST_COMPARE_STRING (strerrorname_np (EUSERS), "EUSERS"); +#endif +#ifdef EDQUOT + TEST_COMPARE_STRING (strerrordesc_np (EDQUOT), "Disk quota exceeded"); + TEST_COMPARE_STRING (strerrorname_np (EDQUOT), "EDQUOT"); +#endif +#ifdef ESTALE + TEST_COMPARE_STRING (strerrordesc_np (ESTALE), "Stale file handle"); + TEST_COMPARE_STRING (strerrorname_np (ESTALE), "ESTALE"); +#endif +#ifdef EREMOTE + TEST_COMPARE_STRING (strerrordesc_np (EREMOTE), "Object is remote"); + TEST_COMPARE_STRING (strerrorname_np (EREMOTE), "EREMOTE"); +#endif +#ifdef ENOLCK + TEST_COMPARE_STRING (strerrordesc_np (ENOLCK), "No locks available"); + TEST_COMPARE_STRING (strerrorname_np (ENOLCK), "ENOLCK"); +#endif +#ifdef ENOSYS + TEST_COMPARE_STRING (strerrordesc_np (ENOSYS), "Function not implemented"); + TEST_COMPARE_STRING (strerrorname_np (ENOSYS), "ENOSYS"); +#endif +#ifdef EILSEQ + TEST_COMPARE_STRING (strerrordesc_np (EILSEQ), + "Invalid or incomplete multibyte or wide character"); + TEST_COMPARE_STRING (strerrorname_np (EILSEQ), "EILSEQ"); +#endif +#ifdef EBADMSG + TEST_COMPARE_STRING (strerrordesc_np (EBADMSG), "Bad message"); + TEST_COMPARE_STRING (strerrorname_np (EBADMSG), "EBADMSG"); +#endif +#ifdef EIDRM + TEST_COMPARE_STRING (strerrordesc_np (EIDRM), "Identifier removed"); + TEST_COMPARE_STRING (strerrorname_np (EIDRM), "EIDRM"); +#endif +#ifdef EMULTIHOP + TEST_COMPARE_STRING (strerrordesc_np (EMULTIHOP), "Multihop attempted"); + TEST_COMPARE_STRING (strerrorname_np (EMULTIHOP), "EMULTIHOP"); +#endif +#ifdef ENODATA + TEST_COMPARE_STRING (strerrordesc_np (ENODATA), "No data available"); + TEST_COMPARE_STRING (strerrorname_np (ENODATA), "ENODATA"); +#endif +#ifdef ENOLINK + TEST_COMPARE_STRING (strerrordesc_np (ENOLINK), "Link has been severed"); + TEST_COMPARE_STRING (strerrorname_np (ENOLINK), "ENOLINK"); +#endif +#ifdef ENOMSG + TEST_COMPARE_STRING (strerrordesc_np (ENOMSG), + "No message of desired type"); + TEST_COMPARE_STRING (strerrorname_np (ENOMSG), "ENOMSG"); +#endif +#ifdef ENOSR + TEST_COMPARE_STRING (strerrordesc_np (ENOSR), "Out of streams resources"); + TEST_COMPARE_STRING (strerrorname_np (ENOSR), "ENOSR"); +#endif +#ifdef ENOSTR + TEST_COMPARE_STRING (strerrordesc_np (ENOSTR), "Device not a stream"); + TEST_COMPARE_STRING (strerrorname_np (ENOSTR), "ENOSTR"); +#endif +#ifdef EOVERFLOW + TEST_COMPARE_STRING (strerrordesc_np (EOVERFLOW), + "Value too large for defined data type"); + TEST_COMPARE_STRING (strerrorname_np (EOVERFLOW), "EOVERFLOW"); +#endif +#ifdef EPROTO + TEST_COMPARE_STRING (strerrordesc_np (EPROTO), "Protocol error"); + TEST_COMPARE_STRING (strerrorname_np (EPROTO), "EPROTO"); +#endif +#ifdef ETIME + TEST_COMPARE_STRING (strerrordesc_np (ETIME), "Timer expired"); + TEST_COMPARE_STRING (strerrorname_np (ETIME), "ETIME"); +#endif +#ifdef ECANCELED + TEST_COMPARE_STRING (strerrordesc_np (ECANCELED), "Operation canceled"); + TEST_COMPARE_STRING (strerrorname_np (ECANCELED), "ECANCELED"); +#endif +#ifdef EOWNERDEAD + TEST_COMPARE_STRING (strerrordesc_np (EOWNERDEAD), "Owner died"); + TEST_COMPARE_STRING (strerrorname_np (EOWNERDEAD), "EOWNERDEAD"); +#endif +#ifdef ENOTRECOVERABLE + TEST_COMPARE_STRING (strerrordesc_np (ENOTRECOVERABLE), + "State not recoverable"); + TEST_COMPARE_STRING (strerrorname_np (ENOTRECOVERABLE), "ENOTRECOVERABLE"); +#endif +#ifdef ERESTART + TEST_COMPARE_STRING (strerrordesc_np (ERESTART), + "Interrupted system call should be restarted"); + TEST_COMPARE_STRING (strerrorname_np (ERESTART), "ERESTART"); +#endif +#ifdef ECHRNG + TEST_COMPARE_STRING (strerrordesc_np (ECHRNG), + "Channel number out of range"); + TEST_COMPARE_STRING (strerrorname_np (ECHRNG), "ECHRNG"); +#endif +#ifdef EL2NSYNC + TEST_COMPARE_STRING (strerrordesc_np (EL2NSYNC), + "Level 2 not synchronized"); + TEST_COMPARE_STRING (strerrorname_np (EL2NSYNC), "EL2NSYNC"); +#endif +#ifdef EL3HLT + TEST_COMPARE_STRING (strerrordesc_np (EL3HLT), "Level 3 halted"); + TEST_COMPARE_STRING (strerrorname_np (EL3HLT), "EL3HLT"); +#endif +#ifdef EL3RST + TEST_COMPARE_STRING (strerrordesc_np (EL3RST), "Level 3 reset"); + TEST_COMPARE_STRING (strerrorname_np (EL3RST), "EL3RST"); +#endif +#ifdef ELNRNG + TEST_COMPARE_STRING (strerrordesc_np (ELNRNG), "Link number out of range"); + TEST_COMPARE_STRING (strerrorname_np (ELNRNG), "ELNRNG"); +#endif +#ifdef EUNATCH + TEST_COMPARE_STRING (strerrordesc_np (EUNATCH), + "Protocol driver not attached"); + TEST_COMPARE_STRING (strerrorname_np (EUNATCH), "EUNATCH"); +#endif +#ifdef ENOCSI + TEST_COMPARE_STRING (strerrordesc_np (ENOCSI), + "No CSI structure available"); + TEST_COMPARE_STRING (strerrorname_np (ENOCSI), "ENOCSI"); +#endif +#ifdef EL2HLT + TEST_COMPARE_STRING (strerrordesc_np (EL2HLT), "Level 2 halted"); + TEST_COMPARE_STRING (strerrorname_np (EL2HLT), "EL2HLT"); +#endif +#ifdef EBADE + TEST_COMPARE_STRING (strerrordesc_np (EBADE), "Invalid exchange"); + TEST_COMPARE_STRING (strerrorname_np (EBADE), "EBADE"); +#endif +#ifdef EBADR + TEST_COMPARE_STRING (strerrordesc_np (EBADR), + "Invalid request descriptor"); + TEST_COMPARE_STRING (strerrorname_np (EBADR), "EBADR"); +#endif +#ifdef EXFULL + TEST_COMPARE_STRING (strerrordesc_np (EXFULL), "Exchange full"); + TEST_COMPARE_STRING (strerrorname_np (EXFULL), "EXFULL"); +#endif +#ifdef ENOANO + TEST_COMPARE_STRING (strerrordesc_np (ENOANO), "No anode"); + TEST_COMPARE_STRING (strerrorname_np (ENOANO), "ENOANO"); +#endif +#ifdef EBADRQC + TEST_COMPARE_STRING (strerrordesc_np (EBADRQC), "Invalid request code"); + TEST_COMPARE_STRING (strerrorname_np (EBADRQC), "EBADRQC"); +#endif +#ifdef EBADSLT + TEST_COMPARE_STRING (strerrordesc_np (EBADSLT), "Invalid slot"); + TEST_COMPARE_STRING (strerrorname_np (EBADSLT), "EBADSLT"); +#endif +#ifdef EBFONT + TEST_COMPARE_STRING (strerrordesc_np (EBFONT), "Bad font file format"); + TEST_COMPARE_STRING (strerrorname_np (EBFONT), "EBFONT"); +#endif +#ifdef ENONET + TEST_COMPARE_STRING (strerrordesc_np (ENONET), + "Machine is not on the network"); + TEST_COMPARE_STRING (strerrorname_np (ENONET), "ENONET"); +#endif +#ifdef ENOPKG + TEST_COMPARE_STRING (strerrordesc_np (ENOPKG), "Package not installed"); + TEST_COMPARE_STRING (strerrorname_np (ENOPKG), "ENOPKG"); +#endif +#ifdef EADV + TEST_COMPARE_STRING (strerrordesc_np (EADV), "Advertise error"); + TEST_COMPARE_STRING (strerrorname_np (EADV), "EADV"); +#endif +#ifdef ESRMNT + TEST_COMPARE_STRING (strerrordesc_np (ESRMNT), "Srmount error"); + TEST_COMPARE_STRING (strerrorname_np (ESRMNT), "ESRMNT"); +#endif +#ifdef ECOMM + TEST_COMPARE_STRING (strerrordesc_np (ECOMM), + "Communication error on send"); + TEST_COMPARE_STRING (strerrorname_np (ECOMM), "ECOMM"); +#endif +#ifdef EDOTDOT + TEST_COMPARE_STRING (strerrordesc_np (EDOTDOT), "RFS specific error"); + TEST_COMPARE_STRING (strerrorname_np (EDOTDOT), "EDOTDOT"); +#endif +#ifdef ENOTUNIQ + TEST_COMPARE_STRING (strerrordesc_np (ENOTUNIQ), + "Name not unique on network"); + TEST_COMPARE_STRING (strerrorname_np (ENOTUNIQ), "ENOTUNIQ"); +#endif +#ifdef EBADFD + TEST_COMPARE_STRING (strerrordesc_np (EBADFD), + "File descriptor in bad state"); + TEST_COMPARE_STRING (strerrorname_np (EBADFD), "EBADFD"); +#endif +#ifdef EREMCHG + TEST_COMPARE_STRING (strerrordesc_np (EREMCHG), "Remote address changed"); + TEST_COMPARE_STRING (strerrorname_np (EREMCHG), "EREMCHG"); +#endif +#ifdef ELIBACC + TEST_COMPARE_STRING (strerrordesc_np (ELIBACC), + "Can not access a needed shared library"); + TEST_COMPARE_STRING (strerrorname_np (ELIBACC), "ELIBACC"); +#endif +#ifdef ELIBBAD + TEST_COMPARE_STRING (strerrordesc_np (ELIBBAD), + "Accessing a corrupted shared library"); + TEST_COMPARE_STRING (strerrorname_np (ELIBBAD), "ELIBBAD"); +#endif +#ifdef ELIBSCN + TEST_COMPARE_STRING (strerrordesc_np (ELIBSCN), + ".lib section in a.out corrupted"); + TEST_COMPARE_STRING (strerrorname_np (ELIBSCN), "ELIBSCN"); +#endif +#ifdef ELIBMAX + TEST_COMPARE_STRING (strerrordesc_np (ELIBMAX), + "Attempting to link in too many shared libraries"); + TEST_COMPARE_STRING (strerrorname_np (ELIBMAX), "ELIBMAX"); +#endif +#ifdef ELIBEXEC + TEST_COMPARE_STRING (strerrordesc_np (ELIBEXEC), + "Cannot exec a shared library directly"); + TEST_COMPARE_STRING (strerrorname_np (ELIBEXEC), "ELIBEXEC"); +#endif +#ifdef ESTRPIPE + TEST_COMPARE_STRING (strerrordesc_np (ESTRPIPE), "Streams pipe error"); + TEST_COMPARE_STRING (strerrorname_np (ESTRPIPE), "ESTRPIPE"); +#endif +#ifdef EUCLEAN + TEST_COMPARE_STRING (strerrordesc_np (EUCLEAN), + "Structure needs cleaning"); + TEST_COMPARE_STRING (strerrorname_np (EUCLEAN), "EUCLEAN"); +#endif +#ifdef ENOTNAM + TEST_COMPARE_STRING (strerrordesc_np (ENOTNAM), + "Not a XENIX named type file"); + TEST_COMPARE_STRING (strerrorname_np (ENOTNAM), "ENOTNAM"); +#endif +#ifdef ENAVAIL + TEST_COMPARE_STRING (strerrordesc_np (ENAVAIL), + "No XENIX semaphores available"); + TEST_COMPARE_STRING (strerrorname_np (ENAVAIL), "ENAVAIL"); +#endif +#ifdef EISNAM + TEST_COMPARE_STRING (strerrordesc_np (EISNAM), "Is a named type file"); + TEST_COMPARE_STRING (strerrorname_np (EISNAM), "EISNAM"); +#endif +#ifdef EREMOTEIO + TEST_COMPARE_STRING (strerrordesc_np (EREMOTEIO), "Remote I/O error"); + TEST_COMPARE_STRING (strerrorname_np (EREMOTEIO), "EREMOTEIO"); +#endif +#ifdef ENOMEDIUM + TEST_COMPARE_STRING (strerrordesc_np (ENOMEDIUM), "No medium found"); + TEST_COMPARE_STRING (strerrorname_np (ENOMEDIUM), "ENOMEDIUM"); +#endif +#ifdef EMEDIUMTYPE + TEST_COMPARE_STRING (strerrordesc_np (EMEDIUMTYPE), "Wrong medium type"); + TEST_COMPARE_STRING (strerrorname_np (EMEDIUMTYPE), "EMEDIUMTYPE"); +#endif +#ifdef ENOKEY + TEST_COMPARE_STRING (strerrordesc_np (ENOKEY), + "Required key not available"); + TEST_COMPARE_STRING (strerrorname_np (ENOKEY), "ENOKEY"); +#endif +#ifdef EKEYEXPIRED + TEST_COMPARE_STRING (strerrordesc_np (EKEYEXPIRED), "Key has expired"); + TEST_COMPARE_STRING (strerrorname_np (EKEYEXPIRED), "EKEYEXPIRED"); +#endif +#ifdef EKEYREVOKED + TEST_COMPARE_STRING (strerrordesc_np (EKEYREVOKED), + "Key has been revoked"); + TEST_COMPARE_STRING (strerrorname_np (EKEYREVOKED), "EKEYREVOKED"); +#endif +#ifdef EKEYREJECTED + TEST_COMPARE_STRING (strerrordesc_np (EKEYREJECTED), + "Key was rejected by service"); + TEST_COMPARE_STRING (strerrorname_np (EKEYREJECTED), "EKEYREJECTED"); +#endif +#ifdef ERFKILL + TEST_COMPARE_STRING (strerrordesc_np (ERFKILL), + "Operation not possible due to RF-kill"); + TEST_COMPARE_STRING (strerrorname_np (ERFKILL), "ERFKILL"); +#endif +#ifdef EHWPOISON + TEST_COMPARE_STRING (strerrordesc_np (EHWPOISON), + "Memory page has hardware error"); + TEST_COMPARE_STRING (strerrorname_np (EHWPOISON), "EHWPOISON"); +#endif +#ifdef EBADRPC + TEST_COMPARE_STRING (strerrordesc_np (EBADRPC), "RPC struct is bad"); + TEST_COMPARE_STRING (strerrorname_np (EBADRPC), "EBADRPC"); +#endif +#ifdef EFTYPE + TEST_COMPARE_STRING (strerrordesc_np (EFTYPE), + "Inappropriate file type or format"); + TEST_COMPARE_STRING (strerrorname_np (EFTYPE), "EFTYPE"); +#endif +#ifdef EPROCUNAVAIL + TEST_COMPARE_STRING (strerrordesc_np (EPROCUNAVAIL), + "RPC bad procedure for program"); + TEST_COMPARE_STRING (strerrorname_np (EPROCUNAVAIL), "EPROCUNAVAIL"); +#endif +#ifdef EAUTH + TEST_COMPARE_STRING (strerrordesc_np (EAUTH), "Authentication error"); + TEST_COMPARE_STRING (strerrorname_np (EAUTH), "EAUTH"); +#endif +#ifdef EDIED + TEST_COMPARE_STRING (strerrordesc_np (EDIED), "Translator died"); + TEST_COMPARE_STRING (strerrorname_np (EDIED), "EDIED"); +#endif +#ifdef ERPCMISMATCH + TEST_COMPARE_STRING (strerrordesc_np (ERPCMISMATCH), "RPC version wrong"); + TEST_COMPARE_STRING (strerrorname_np (ERPCMISMATCH), "ERPCMISMATCH"); +#endif +#ifdef EGREGIOUS + TEST_COMPARE_STRING (strerrordesc_np (EGREGIOUS), + "You really blew it this time"); + TEST_COMPARE_STRING (strerrorname_np (EGREGIOUS), "EGREGIOUS"); +#endif +#ifdef EPROCLIM + TEST_COMPARE_STRING (strerrordesc_np (EPROCLIM), "Too many processes"); + TEST_COMPARE_STRING (strerrorname_np (EPROCLIM), "EPROCLIM"); +#endif +#ifdef EGRATUITOUS + TEST_COMPARE_STRING (strerrordesc_np (EGRATUITOUS), "Gratuitous error"); + TEST_COMPARE_STRING (strerrorname_np (EGRATUITOUS), "EGRATUITOUS"); +#endif +#if defined (ENOTSUP) && ENOTSUP != EOPNOTSUPP + TEST_COMPARE_STRING (strerrordesc_np (ENOTSUP), "Not supported"); + TEST_COMPARE_STRING (strerrorname_np (ENOTSUP), "ENOTSUP"); +#endif +#ifdef EPROGMISMATCH + TEST_COMPARE_STRING (strerrordesc_np (EPROGMISMATCH), + "RPC program version wrong"); + TEST_COMPARE_STRING (strerrorname_np (EPROGMISMATCH), "EPROGMISMATCH"); +#endif +#ifdef EBACKGROUND + TEST_COMPARE_STRING (strerrordesc_np (EBACKGROUND), + "Inappropriate operation for background process"); + TEST_COMPARE_STRING (strerrorname_np (EBACKGROUND), "EBACKGROUND"); +#endif +#ifdef EIEIO + TEST_COMPARE_STRING (strerrordesc_np (EIEIO), "Computer bought the farm"); + TEST_COMPARE_STRING (strerrorname_np (EIEIO), "EIEIO"); +#endif +#if defined (EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + TEST_COMPARE_STRING (strerrordesc_np (EWOULDBLOCK), + "Operation would block"); + TEST_COMPARE_STRING (strerrorname_np (EWOULDBLOCK), "EWOULDBLOCK"); +#endif +#ifdef ENEEDAUTH + TEST_COMPARE_STRING (strerrordesc_np (ENEEDAUTH), "Need authenticator"); + TEST_COMPARE_STRING (strerrorname_np (ENEEDAUTH), "ENEEDAUTH"); +#endif +#ifdef ED + TEST_COMPARE_STRING (strerrordesc_np (ED), "?"); + TEST_COMPARE_STRING (strerrorname_np (ED), "ED"); +#endif +#ifdef EPROGUNAVAIL + TEST_COMPARE_STRING (strerrordesc_np (EPROGUNAVAIL), + "RPC program not available"); + TEST_COMPARE_STRING (strerrorname_np (EPROGUNAVAIL), "EPROGUNAVAIL"); +#endif return 0; } diff -pruN glibc-2.32.orig/stdio-common/vfscanf-internal.c glibc-2.32/stdio-common/vfscanf-internal.c --- glibc-2.32.orig/stdio-common/vfscanf-internal.c 2021-09-18 21:02:32.699184579 +1000 +++ glibc-2.32/stdio-common/vfscanf-internal.c 2021-09-18 21:03:05.312302287 +1000 @@ -277,7 +277,7 @@ __vfscanf_internal (FILE *s, const char #endif { va_list arg; - const CHAR_T *f = format; + const UCHAR_T *f = (const UCHAR_T *) format; UCHAR_T fc; /* Current character of the format. */ WINT_T done = 0; /* Assignments done. */ size_t read_in = 0; /* Chars read in. */ @@ -415,10 +415,11 @@ __vfscanf_internal (FILE *s, const char #endif #ifndef COMPILE_WSCANF - if (!isascii ((unsigned char) *f)) + if (!isascii (*f)) { /* Non-ASCII, may be a multibyte. */ - int len = __mbrlen (f, strlen (f), &state); + int len = __mbrlen ((const char *) f, strlen ((const char *) f), + &state); if (len > 0) { do @@ -426,7 +427,7 @@ __vfscanf_internal (FILE *s, const char c = inchar (); if (__glibc_unlikely (c == EOF)) input_error (); - else if (c != (unsigned char) *f++) + else if (c != *f++) { ungetc_not_eof (c, s); conv_error (); @@ -484,9 +485,9 @@ __vfscanf_internal (FILE *s, const char char_buffer_rewind (&charbuf); /* Check for a positional parameter specification. */ - if (ISDIGIT ((UCHAR_T) *f)) + if (ISDIGIT (*f)) { - argpos = read_int ((const UCHAR_T **) &f); + argpos = read_int (&f); if (*f == L_('$')) ++f; else @@ -521,8 +522,8 @@ __vfscanf_internal (FILE *s, const char /* Find the maximum field width. */ width = 0; - if (ISDIGIT ((UCHAR_T) *f)) - width = read_int ((const UCHAR_T **) &f); + if (ISDIGIT (*f)) + width = read_int (&f); got_width: if (width == 0) width = -1; @@ -2522,12 +2523,11 @@ __vfscanf_internal (FILE *s, const char } while ((fc = *f++) != '\0' && fc != ']') - if (fc == '-' && *f != '\0' && *f != ']' - && (unsigned char) f[-2] <= (unsigned char) *f) + if (fc == '-' && *f != '\0' && *f != ']' && f[-2] <= *f) { /* Add all characters from the one before the '-' up to (but not including) the next format char. */ - for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc) + for (fc = f[-2]; fc < *f; ++fc) ((char *)charbuf.scratch.data)[fc] = 1; } else diff -pruN glibc-2.32.orig/stdlib/tst-secure-getenv.c glibc-2.32/stdlib/tst-secure-getenv.c --- glibc-2.32.orig/stdlib/tst-secure-getenv.c 2021-09-18 21:02:32.700184614 +1000 +++ glibc-2.32/stdlib/tst-secure-getenv.c 2021-09-18 21:03:05.312302287 +1000 @@ -30,167 +30,12 @@ #include #include +#include #include +#include #include static char MAGIC_ARGUMENT[] = "run-actual-test"; -#define MAGIC_STATUS 19 - -/* Return a GID which is not our current GID, but is present in the - supplementary group list. */ -static gid_t -choose_gid (void) -{ - int count = getgroups (0, NULL); - if (count < 0) - { - printf ("getgroups: %m\n"); - exit (1); - } - gid_t *groups; - groups = xcalloc (count, sizeof (*groups)); - int ret = getgroups (count, groups); - if (ret < 0) - { - printf ("getgroups: %m\n"); - exit (1); - } - gid_t current = getgid (); - gid_t not_current = 0; - for (int i = 0; i < ret; ++i) - { - if (groups[i] != current) - { - not_current = groups[i]; - break; - } - } - free (groups); - return not_current; -} - - -/* Copies the executable into a restricted directory, so that we can - safely make it SGID with the TARGET group ID. Then runs the - executable. */ -static int -run_executable_sgid (gid_t target) -{ - char *dirname = xasprintf ("%s/secure-getenv.%jd", - test_dir, (intmax_t) getpid ()); - char *execname = xasprintf ("%s/bin", dirname); - int infd = -1; - int outfd = -1; - int ret = -1; - if (mkdir (dirname, 0700) < 0) - { - printf ("mkdir: %m\n"); - goto err; - } - infd = open ("/proc/self/exe", O_RDONLY); - if (infd < 0) - { - printf ("open (/proc/self/exe): %m\n"); - goto err; - } - outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); - if (outfd < 0) - { - printf ("open (%s): %m\n", execname); - goto err; - } - char buf[4096]; - for (;;) - { - ssize_t rdcount = read (infd, buf, sizeof (buf)); - if (rdcount < 0) - { - printf ("read: %m\n"); - goto err; - } - if (rdcount == 0) - break; - char *p = buf; - char *end = buf + rdcount; - while (p != end) - { - ssize_t wrcount = write (outfd, buf, end - p); - if (wrcount == 0) - errno = ENOSPC; - if (wrcount <= 0) - { - printf ("write: %m\n"); - goto err; - } - p += wrcount; - } - } - if (fchown (outfd, getuid (), target) < 0) - { - printf ("fchown (%s): %m\n", execname); - goto err; - } - if (fchmod (outfd, 02750) < 0) - { - printf ("fchmod (%s): %m\n", execname); - goto err; - } - if (close (outfd) < 0) - { - printf ("close (outfd): %m\n"); - goto err; - } - if (close (infd) < 0) - { - printf ("close (infd): %m\n"); - goto err; - } - - int kid = fork (); - if (kid < 0) - { - printf ("fork: %m\n"); - goto err; - } - if (kid == 0) - { - /* Child process. */ - char *args[] = { execname, MAGIC_ARGUMENT, NULL }; - execve (execname, args, environ); - printf ("execve (%s): %m\n", execname); - _exit (1); - } - int status; - if (waitpid (kid, &status, 0) < 0) - { - printf ("waitpid: %m\n"); - goto err; - } - if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS) - { - printf ("Unexpected exit status %d from child process\n", - status); - goto err; - } - ret = 0; - -err: - if (outfd >= 0) - close (outfd); - if (infd >= 0) - close (infd); - if (execname) - { - unlink (execname); - free (execname); - } - if (dirname) - { - rmdir (dirname); - free (dirname); - } - return ret; -} static int do_test (void) @@ -212,15 +57,15 @@ do_test (void) exit (1); } - gid_t target = choose_gid (); - if (target == 0) - { - fprintf (stderr, - "Could not find a suitable GID for user %jd, skipping test\n", - (intmax_t) getuid ()); - exit (0); - } - return run_executable_sgid (target); + int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT); + + if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) + return EXIT_UNSUPPORTED; + + if (!WIFEXITED (status)) + FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status); + + return 0; } static void @@ -229,23 +74,15 @@ alternative_main (int argc, char **argv) if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0) { if (getgid () == getegid ()) - { - /* This can happen if the file system is mounted nosuid. */ - fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n", - (intmax_t) getgid ()); - exit (MAGIC_STATUS); - } + /* This can happen if the file system is mounted nosuid. */ + FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", + (intmax_t) getgid ()); if (getenv ("PATH") == NULL) - { - printf ("PATH variable not present\n"); - exit (3); - } + FAIL_EXIT (3, "PATH variable not present\n"); if (secure_getenv ("PATH") != NULL) - { - printf ("PATH variable not filtered out\n"); - exit (4); - } - exit (MAGIC_STATUS); + FAIL_EXIT (4, "PATH variable not filtered out\n"); + + exit (EXIT_SUCCESS); } } diff -pruN glibc-2.32.orig/string/bits/string_fortified.h glibc-2.32/string/bits/string_fortified.h --- glibc-2.32.orig/string/bits/string_fortified.h 2021-09-18 21:02:32.700184614 +1000 +++ glibc-2.32/string/bits/string_fortified.h 2021-09-18 21:03:05.312302287 +1000 @@ -22,11 +22,6 @@ # error "Never use directly; include instead." #endif -#if !__GNUC_PREREQ (5,0) -__warndecl (__warn_memset_zero_len, - "memset used with constant zero length parameter; this could be due to transposed parameters"); -#endif - __fortify_function void * __NTH (memcpy (void *__restrict __dest, const void *__restrict __src, size_t __len)) @@ -58,16 +53,6 @@ __NTH (mempcpy (void *__restrict __dest, __fortify_function void * __NTH (memset (void *__dest, int __ch, size_t __len)) { - /* GCC-5.0 and newer implements these checks in the compiler, so we don't - need them here. */ -#if !__GNUC_PREREQ (5,0) - if (__builtin_constant_p (__len) && __len == 0 - && (!__builtin_constant_p (__ch) || __ch != 0)) - { - __warn_memset_zero_len (); - return __dest; - } -#endif return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest)); } diff -pruN glibc-2.32.orig/support/capture_subprocess.h glibc-2.32/support/capture_subprocess.h --- glibc-2.32.orig/support/capture_subprocess.h 2021-09-18 21:02:32.701184648 +1000 +++ glibc-2.32/support/capture_subprocess.h 2021-09-18 21:03:05.312302287 +1000 @@ -41,6 +41,12 @@ struct support_capture_subprocess suppor struct support_capture_subprocess support_capture_subprogram (const char *file, char *const argv[]); +/* Copy the running program into a setgid binary and run it with CHILD_ID + argument. If execution is successful, return the exit status of the child + program, otherwise return a non-zero failure exit code. */ +int support_capture_subprogram_self_sgid + (char *child_id); + /* Deallocate the subprocess data captured by support_capture_subprocess. */ void support_capture_subprocess_free (struct support_capture_subprocess *); diff -pruN glibc-2.32.orig/support/Makefile glibc-2.32/support/Makefile --- glibc-2.32.orig/support/Makefile 2021-09-18 21:02:32.701184648 +1000 +++ glibc-2.32/support/Makefile 2021-09-18 21:03:05.312302287 +1000 @@ -35,6 +35,8 @@ libsupport-routines = \ ignore_stderr \ next_to_fault \ oom_error \ + resolv_response_context_duplicate \ + resolv_response_context_free \ resolv_test \ set_fortify_handler \ support-xfstat \ diff -pruN glibc-2.32.orig/support/resolv_response_context_duplicate.c glibc-2.32/support/resolv_response_context_duplicate.c --- glibc-2.32.orig/support/resolv_response_context_duplicate.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/support/resolv_response_context_duplicate.c 2021-09-18 21:03:05.312302287 +1000 @@ -0,0 +1,37 @@ +/* Duplicate a response context used in DNS resolver tests. + Copyright (C) 2020 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 + +struct resolv_response_context * +resolv_response_context_duplicate (const struct resolv_response_context *ctx) +{ + struct resolv_response_context *result = xmalloc (sizeof (*result)); + memcpy (result, ctx, sizeof (*result)); + if (result->client_address != NULL) + { + result->client_address = xmalloc (result->client_address_length); + memcpy (result->client_address, ctx->client_address, + result->client_address_length); + } + result->query_buffer = xmalloc (result->query_length); + memcpy (result->query_buffer, ctx->query_buffer, result->query_length); + return result; +} diff -pruN glibc-2.32.orig/support/resolv_response_context_free.c glibc-2.32/support/resolv_response_context_free.c --- glibc-2.32.orig/support/resolv_response_context_free.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/support/resolv_response_context_free.c 2021-09-18 21:03:05.312302287 +1000 @@ -0,0 +1,28 @@ +/* Free a response context used in DNS resolver tests. + Copyright (C) 2020 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 +resolv_response_context_free (struct resolv_response_context *ctx) +{ + free (ctx->query_buffer); + free (ctx->client_address); + free (ctx); +} diff -pruN glibc-2.32.orig/support/resolv_test.c glibc-2.32/support/resolv_test.c --- glibc-2.32.orig/support/resolv_test.c 2021-09-18 21:02:32.701184648 +1000 +++ glibc-2.32/support/resolv_test.c 2021-09-18 21:03:05.312302287 +1000 @@ -181,7 +181,9 @@ resolv_response_init (struct resolv_resp b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */ if (flags.tc) b->buffer[2] |= 0x02; - b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */ + b->buffer[3] = flags.rcode; + if (!flags.clear_ra) + b->buffer[3] |= 0x80; if (flags.ad) b->buffer[3] |= 0x20; @@ -434,9 +436,9 @@ resolv_response_buffer (const struct res return result; } -static struct resolv_response_builder * -response_builder_allocate - (const unsigned char *query_buffer, size_t query_length) +struct resolv_response_builder * +resolv_response_builder_allocate (const unsigned char *query_buffer, + size_t query_length) { struct resolv_response_builder *b = xmalloc (sizeof (*b)); memset (b, 0, offsetof (struct resolv_response_builder, buffer)); @@ -445,8 +447,8 @@ response_builder_allocate return b; } -static void -response_builder_free (struct resolv_response_builder *b) +void +resolv_response_builder_free (struct resolv_response_builder *b) { tdestroy (b->compression_offsets, free); free (b); @@ -661,13 +663,17 @@ server_thread_udp_process_one (struct re struct resolv_response_context ctx = { + .test = obj, + .client_address = &peer, + .client_address_length = peerlen, .query_buffer = query, .query_length = length, .server_index = server_index, .tcp = false, .edns = qinfo.edns, }; - struct resolv_response_builder *b = response_builder_allocate (query, length); + struct resolv_response_builder *b + = resolv_response_builder_allocate (query, length); obj->config.response_callback (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); @@ -684,7 +690,7 @@ server_thread_udp_process_one (struct re if (b->offset >= 12) printf ("info: UDP server %d: sending response:" " %zu bytes, RCODE %d (for %s/%u/%u)\n", - server_index, b->offset, b->buffer[3] & 0x0f, + ctx.server_index, b->offset, b->buffer[3] & 0x0f, qinfo.qname, qinfo.qclass, qinfo.qtype); else printf ("info: UDP server %d: sending response: %zu bytes" @@ -694,23 +700,31 @@ server_thread_udp_process_one (struct re if (b->truncate_bytes > 0) printf ("info: truncated by %u bytes\n", b->truncate_bytes); } - size_t to_send = b->offset; - if (to_send < b->truncate_bytes) - to_send = 0; - else - to_send -= b->truncate_bytes; - - /* Ignore most errors here because the other end may have closed - the socket. */ - if (sendto (obj->servers[server_index].socket_udp, - b->buffer, to_send, 0, - (struct sockaddr *) &peer, peerlen) < 0) - TEST_VERIFY_EXIT (errno != EBADF); + resolv_response_send_udp (&ctx, b); } - response_builder_free (b); + resolv_response_builder_free (b); return true; } +void +resolv_response_send_udp (const struct resolv_response_context *ctx, + struct resolv_response_builder *b) +{ + TEST_VERIFY_EXIT (!ctx->tcp); + size_t to_send = b->offset; + if (to_send < b->truncate_bytes) + to_send = 0; + else + to_send -= b->truncate_bytes; + + /* Ignore most errors here because the other end may have closed + the socket. */ + if (sendto (ctx->test->servers[ctx->server_index].socket_udp, + b->buffer, to_send, 0, + ctx->client_address, ctx->client_address_length) < 0) + TEST_VERIFY_EXIT (errno != EBADF); +} + /* UDP thread_callback function. Variant for one thread per server. */ static void @@ -897,14 +911,15 @@ server_thread_tcp_client (void *arg) struct resolv_response_context ctx = { + .test = closure->obj, .query_buffer = query_buffer, .query_length = query_length, .server_index = closure->server_index, .tcp = true, .edns = qinfo.edns, }; - struct resolv_response_builder *b = response_builder_allocate - (query_buffer, query_length); + struct resolv_response_builder *b + = resolv_response_builder_allocate (query_buffer, query_length); closure->obj->config.response_callback (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); @@ -936,7 +951,7 @@ server_thread_tcp_client (void *arg) writev_fully (closure->client_socket, buffers, 2); } bool close_flag = b->close; - response_builder_free (b); + resolv_response_builder_free (b); free (query_buffer); if (close_flag) break; diff -pruN glibc-2.32.orig/support/resolv_test.h glibc-2.32/support/resolv_test.h --- glibc-2.32.orig/support/resolv_test.h 2021-09-18 21:02:32.701184648 +1000 +++ glibc-2.32/support/resolv_test.h 2021-09-18 21:03:05.312302287 +1000 @@ -35,25 +35,36 @@ struct resolv_edns_info uint16_t payload_size; }; +/* This opaque struct collects information about the resolver testing + currently in progress. */ +struct resolv_test; + /* This struct provides context information when the response callback specified in struct resolv_redirect_config is invoked. */ struct resolv_response_context { - const unsigned char *query_buffer; + struct resolv_test *test; + void *client_address; + size_t client_address_length; + unsigned char *query_buffer; size_t query_length; int server_index; bool tcp; struct resolv_edns_info edns; }; +/* Produces a deep copy of the context. */ +struct resolv_response_context * + resolv_response_context_duplicate (const struct resolv_response_context *); + +/* Frees the copy. For the context passed to the response function, + this happens implicitly. */ +void resolv_response_context_free (struct resolv_response_context *); + /* This opaque struct is used to construct responses from within the response callback function. */ struct resolv_response_builder; -/* This opaque struct collects information about the resolver testing - currently in progress. */ -struct resolv_test; - enum { /* Maximum number of test servers supported by the framework. */ @@ -137,6 +148,10 @@ struct resolv_response_flags /* If true, the AD (authenticated data) flag will be set. */ bool ad; + /* If true, do not set the RA (recursion available) flag in the + response. */ + bool clear_ra; + /* Initial section count values. Can be used to artificially increase the counts, for malformed packet testing.*/ unsigned short qdcount; @@ -188,6 +203,22 @@ void resolv_response_close (struct resol /* The size of the response packet built so far. */ size_t resolv_response_length (const struct resolv_response_builder *); +/* Allocates a response builder tied to a specific query packet, + starting at QUERY_BUFFER, containing QUERY_LENGTH bytes. */ +struct resolv_response_builder * + resolv_response_builder_allocate (const unsigned char *query_buffer, + size_t query_length); + +/* Deallocates a response buffer. */ +void resolv_response_builder_free (struct resolv_response_builder *); + +/* Sends a UDP response using a specific context. This can be used to + reorder or duplicate responses, along with + resolv_response_context_duplicate and + response_builder_allocate. */ +void resolv_response_send_udp (const struct resolv_response_context *, + struct resolv_response_builder *); + __END_DECLS #endif /* SUPPORT_RESOLV_TEST_H */ diff -pruN glibc-2.32.orig/support/subprocess.h glibc-2.32/support/subprocess.h --- glibc-2.32.orig/support/subprocess.h 2021-09-18 21:02:32.701184648 +1000 +++ glibc-2.32/support/subprocess.h 2021-09-18 21:03:05.312302287 +1000 @@ -38,6 +38,11 @@ struct support_subprocess support_subpro struct support_subprocess support_subprogram (const char *file, char *const argv[]); +/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it + to complete. Return program exit status. */ +int support_subprogram_wait + (const char *file, char *const argv[]); + /* Wait for the subprocess indicated by PROC::PID. Return the status indicate by waitpid call. */ int support_process_wait (struct support_subprocess *proc); diff -pruN glibc-2.32.orig/support/support_capture_subprocess.c glibc-2.32/support/support_capture_subprocess.c --- glibc-2.32.orig/support/support_capture_subprocess.c 2021-09-18 21:02:32.701184648 +1000 +++ glibc-2.32/support/support_capture_subprocess.c 2021-09-18 21:03:05.313302322 +1000 @@ -20,11 +20,14 @@ #include #include +#include #include #include #include #include #include +#include +#include static void transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) @@ -36,7 +39,7 @@ transfer (const char *what, struct pollf if (ret < 0) { support_record_failure (); - printf ("error: reading from subprocess %s: %m", what); + printf ("error: reading from subprocess %s: %m\n", what); pfd->events = 0; pfd->revents = 0; } @@ -102,6 +105,129 @@ support_capture_subprogram (const char * return result; } +/* Copies the executable into a restricted directory, so that we can + safely make it SGID with the TARGET group ID. Then runs the + executable. */ +static int +copy_and_spawn_sgid (char *child_id, gid_t gid) +{ + char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd", + test_dir, (intmax_t) getpid ()); + char *execname = xasprintf ("%s/bin", dirname); + int infd = -1; + int outfd = -1; + int ret = 1, status = 1; + + TEST_VERIFY (mkdir (dirname, 0700) == 0); + if (support_record_failure_is_failed ()) + goto err; + + infd = open ("/proc/self/exe", O_RDONLY); + if (infd < 0) + FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n"); + + outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); + TEST_VERIFY (outfd >= 0); + if (support_record_failure_is_failed ()) + goto err; + + char buf[4096]; + for (;;) + { + ssize_t rdcount = read (infd, buf, sizeof (buf)); + TEST_VERIFY (rdcount >= 0); + if (support_record_failure_is_failed ()) + goto err; + if (rdcount == 0) + break; + char *p = buf; + char *end = buf + rdcount; + while (p != end) + { + ssize_t wrcount = write (outfd, buf, end - p); + if (wrcount == 0) + errno = ENOSPC; + TEST_VERIFY (wrcount > 0); + if (support_record_failure_is_failed ()) + goto err; + p += wrcount; + } + } + TEST_VERIFY (fchown (outfd, getuid (), gid) == 0); + if (support_record_failure_is_failed ()) + goto err; + TEST_VERIFY (fchmod (outfd, 02750) == 0); + if (support_record_failure_is_failed ()) + goto err; + TEST_VERIFY (close (outfd) == 0); + if (support_record_failure_is_failed ()) + goto err; + TEST_VERIFY (close (infd) == 0); + if (support_record_failure_is_failed ()) + goto err; + + /* We have the binary, now spawn the subprocess. Avoid using + support_subprogram because we only want the program exit status, not the + contents. */ + ret = 0; + + char * const args[] = {execname, child_id, NULL}; + + status = support_subprogram_wait (args[0], args); + +err: + if (outfd >= 0) + close (outfd); + if (infd >= 0) + close (infd); + if (execname != NULL) + { + unlink (execname); + free (execname); + } + if (dirname != NULL) + { + rmdir (dirname); + free (dirname); + } + + if (ret != 0) + FAIL_EXIT1("Failed to make sgid executable for test\n"); + + return status; +} + +int +support_capture_subprogram_self_sgid (char *child_id) +{ + gid_t target = 0; + const int count = 64; + gid_t groups[count]; + + /* Get a GID which is not our current GID, but is present in the + supplementary group list. */ + int ret = getgroups (count, groups); + if (ret < 0) + FAIL_UNSUPPORTED("Could not get group list for user %jd\n", + (intmax_t) getuid ()); + + gid_t current = getgid (); + for (int i = 0; i < ret; ++i) + { + if (groups[i] != current) + { + target = groups[i]; + break; + } + } + + if (target == 0) + FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n", + (intmax_t) getuid ()); + + return copy_and_spawn_sgid (child_id, target); +} + void support_capture_subprocess_free (struct support_capture_subprocess *p) { diff -pruN glibc-2.32.orig/support/support_subprocess.c glibc-2.32/support/support_subprocess.c --- glibc-2.32.orig/support/support_subprocess.c 2021-09-18 21:02:32.701184648 +1000 +++ glibc-2.32/support/support_subprocess.c 2021-09-18 21:03:05.313302322 +1000 @@ -27,7 +27,7 @@ #include static struct support_subprocess -support_suprocess_init (void) +support_subprocess_init (void) { struct support_subprocess result; @@ -48,7 +48,7 @@ support_suprocess_init (void) struct support_subprocess support_subprocess (void (*callback) (void *), void *closure) { - struct support_subprocess result = support_suprocess_init (); + struct support_subprocess result = support_subprocess_init (); result.pid = xfork (); if (result.pid == 0) @@ -71,7 +71,7 @@ support_subprocess (void (*callback) (vo struct support_subprocess support_subprogram (const char *file, char *const argv[]) { - struct support_subprocess result = support_suprocess_init (); + struct support_subprocess result = support_subprocess_init (); posix_spawn_file_actions_t fa; /* posix_spawn_file_actions_init does not fail. */ @@ -84,7 +84,7 @@ support_subprogram (const char *file, ch xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]); xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]); - result.pid = xposix_spawn (file, &fa, NULL, argv, NULL); + result.pid = xposix_spawn (file, &fa, NULL, argv, environ); xclose (result.stdout_pipe[1]); xclose (result.stderr_pipe[1]); @@ -93,6 +93,19 @@ support_subprogram (const char *file, ch } int +support_subprogram_wait (const char *file, char *const argv[]) +{ + posix_spawn_file_actions_t fa; + + posix_spawn_file_actions_init (&fa); + struct support_subprocess res = support_subprocess_init (); + + res.pid = xposix_spawn (file, &fa, NULL, argv, environ); + + return support_process_wait (&res); +} + +int support_process_wait (struct support_subprocess *proc) { xclose (proc->stdout_pipe[0]); diff -pruN glibc-2.32.orig/sysdeps/aarch64/dl-bti.c glibc-2.32/sysdeps/aarch64/dl-bti.c --- glibc-2.32.orig/sysdeps/aarch64/dl-bti.c 2021-09-18 21:02:32.702184682 +1000 +++ glibc-2.32/sysdeps/aarch64/dl-bti.c 2021-09-18 21:03:05.313302322 +1000 @@ -19,43 +19,76 @@ #include #include #include +#include -static int -enable_bti (struct link_map *map, const char *program) +/* See elf/dl-load.h. */ +#ifndef MAP_COPY +# define MAP_COPY (MAP_PRIVATE | MAP_DENYWRITE) +#endif + +/* Enable BTI protection for MAP. */ + +void +_dl_bti_protect (struct link_map *map, int fd) { + const size_t pagesz = GLRO(dl_pagesize); const ElfW(Phdr) *phdr; - unsigned prot; for (phdr = map->l_phdr; phdr < &map->l_phdr[map->l_phnum]; ++phdr) if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X)) { - void *start = (void *) (phdr->p_vaddr + map->l_addr); - size_t len = phdr->p_memsz; + size_t vstart = ALIGN_DOWN (phdr->p_vaddr, pagesz); + size_t vend = ALIGN_UP (phdr->p_vaddr + phdr->p_filesz, pagesz); + off_t off = ALIGN_DOWN (phdr->p_offset, pagesz); + void *start = (void *) (vstart + map->l_addr); + size_t len = vend - vstart; - prot = PROT_EXEC | PROT_BTI; + unsigned prot = PROT_EXEC | PROT_BTI; if (phdr->p_flags & PF_R) prot |= PROT_READ; if (phdr->p_flags & PF_W) prot |= PROT_WRITE; - if (__mprotect (start, len, prot) < 0) - { - if (program) - _dl_fatal_printf ("%s: mprotect failed to turn on BTI\n", - map->l_name); - else - _dl_signal_error (errno, map->l_name, "dlopen", - N_("mprotect failed to turn on BTI")); - } + if (fd == -1) + /* Ignore failures for kernel mapped binaries. */ + __mprotect (start, len, prot); + else + map->l_mach.bti_fail = __mmap (start, len, prot, + MAP_FIXED|MAP_COPY|MAP_FILE, + fd, off) == MAP_FAILED; } - return 0; } -/* Enable BTI for L if required. */ + +static void +bti_failed (struct link_map *l, const char *program) +{ + if (program) + _dl_fatal_printf ("%s: %s: failed to turn on BTI protection\n", + program, l->l_name); + else + /* Note: the errno value is not available any more. */ + _dl_signal_error (0, l->l_name, "dlopen", + N_("failed to turn on BTI protection")); +} + + +/* Enable BTI for L and its dependencies. */ void _dl_bti_check (struct link_map *l, const char *program) { - if (GLRO(dl_aarch64_cpu_features).bti && l->l_mach.bti) - enable_bti (l, program); + if (!GLRO(dl_aarch64_cpu_features).bti) + return; + + if (l->l_mach.bti_fail) + bti_failed (l, program); + + unsigned int i = l->l_searchlist.r_nlist; + while (i-- > 0) + { + struct link_map *dep = l->l_initfini[i]; + if (dep->l_mach.bti_fail) + bti_failed (dep, program); + } } diff -pruN glibc-2.32.orig/sysdeps/aarch64/dl-machine.h glibc-2.32/sysdeps/aarch64/dl-machine.h --- glibc-2.32.orig/sysdeps/aarch64/dl-machine.h 2021-09-18 21:02:32.702184682 +1000 +++ glibc-2.32/sysdeps/aarch64/dl-machine.h 2021-09-18 21:03:05.313302322 +1000 @@ -395,13 +395,6 @@ elf_machine_lazy_rel (struct link_map *m /* Check for unexpected PLT reloc type. */ if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1)) { - if (map->l_mach.plt == 0) - { - /* Prelinking. */ - *reloc_addr += l_addr; - return; - } - if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL)) { /* Check the symbol table for variant PCS symbols. */ @@ -425,7 +418,10 @@ elf_machine_lazy_rel (struct link_map *m } } - *reloc_addr = map->l_mach.plt; + if (map->l_mach.plt == 0) + *reloc_addr += l_addr; + else + *reloc_addr = map->l_mach.plt; } else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1)) { diff -pruN glibc-2.32.orig/sysdeps/aarch64/dl-prop.h glibc-2.32/sysdeps/aarch64/dl-prop.h --- glibc-2.32.orig/sysdeps/aarch64/dl-prop.h 2021-09-18 21:02:32.702184682 +1000 +++ glibc-2.32/sysdeps/aarch64/dl-prop.h 2021-09-18 21:03:05.313302322 +1000 @@ -19,6 +19,8 @@ #ifndef _DL_PROP_H #define _DL_PROP_H +extern void _dl_bti_protect (struct link_map *, int) attribute_hidden; + extern void _dl_bti_check (struct link_map *, const char *) attribute_hidden; @@ -35,14 +37,18 @@ _dl_open_check (struct link_map *m) } static inline void __attribute__ ((always_inline)) -_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph) +_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph) { } static inline int -_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz, - void *data) +_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, + uint32_t datasz, void *data) { + if (!GLRO(dl_aarch64_cpu_features).bti) + /* Skip note processing. */ + return 0; + if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) { /* Stop if the property note is ill-formed. */ @@ -51,7 +57,7 @@ _dl_process_gnu_property (struct link_ma unsigned int feature_1 = *(unsigned int *) data; if (feature_1 & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) - l->l_mach.bti = true; + _dl_bti_protect (l, fd); /* Stop if we processed the property note. */ return 0; diff -pruN glibc-2.32.orig/sysdeps/aarch64/linkmap.h glibc-2.32/sysdeps/aarch64/linkmap.h --- glibc-2.32.orig/sysdeps/aarch64/linkmap.h 2021-09-18 21:02:32.702184682 +1000 +++ glibc-2.32/sysdeps/aarch64/linkmap.h 2021-09-18 21:03:05.313302322 +1000 @@ -22,5 +22,5 @@ struct link_map_machine { ElfW(Addr) plt; /* Address of .plt */ void *tlsdesc_table; /* Address of TLS descriptor hash table. */ - bool bti; /* Branch Target Identification is enabled. */ + bool bti_fail; /* Failed to enable Branch Target Identification. */ }; diff -pruN glibc-2.32.orig/sysdeps/aarch64/multiarch/memcpy_advsimd.S glibc-2.32/sysdeps/aarch64/multiarch/memcpy_advsimd.S --- glibc-2.32.orig/sysdeps/aarch64/multiarch/memcpy_advsimd.S 2021-09-18 21:02:32.702184682 +1000 +++ glibc-2.32/sysdeps/aarch64/multiarch/memcpy_advsimd.S 2021-09-18 21:03:05.313302322 +1000 @@ -223,12 +223,13 @@ L(copy_long_backwards): b.ls L(copy64_from_start) L(loop64_backwards): - stp A_q, B_q, [dstend, -32] + str B_q, [dstend, -16] + str A_q, [dstend, -32] ldp A_q, B_q, [srcend, -96] - stp C_q, D_q, [dstend, -64] + str D_q, [dstend, -48] + str C_q, [dstend, -64]! ldp C_q, D_q, [srcend, -128] sub srcend, srcend, 64 - sub dstend, dstend, 64 subs count, count, 64 b.hi L(loop64_backwards) diff -pruN glibc-2.32.orig/sysdeps/aarch64/multiarch/memcpy.c glibc-2.32/sysdeps/aarch64/multiarch/memcpy.c --- glibc-2.32.orig/sysdeps/aarch64/multiarch/memcpy.c 2021-09-18 21:02:32.702184682 +1000 +++ glibc-2.32/sysdeps/aarch64/multiarch/memcpy.c 2021-09-18 21:03:05.313302322 +1000 @@ -41,7 +41,8 @@ libc_ifunc (__libc_memcpy, ? __memcpy_falkor : (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr) ? __memcpy_thunderx2 - : (IS_NEOVERSE_N1 (midr) + : (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr) + || IS_NEOVERSE_V1 (midr) ? __memcpy_simd : __memcpy_generic))))); diff -pruN glibc-2.32.orig/sysdeps/aarch64/multiarch/memmove.c glibc-2.32/sysdeps/aarch64/multiarch/memmove.c --- glibc-2.32.orig/sysdeps/aarch64/multiarch/memmove.c 2021-09-18 21:02:32.702184682 +1000 +++ glibc-2.32/sysdeps/aarch64/multiarch/memmove.c 2021-09-18 21:03:05.313302322 +1000 @@ -41,7 +41,8 @@ libc_ifunc (__libc_memmove, ? __memmove_falkor : (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr) ? __memmove_thunderx2 - : (IS_NEOVERSE_N1 (midr) + : (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr) + || IS_NEOVERSE_V1 (midr) ? __memmove_simd : __memmove_generic))))); diff -pruN glibc-2.32.orig/sysdeps/aarch64/start.S glibc-2.32/sysdeps/aarch64/start.S --- glibc-2.32.orig/sysdeps/aarch64/start.S 2021-09-18 21:02:32.702184682 +1000 +++ glibc-2.32/sysdeps/aarch64/start.S 2021-09-18 21:03:05.313302322 +1000 @@ -43,11 +43,9 @@ */ .text - .globl _start - .type _start,#function -_start: - BTI_C +ENTRY(_start) /* Create an initial frame with 0 LR and FP */ + cfi_undefined (x30) mov x29, #0 mov x30, #0 @@ -101,8 +99,10 @@ _start: because crt1.o and rcrt1.o share code and the later must avoid the use of GOT relocations before __libc_start_main is called. */ __wrap_main: + BTI_C b main #endif +END(_start) /* Define a symbol for the first piece of initialized data. */ .data diff -pruN glibc-2.32.orig/sysdeps/generic/dl-prop.h glibc-2.32/sysdeps/generic/dl-prop.h --- glibc-2.32.orig/sysdeps/generic/dl-prop.h 2021-09-18 21:02:32.705184785 +1000 +++ glibc-2.32/sysdeps/generic/dl-prop.h 2021-09-18 21:03:05.313302322 +1000 @@ -37,15 +37,15 @@ _dl_open_check (struct link_map *m) } static inline void __attribute__ ((always_inline)) -_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph) +_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph) { } /* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of L, processing of the properties continues until this returns 0. */ static inline int __attribute__ ((always_inline)) -_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz, - void *data) +_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, + uint32_t datasz, void *data) { return 0; } diff -pruN glibc-2.32.orig/sysdeps/generic/ldsodefs.h glibc-2.32/sysdeps/generic/ldsodefs.h --- glibc-2.32.orig/sysdeps/generic/ldsodefs.h 2021-09-18 21:02:32.705184785 +1000 +++ glibc-2.32/sysdeps/generic/ldsodefs.h 2021-09-18 21:03:05.313302322 +1000 @@ -919,8 +919,9 @@ extern void _dl_rtld_di_serinfo (struct Dl_serinfo *si, bool counting); /* Process PT_GNU_PROPERTY program header PH in module L after - PT_LOAD segments are mapped. */ -void _dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph); + PT_LOAD segments are mapped from file FD. */ +void _dl_process_pt_gnu_property (struct link_map *l, int fd, + const ElfW(Phdr) *ph); /* Search loaded objects' symbol tables for a definition of the symbol diff -pruN glibc-2.32.orig/sysdeps/generic/unwind.h glibc-2.32/sysdeps/generic/unwind.h --- glibc-2.32.orig/sysdeps/generic/unwind.h 2021-09-18 21:02:32.706184819 +1000 +++ glibc-2.32/sysdeps/generic/unwind.h 2021-09-18 21:03:05.313302322 +1000 @@ -75,15 +75,21 @@ typedef void (*_Unwind_Exception_Cleanup struct _Unwind_Exception { - _Unwind_Exception_Class exception_class; - _Unwind_Exception_Cleanup_Fn exception_cleanup; - _Unwind_Word private_1; - _Unwind_Word private_2; + union + { + struct + { + _Unwind_Exception_Class exception_class; + _Unwind_Exception_Cleanup_Fn exception_cleanup; + _Unwind_Word private_1; + _Unwind_Word private_2; + }; - /* @@@ The IA-64 ABI says that this structure must be double-word aligned. - Taking that literally does not make much sense generically. Instead we - provide the maximum alignment required by any type for the machine. */ -} __attribute__((__aligned__)); + /* The IA-64 ABI says that this structure must be double-word aligned. */ + _Unwind_Word unwind_exception_align[2] + __attribute__ ((__aligned__ (2 * sizeof (_Unwind_Word)))); + }; +}; /* The ACTIONS argument to the personality routine is a bitwise OR of one diff -pruN glibc-2.32.orig/sysdeps/gnu/errlist.h glibc-2.32/sysdeps/gnu/errlist.h --- glibc-2.32.orig/sysdeps/gnu/errlist.h 2021-09-18 21:02:32.706184819 +1000 +++ glibc-2.32/sysdeps/gnu/errlist.h 2021-09-18 21:03:05.313302322 +1000 @@ -1,24 +1,21 @@ -#ifndef ERR_MAP -#define ERR_MAP(value) value -#endif -_S(ERR_MAP(0), N_("Success")) +_S(0, N_("Success")) #ifdef EPERM /* TRANS Only the owner of the file (or other resource) TRANS or processes with special privileges can perform the operation. */ -_S(ERR_MAP(EPERM), N_("Operation not permitted")) +_S(EPERM, N_("Operation not permitted")) #endif #ifdef ENOENT /* TRANS This is a ``file doesn't exist'' error TRANS for ordinary files that are referenced in contexts where they are TRANS expected to already exist. */ -_S(ERR_MAP(ENOENT), N_("No such file or directory")) +_S(ENOENT, N_("No such file or directory")) #endif #ifdef ESRCH /* TRANS No process matches the specified process ID. */ -_S(ERR_MAP(ESRCH), N_("No such process")) +_S(ESRCH, N_("No such process")) #endif #ifdef EINTR /* @@ -29,12 +26,12 @@ TRANS TRANS You can choose to have functions resume after a signal that is handled, TRANS rather than failing with @code{EINTR}; see @ref{Interrupted TRANS Primitives}. */ -_S(ERR_MAP(EINTR), N_("Interrupted system call")) +_S(EINTR, N_("Interrupted system call")) #endif #ifdef EIO /* TRANS Usually used for physical read or write errors. */ -_S(ERR_MAP(EIO), N_("Input/output error")) +_S(EIO, N_("Input/output error")) #endif #ifdef ENXIO /* @@ -43,7 +40,7 @@ TRANS represented by a file you specifie TRANS This can mean that the device file was installed incorrectly, or that TRANS the physical device is missing or not correctly attached to the TRANS computer. */ -_S(ERR_MAP(ENXIO), N_("No such device or address")) +_S(ENXIO, N_("No such device or address")) #endif #ifdef E2BIG /* @@ -51,27 +48,27 @@ TRANS Used when the arguments passed to TRANS being executed with one of the @code{exec} functions (@pxref{Executing a TRANS File}) occupy too much memory space. This condition never arises on TRANS @gnuhurdsystems{}. */ -_S(ERR_MAP(E2BIG), N_("Argument list too long")) +_S(E2BIG, N_("Argument list too long")) #endif #ifdef ENOEXEC /* TRANS Invalid executable file format. This condition is detected by the TRANS @code{exec} functions; see @ref{Executing a File}. */ -_S(ERR_MAP(ENOEXEC), N_("Exec format error")) +_S(ENOEXEC, N_("Exec format error")) #endif #ifdef EBADF /* TRANS For example, I/O on a descriptor that has been TRANS closed or reading from a descriptor open only for writing (or vice TRANS versa). */ -_S(ERR_MAP(EBADF), N_("Bad file descriptor")) +_S(EBADF, N_("Bad file descriptor")) #endif #ifdef ECHILD /* TRANS This error happens on operations that are TRANS supposed to manipulate child processes, when there aren't any processes TRANS to manipulate. */ -_S(ERR_MAP(ECHILD), N_("No child processes")) +_S(ECHILD, N_("No child processes")) #endif #ifdef EDEADLK /* @@ -79,74 +76,74 @@ TRANS Allocating a system resource would TRANS deadlock situation. The system does not guarantee that it will notice TRANS all such situations. This error means you got lucky and the system TRANS noticed; it might just hang. @xref{File Locks}, for an example. */ -_S(ERR_MAP(EDEADLK), N_("Resource deadlock avoided")) +_S(EDEADLK, N_("Resource deadlock avoided")) #endif #ifdef ENOMEM /* TRANS The system cannot allocate more virtual memory TRANS because its capacity is full. */ -_S(ERR_MAP(ENOMEM), N_("Cannot allocate memory")) +_S(ENOMEM, N_("Cannot allocate memory")) #endif #ifdef EACCES /* TRANS The file permissions do not allow the attempted operation. */ -_S(ERR_MAP(EACCES), N_("Permission denied")) +_S(EACCES, N_("Permission denied")) #endif #ifdef EFAULT /* TRANS An invalid pointer was detected. TRANS On @gnuhurdsystems{}, this error never happens; you get a signal instead. */ -_S(ERR_MAP(EFAULT), N_("Bad address")) +_S(EFAULT, N_("Bad address")) #endif #ifdef ENOTBLK /* TRANS A file that isn't a block special file was given in a situation that TRANS requires one. For example, trying to mount an ordinary file as a file TRANS system in Unix gives this error. */ -_S(ERR_MAP(ENOTBLK), N_("Block device required")) +_S(ENOTBLK, N_("Block device required")) #endif #ifdef EBUSY /* TRANS A system resource that can't be shared is already in use. TRANS For example, if you try to delete a file that is the root of a currently TRANS mounted filesystem, you get this error. */ -_S(ERR_MAP(EBUSY), N_("Device or resource busy")) +_S(EBUSY, N_("Device or resource busy")) #endif #ifdef EEXIST /* TRANS An existing file was specified in a context where it only TRANS makes sense to specify a new file. */ -_S(ERR_MAP(EEXIST), N_("File exists")) +_S(EEXIST, N_("File exists")) #endif #ifdef EXDEV /* TRANS An attempt to make an improper link across file systems was detected. TRANS This happens not only when you use @code{link} (@pxref{Hard Links}) but TRANS also when you rename a file with @code{rename} (@pxref{Renaming Files}). */ -_S(ERR_MAP(EXDEV), N_("Invalid cross-device link")) +_S(EXDEV, N_("Invalid cross-device link")) #endif #ifdef ENODEV /* TRANS The wrong type of device was given to a function that expects a TRANS particular sort of device. */ -_S(ERR_MAP(ENODEV), N_("No such device")) +_S(ENODEV, N_("No such device")) #endif #ifdef ENOTDIR /* TRANS A file that isn't a directory was specified when a directory is required. */ -_S(ERR_MAP(ENOTDIR), N_("Not a directory")) +_S(ENOTDIR, N_("Not a directory")) #endif #ifdef EISDIR /* TRANS You cannot open a directory for writing, TRANS or create or remove hard links to it. */ -_S(ERR_MAP(EISDIR), N_("Is a directory")) +_S(EISDIR, N_("Is a directory")) #endif #ifdef EINVAL /* TRANS This is used to indicate various kinds of problems TRANS with passing the wrong argument to a library function. */ -_S(ERR_MAP(EINVAL), N_("Invalid argument")) +_S(EINVAL, N_("Invalid argument")) #endif #ifdef EMFILE /* @@ -157,20 +154,20 @@ TRANS In BSD and GNU, the number of open TRANS limit that can usually be increased. If you get this error, you might TRANS want to increase the @code{RLIMIT_NOFILE} limit or make it unlimited; TRANS @pxref{Limits on Resources}. */ -_S(ERR_MAP(EMFILE), N_("Too many open files")) +_S(EMFILE, N_("Too many open files")) #endif #ifdef ENFILE /* TRANS There are too many distinct file openings in the entire system. Note TRANS that any number of linked channels count as just one file opening; see TRANS @ref{Linked Channels}. This error never occurs on @gnuhurdsystems{}. */ -_S(ERR_MAP(ENFILE), N_("Too many open files in system")) +_S(ENFILE, N_("Too many open files in system")) #endif #ifdef ENOTTY /* TRANS Inappropriate I/O control operation, such as trying to set terminal TRANS modes on an ordinary file. */ -_S(ERR_MAP(ENOTTY), N_("Inappropriate ioctl for device")) +_S(ENOTTY, N_("Inappropriate ioctl for device")) #endif #ifdef ETXTBSY /* @@ -179,35 +176,35 @@ TRANS write to a file that is currently TRANS debugger to run a program is considered having it open for writing and TRANS will cause this error. (The name stands for ``text file busy''.) This TRANS is not an error on @gnuhurdsystems{}; the text is copied as necessary. */ -_S(ERR_MAP(ETXTBSY), N_("Text file busy")) +_S(ETXTBSY, N_("Text file busy")) #endif #ifdef EFBIG /* TRANS The size of a file would be larger than allowed by the system. */ -_S(ERR_MAP(EFBIG), N_("File too large")) +_S(EFBIG, N_("File too large")) #endif #ifdef ENOSPC /* TRANS Write operation on a file failed because the TRANS disk is full. */ -_S(ERR_MAP(ENOSPC), N_("No space left on device")) +_S(ENOSPC, N_("No space left on device")) #endif #ifdef ESPIPE /* TRANS Invalid seek operation (such as on a pipe). */ -_S(ERR_MAP(ESPIPE), N_("Illegal seek")) +_S(ESPIPE, N_("Illegal seek")) #endif #ifdef EROFS /* TRANS An attempt was made to modify something on a read-only file system. */ -_S(ERR_MAP(EROFS), N_("Read-only file system")) +_S(EROFS, N_("Read-only file system")) #endif #ifdef EMLINK /* TRANS The link count of a single file would become too large. TRANS @code{rename} can cause this error if the file being renamed already has TRANS as many links as it can take (@pxref{Renaming Files}). */ -_S(ERR_MAP(EMLINK), N_("Too many links")) +_S(EMLINK, N_("Too many links")) #endif #ifdef EPIPE /* @@ -216,19 +213,19 @@ TRANS Every library function that return TRANS @code{SIGPIPE} signal; this signal terminates the program if not handled TRANS or blocked. Thus, your program will never actually see @code{EPIPE} TRANS unless it has handled or blocked @code{SIGPIPE}. */ -_S(ERR_MAP(EPIPE), N_("Broken pipe")) +_S(EPIPE, N_("Broken pipe")) #endif #ifdef EDOM /* TRANS Used by mathematical functions when an argument value does TRANS not fall into the domain over which the function is defined. */ -_S(ERR_MAP(EDOM), N_("Numerical argument out of domain")) +_S(EDOM, N_("Numerical argument out of domain")) #endif #ifdef ERANGE /* TRANS Used by mathematical functions when the result value is TRANS not representable because of overflow or underflow. */ -_S(ERR_MAP(ERANGE), N_("Numerical result out of range")) +_S(ERANGE, N_("Numerical result out of range")) #endif #ifdef EAGAIN /* @@ -261,7 +258,7 @@ TRANS Such shortages are usually fairly TRANS so usually an interactive program should report the error to the user TRANS and return to its command loop. TRANS @end itemize */ -_S(ERR_MAP(EAGAIN), N_("Resource temporarily unavailable")) +_S(EAGAIN, N_("Resource temporarily unavailable")) #endif #ifdef EINPROGRESS /* @@ -273,47 +270,47 @@ TRANS the operation has begun and will t TRANS the object before the call completes return @code{EALREADY}. You can TRANS use the @code{select} function to find out when the pending operation TRANS has completed; @pxref{Waiting for I/O}. */ -_S(ERR_MAP(EINPROGRESS), N_("Operation now in progress")) +_S(EINPROGRESS, N_("Operation now in progress")) #endif #ifdef EALREADY /* TRANS An operation is already in progress on an object that has non-blocking TRANS mode selected. */ -_S(ERR_MAP(EALREADY), N_("Operation already in progress")) +_S(EALREADY, N_("Operation already in progress")) #endif #ifdef ENOTSOCK /* TRANS A file that isn't a socket was specified when a socket is required. */ -_S(ERR_MAP(ENOTSOCK), N_("Socket operation on non-socket")) +_S(ENOTSOCK, N_("Socket operation on non-socket")) #endif #ifdef EMSGSIZE /* TRANS The size of a message sent on a socket was larger than the supported TRANS maximum size. */ -_S(ERR_MAP(EMSGSIZE), N_("Message too long")) +_S(EMSGSIZE, N_("Message too long")) #endif #ifdef EPROTOTYPE /* TRANS The socket type does not support the requested communications protocol. */ -_S(ERR_MAP(EPROTOTYPE), N_("Protocol wrong type for socket")) +_S(EPROTOTYPE, N_("Protocol wrong type for socket")) #endif #ifdef ENOPROTOOPT /* TRANS You specified a socket option that doesn't make sense for the TRANS particular protocol being used by the socket. @xref{Socket Options}. */ -_S(ERR_MAP(ENOPROTOOPT), N_("Protocol not available")) +_S(ENOPROTOOPT, N_("Protocol not available")) #endif #ifdef EPROTONOSUPPORT /* TRANS The socket domain does not support the requested communications protocol TRANS (perhaps because the requested protocol is completely invalid). TRANS @xref{Creating a Socket}. */ -_S(ERR_MAP(EPROTONOSUPPORT), N_("Protocol not supported")) +_S(EPROTONOSUPPORT, N_("Protocol not supported")) #endif #ifdef ESOCKTNOSUPPORT /* TRANS The socket type is not supported. */ -_S(ERR_MAP(ESOCKTNOSUPPORT), N_("Socket type not supported")) +_S(ESOCKTNOSUPPORT, N_("Socket type not supported")) #endif #ifdef EOPNOTSUPP /* @@ -323,71 +320,71 @@ TRANS implemented for all communications TRANS error can happen for many calls when the object does not support the TRANS particular operation; it is a generic indication that the server knows TRANS nothing to do for that call. */ -_S(ERR_MAP(EOPNOTSUPP), N_("Operation not supported")) +_S(EOPNOTSUPP, N_("Operation not supported")) #endif #ifdef EPFNOSUPPORT /* TRANS The socket communications protocol family you requested is not supported. */ -_S(ERR_MAP(EPFNOSUPPORT), N_("Protocol family not supported")) +_S(EPFNOSUPPORT, N_("Protocol family not supported")) #endif #ifdef EAFNOSUPPORT /* TRANS The address family specified for a socket is not supported; it is TRANS inconsistent with the protocol being used on the socket. @xref{Sockets}. */ -_S(ERR_MAP(EAFNOSUPPORT), N_("Address family not supported by protocol")) +_S(EAFNOSUPPORT, N_("Address family not supported by protocol")) #endif #ifdef EADDRINUSE /* TRANS The requested socket address is already in use. @xref{Socket Addresses}. */ -_S(ERR_MAP(EADDRINUSE), N_("Address already in use")) +_S(EADDRINUSE, N_("Address already in use")) #endif #ifdef EADDRNOTAVAIL /* TRANS The requested socket address is not available; for example, you tried TRANS to give a socket a name that doesn't match the local host name. TRANS @xref{Socket Addresses}. */ -_S(ERR_MAP(EADDRNOTAVAIL), N_("Cannot assign requested address")) +_S(EADDRNOTAVAIL, N_("Cannot assign requested address")) #endif #ifdef ENETDOWN /* TRANS A socket operation failed because the network was down. */ -_S(ERR_MAP(ENETDOWN), N_("Network is down")) +_S(ENETDOWN, N_("Network is down")) #endif #ifdef ENETUNREACH /* TRANS A socket operation failed because the subnet containing the remote host TRANS was unreachable. */ -_S(ERR_MAP(ENETUNREACH), N_("Network is unreachable")) +_S(ENETUNREACH, N_("Network is unreachable")) #endif #ifdef ENETRESET /* TRANS A network connection was reset because the remote host crashed. */ -_S(ERR_MAP(ENETRESET), N_("Network dropped connection on reset")) +_S(ENETRESET, N_("Network dropped connection on reset")) #endif #ifdef ECONNABORTED /* TRANS A network connection was aborted locally. */ -_S(ERR_MAP(ECONNABORTED), N_("Software caused connection abort")) +_S(ECONNABORTED, N_("Software caused connection abort")) #endif #ifdef ECONNRESET /* TRANS A network connection was closed for reasons outside the control of the TRANS local host, such as by the remote machine rebooting or an unrecoverable TRANS protocol violation. */ -_S(ERR_MAP(ECONNRESET), N_("Connection reset by peer")) +_S(ECONNRESET, N_("Connection reset by peer")) #endif #ifdef ENOBUFS /* TRANS The kernel's buffers for I/O operations are all in use. In GNU, this TRANS error is always synonymous with @code{ENOMEM}; you may get one or the TRANS other from network operations. */ -_S(ERR_MAP(ENOBUFS), N_("No buffer space available")) +_S(ENOBUFS, N_("No buffer space available")) #endif #ifdef EISCONN /* TRANS You tried to connect a socket that is already connected. TRANS @xref{Connecting}. */ -_S(ERR_MAP(EISCONN), N_("Transport endpoint is already connected")) +_S(EISCONN, N_("Transport endpoint is already connected")) #endif #ifdef ENOTCONN /* @@ -395,74 +392,74 @@ TRANS The socket is not connected to any TRANS try to transmit data over a socket, without first specifying a TRANS destination for the data. For a connectionless socket (for datagram TRANS protocols, such as UDP), you get @code{EDESTADDRREQ} instead. */ -_S(ERR_MAP(ENOTCONN), N_("Transport endpoint is not connected")) +_S(ENOTCONN, N_("Transport endpoint is not connected")) #endif #ifdef EDESTADDRREQ /* TRANS No default destination address was set for the socket. You get this TRANS error when you try to transmit data over a connectionless socket, TRANS without first specifying a destination for the data with @code{connect}. */ -_S(ERR_MAP(EDESTADDRREQ), N_("Destination address required")) +_S(EDESTADDRREQ, N_("Destination address required")) #endif #ifdef ESHUTDOWN /* TRANS The socket has already been shut down. */ -_S(ERR_MAP(ESHUTDOWN), N_("Cannot send after transport endpoint shutdown")) +_S(ESHUTDOWN, N_("Cannot send after transport endpoint shutdown")) #endif #ifdef ETOOMANYREFS -_S(ERR_MAP(ETOOMANYREFS), N_("Too many references: cannot splice")) +_S(ETOOMANYREFS, N_("Too many references: cannot splice")) #endif #ifdef ETIMEDOUT /* TRANS A socket operation with a specified timeout received no response during TRANS the timeout period. */ -_S(ERR_MAP(ETIMEDOUT), N_("Connection timed out")) +_S(ETIMEDOUT, N_("Connection timed out")) #endif #ifdef ECONNREFUSED /* TRANS A remote host refused to allow the network connection (typically because TRANS it is not running the requested service). */ -_S(ERR_MAP(ECONNREFUSED), N_("Connection refused")) +_S(ECONNREFUSED, N_("Connection refused")) #endif #ifdef ELOOP /* TRANS Too many levels of symbolic links were encountered in looking up a file name. TRANS This often indicates a cycle of symbolic links. */ -_S(ERR_MAP(ELOOP), N_("Too many levels of symbolic links")) +_S(ELOOP, N_("Too many levels of symbolic links")) #endif #ifdef ENAMETOOLONG /* TRANS Filename too long (longer than @code{PATH_MAX}; @pxref{Limits for TRANS Files}) or host name too long (in @code{gethostname} or TRANS @code{sethostname}; @pxref{Host Identification}). */ -_S(ERR_MAP(ENAMETOOLONG), N_("File name too long")) +_S(ENAMETOOLONG, N_("File name too long")) #endif #ifdef EHOSTDOWN /* TRANS The remote host for a requested network connection is down. */ -_S(ERR_MAP(EHOSTDOWN), N_("Host is down")) +_S(EHOSTDOWN, N_("Host is down")) #endif /* TRANS The remote host for a requested network connection is not reachable. */ #ifdef EHOSTUNREACH -_S(ERR_MAP(EHOSTUNREACH), N_("No route to host")) +_S(EHOSTUNREACH, N_("No route to host")) #endif #ifdef ENOTEMPTY /* TRANS Directory not empty, where an empty directory was expected. Typically, TRANS this error occurs when you are trying to delete a directory. */ -_S(ERR_MAP(ENOTEMPTY), N_("Directory not empty")) +_S(ENOTEMPTY, N_("Directory not empty")) #endif #ifdef EUSERS /* TRANS The file quota system is confused because there are too many users. TRANS @c This can probably happen in a GNU system when using NFS. */ -_S(ERR_MAP(EUSERS), N_("Too many users")) +_S(EUSERS, N_("Too many users")) #endif #ifdef EDQUOT /* TRANS The user's disk quota was exceeded. */ -_S(ERR_MAP(EDQUOT), N_("Disk quota exceeded")) +_S(EDQUOT, N_("Disk quota exceeded")) #endif #ifdef ESTALE /* @@ -471,7 +468,7 @@ TRANS file system which is due to file s TRANS for NFS file systems or corruption in other file systems. TRANS Repairing this condition usually requires unmounting, possibly repairing TRANS and remounting the file system. */ -_S(ERR_MAP(ESTALE), N_("Stale file handle")) +_S(ESTALE, N_("Stale file handle")) #endif #ifdef EREMOTE /* @@ -479,7 +476,7 @@ TRANS An attempt was made to NFS-mount a TRANS already specifies an NFS-mounted file. TRANS (This is an error on some operating systems, but we expect it to work TRANS properly on @gnuhurdsystems{}, making this error code impossible.) */ -_S(ERR_MAP(EREMOTE), N_("Object is remote")) +_S(EREMOTE, N_("Object is remote")) #endif #ifdef ENOLCK /* @@ -487,7 +484,7 @@ TRANS This is used by the file locking f TRANS @ref{File Locks}. This error is never generated by @gnuhurdsystems{}, but TRANS it can result from an operation to an NFS server running another TRANS operating system. */ -_S(ERR_MAP(ENOLCK), N_("No locks available")) +_S(ENOLCK, N_("No locks available")) #endif #ifdef ENOSYS /* @@ -496,46 +493,46 @@ TRANS not implemented at all, either in TRANS operating system. When you get this error, you can be sure that this TRANS particular function will always fail with @code{ENOSYS} unless you TRANS install a new version of the C library or the operating system. */ -_S(ERR_MAP(ENOSYS), N_("Function not implemented")) +_S(ENOSYS, N_("Function not implemented")) #endif #ifdef EILSEQ /* TRANS While decoding a multibyte character the function came along an invalid TRANS or an incomplete sequence of bytes or the given wide character is invalid. */ -_S(ERR_MAP(EILSEQ), N_("Invalid or incomplete multibyte or wide character")) +_S(EILSEQ, N_("Invalid or incomplete multibyte or wide character")) #endif #ifdef EBADMSG -_S(ERR_MAP(EBADMSG), N_("Bad message")) +_S(EBADMSG, N_("Bad message")) #endif #ifdef EIDRM -_S(ERR_MAP(EIDRM), N_("Identifier removed")) +_S(EIDRM, N_("Identifier removed")) #endif #ifdef EMULTIHOP -_S(ERR_MAP(EMULTIHOP), N_("Multihop attempted")) +_S(EMULTIHOP, N_("Multihop attempted")) #endif #ifdef ENODATA -_S(ERR_MAP(ENODATA), N_("No data available")) +_S(ENODATA, N_("No data available")) #endif #ifdef ENOLINK -_S(ERR_MAP(ENOLINK), N_("Link has been severed")) +_S(ENOLINK, N_("Link has been severed")) #endif #ifdef ENOMSG -_S(ERR_MAP(ENOMSG), N_("No message of desired type")) +_S(ENOMSG, N_("No message of desired type")) #endif #ifdef ENOSR -_S(ERR_MAP(ENOSR), N_("Out of streams resources")) +_S(ENOSR, N_("Out of streams resources")) #endif #ifdef ENOSTR -_S(ERR_MAP(ENOSTR), N_("Device not a stream")) +_S(ENOSTR, N_("Device not a stream")) #endif #ifdef EOVERFLOW -_S(ERR_MAP(EOVERFLOW), N_("Value too large for defined data type")) +_S(EOVERFLOW, N_("Value too large for defined data type")) #endif #ifdef EPROTO -_S(ERR_MAP(EPROTO), N_("Protocol error")) +_S(EPROTO, N_("Protocol error")) #endif #ifdef ETIME -_S(ERR_MAP(ETIME), N_("Timer expired")) +_S(ETIME, N_("Timer expired")) #endif #ifdef ECANCELED /* @@ -543,148 +540,148 @@ TRANS An asynchronous operation was canc TRANS completed. @xref{Asynchronous I/O}. When you call @code{aio_cancel}, TRANS the normal result is for the operations affected to complete with this TRANS error; @pxref{Cancel AIO Operations}. */ -_S(ERR_MAP(ECANCELED), N_("Operation canceled")) +_S(ECANCELED, N_("Operation canceled")) #endif #ifdef EOWNERDEAD -_S(ERR_MAP(EOWNERDEAD), N_("Owner died")) +_S(EOWNERDEAD, N_("Owner died")) #endif #ifdef ENOTRECOVERABLE -_S(ERR_MAP(ENOTRECOVERABLE), N_("State not recoverable")) +_S(ENOTRECOVERABLE, N_("State not recoverable")) #endif #ifdef ERESTART -_S(ERR_MAP(ERESTART), N_("Interrupted system call should be restarted")) +_S(ERESTART, N_("Interrupted system call should be restarted")) #endif #ifdef ECHRNG -_S(ERR_MAP(ECHRNG), N_("Channel number out of range")) +_S(ECHRNG, N_("Channel number out of range")) #endif #ifdef EL2NSYNC -_S(ERR_MAP(EL2NSYNC), N_("Level 2 not synchronized")) +_S(EL2NSYNC, N_("Level 2 not synchronized")) #endif #ifdef EL3HLT -_S(ERR_MAP(EL3HLT), N_("Level 3 halted")) +_S(EL3HLT, N_("Level 3 halted")) #endif #ifdef EL3RST -_S(ERR_MAP(EL3RST), N_("Level 3 reset")) +_S(EL3RST, N_("Level 3 reset")) #endif #ifdef ELNRNG -_S(ERR_MAP(ELNRNG), N_("Link number out of range")) +_S(ELNRNG, N_("Link number out of range")) #endif #ifdef EUNATCH -_S(ERR_MAP(EUNATCH), N_("Protocol driver not attached")) +_S(EUNATCH, N_("Protocol driver not attached")) #endif #ifdef ENOCSI -_S(ERR_MAP(ENOCSI), N_("No CSI structure available")) +_S(ENOCSI, N_("No CSI structure available")) #endif #ifdef EL2HLT -_S(ERR_MAP(EL2HLT), N_("Level 2 halted")) +_S(EL2HLT, N_("Level 2 halted")) #endif #ifdef EBADE -_S(ERR_MAP(EBADE), N_("Invalid exchange")) +_S(EBADE, N_("Invalid exchange")) #endif #ifdef EBADR -_S(ERR_MAP(EBADR), N_("Invalid request descriptor")) +_S(EBADR, N_("Invalid request descriptor")) #endif #ifdef EXFULL -_S(ERR_MAP(EXFULL), N_("Exchange full")) +_S(EXFULL, N_("Exchange full")) #endif #ifdef ENOANO -_S(ERR_MAP(ENOANO), N_("No anode")) +_S(ENOANO, N_("No anode")) #endif #ifdef EBADRQC -_S(ERR_MAP(EBADRQC), N_("Invalid request code")) +_S(EBADRQC, N_("Invalid request code")) #endif #ifdef EBADSLT -_S(ERR_MAP(EBADSLT), N_("Invalid slot")) +_S(EBADSLT, N_("Invalid slot")) #endif #ifdef EBFONT -_S(ERR_MAP(EBFONT), N_("Bad font file format")) +_S(EBFONT, N_("Bad font file format")) #endif #ifdef ENONET -_S(ERR_MAP(ENONET), N_("Machine is not on the network")) +_S(ENONET, N_("Machine is not on the network")) #endif #ifdef ENOPKG -_S(ERR_MAP(ENOPKG), N_("Package not installed")) +_S(ENOPKG, N_("Package not installed")) #endif #ifdef EADV -_S(ERR_MAP(EADV), N_("Advertise error")) +_S(EADV, N_("Advertise error")) #endif #ifdef ESRMNT -_S(ERR_MAP(ESRMNT), N_("Srmount error")) +_S(ESRMNT, N_("Srmount error")) #endif #ifdef ECOMM -_S(ERR_MAP(ECOMM), N_("Communication error on send")) +_S(ECOMM, N_("Communication error on send")) #endif #ifdef EDOTDOT -_S(ERR_MAP(EDOTDOT), N_("RFS specific error")) +_S(EDOTDOT, N_("RFS specific error")) #endif #ifdef ENOTUNIQ -_S(ERR_MAP(ENOTUNIQ), N_("Name not unique on network")) +_S(ENOTUNIQ, N_("Name not unique on network")) #endif #ifdef EBADFD -_S(ERR_MAP(EBADFD), N_("File descriptor in bad state")) +_S(EBADFD, N_("File descriptor in bad state")) #endif #ifdef EREMCHG -_S(ERR_MAP(EREMCHG), N_("Remote address changed")) +_S(EREMCHG, N_("Remote address changed")) #endif #ifdef ELIBACC -_S(ERR_MAP(ELIBACC), N_("Can not access a needed shared library")) +_S(ELIBACC, N_("Can not access a needed shared library")) #endif #ifdef ELIBBAD -_S(ERR_MAP(ELIBBAD), N_("Accessing a corrupted shared library")) +_S(ELIBBAD, N_("Accessing a corrupted shared library")) #endif #ifdef ELIBSCN -_S(ERR_MAP(ELIBSCN), N_(".lib section in a.out corrupted")) +_S(ELIBSCN, N_(".lib section in a.out corrupted")) #endif #ifdef ELIBMAX -_S(ERR_MAP(ELIBMAX), N_("Attempting to link in too many shared libraries")) +_S(ELIBMAX, N_("Attempting to link in too many shared libraries")) #endif #ifdef ELIBEXEC -_S(ERR_MAP(ELIBEXEC), N_("Cannot exec a shared library directly")) +_S(ELIBEXEC, N_("Cannot exec a shared library directly")) #endif #ifdef ESTRPIPE -_S(ERR_MAP(ESTRPIPE), N_("Streams pipe error")) +_S(ESTRPIPE, N_("Streams pipe error")) #endif #ifdef EUCLEAN -_S(ERR_MAP(EUCLEAN), N_("Structure needs cleaning")) +_S(EUCLEAN, N_("Structure needs cleaning")) #endif #ifdef ENOTNAM -_S(ERR_MAP(ENOTNAM), N_("Not a XENIX named type file")) +_S(ENOTNAM, N_("Not a XENIX named type file")) #endif #ifdef ENAVAIL -_S(ERR_MAP(ENAVAIL), N_("No XENIX semaphores available")) +_S(ENAVAIL, N_("No XENIX semaphores available")) #endif #ifdef EISNAM -_S(ERR_MAP(EISNAM), N_("Is a named type file")) +_S(EISNAM, N_("Is a named type file")) #endif #ifdef EREMOTEIO -_S(ERR_MAP(EREMOTEIO), N_("Remote I/O error")) +_S(EREMOTEIO, N_("Remote I/O error")) #endif #ifdef ENOMEDIUM -_S(ERR_MAP(ENOMEDIUM), N_("No medium found")) +_S(ENOMEDIUM, N_("No medium found")) #endif #ifdef EMEDIUMTYPE -_S(ERR_MAP(EMEDIUMTYPE), N_("Wrong medium type")) +_S(EMEDIUMTYPE, N_("Wrong medium type")) #endif #ifdef ENOKEY -_S(ERR_MAP(ENOKEY), N_("Required key not available")) +_S(ENOKEY, N_("Required key not available")) #endif #ifdef EKEYEXPIRED -_S(ERR_MAP(EKEYEXPIRED), N_("Key has expired")) +_S(EKEYEXPIRED, N_("Key has expired")) #endif #ifdef EKEYREVOKED -_S(ERR_MAP(EKEYREVOKED), N_("Key has been revoked")) +_S(EKEYREVOKED, N_("Key has been revoked")) #endif #ifdef EKEYREJECTED -_S(ERR_MAP(EKEYREJECTED), N_("Key was rejected by service")) +_S(EKEYREJECTED, N_("Key was rejected by service")) #endif #ifdef ERFKILL -_S(ERR_MAP(ERFKILL), N_("Operation not possible due to RF-kill")) +_S(ERFKILL, N_("Operation not possible due to RF-kill")) #endif #ifdef EHWPOISON -_S(ERR_MAP(EHWPOISON), N_("Memory page has hardware error")) +_S(EHWPOISON, N_("Memory page has hardware error")) #endif #ifdef EBADRPC -_S(ERR_MAP(EBADRPC), N_("RPC struct is bad")) +_S(EBADRPC, N_("RPC struct is bad")) #endif #ifdef EFTYPE /* @@ -693,40 +690,40 @@ TRANS operation, or a data file had the TRANS TRANS On some systems @code{chmod} returns this error if you try to set the TRANS sticky bit on a non-directory file; @pxref{Setting Permissions}. */ -_S(ERR_MAP(EFTYPE), N_("Inappropriate file type or format")) +_S(EFTYPE, N_("Inappropriate file type or format")) #endif #ifdef EPROCUNAVAIL -_S(ERR_MAP(EPROCUNAVAIL), N_("RPC bad procedure for program")) +_S(EPROCUNAVAIL, N_("RPC bad procedure for program")) #endif #ifdef EAUTH -_S(ERR_MAP(EAUTH), N_("Authentication error")) +_S(EAUTH, N_("Authentication error")) #endif #ifdef EDIED /* TRANS On @gnuhurdsystems{}, opening a file returns this error when the file is TRANS translated by a program and the translator program dies while starting TRANS up, before it has connected to the file. */ -_S(ERR_MAP(EDIED), N_("Translator died")) +_S(EDIED, N_("Translator died")) #endif #ifdef ERPCMISMATCH -_S(ERR_MAP(ERPCMISMATCH), N_("RPC version wrong")) +_S(ERPCMISMATCH, N_("RPC version wrong")) #endif #ifdef EGREGIOUS /* TRANS You did @strong{what}? */ -_S(ERR_MAP(EGREGIOUS), N_("You really blew it this time")) +_S(EGREGIOUS, N_("You really blew it this time")) #endif #ifdef EPROCLIM /* TRANS This means that the per-user limit on new process would be exceeded by TRANS an attempted @code{fork}. @xref{Limits on Resources}, for details on TRANS the @code{RLIMIT_NPROC} limit. */ -_S(ERR_MAP(EPROCLIM), N_("Too many processes")) +_S(EPROCLIM, N_("Too many processes")) #endif #ifdef EGRATUITOUS /* TRANS This error code has no purpose. */ -_S(ERR_MAP(EGRATUITOUS), N_("Gratuitous error")) +_S(EGRATUITOUS, N_("Gratuitous error")) #endif #if defined (ENOTSUP) && ENOTSUP != EOPNOTSUPP /* @@ -742,10 +739,10 @@ TRANS values. TRANS TRANS If the entire function is not available at all in the implementation, TRANS it returns @code{ENOSYS} instead. */ -_S(ERR_MAP(ENOTSUP), N_("Not supported")) +_S(ENOTSUP, N_("Not supported")) #endif #ifdef EPROGMISMATCH -_S(ERR_MAP(EPROGMISMATCH), N_("RPC program version wrong")) +_S(EPROGMISMATCH, N_("RPC program version wrong")) #endif #ifdef EBACKGROUND /* @@ -755,7 +752,7 @@ TRANS foreground process group of the te TRANS error because functions such as @code{read} and @code{write} translate TRANS it into a @code{SIGTTIN} or @code{SIGTTOU} signal. @xref{Job Control}, TRANS for information on process groups and these signals. */ -_S(ERR_MAP(EBACKGROUND), N_("Inappropriate operation for background process")) +_S(EBACKGROUND, N_("Inappropriate operation for background process")) #endif #ifdef EIEIO /* @@ -773,7 +770,7 @@ TRANS @c "bought the farm" means "died". TRANS @c TRANS @c Translators, please do not translate this litteraly, translate it into TRANS @c an idiomatic funny way of saying that the computer died. */ -_S(ERR_MAP(EIEIO), N_("Computer bought the farm")) +_S(EIEIO, N_("Computer bought the farm")) #endif #if defined (EWOULDBLOCK) && EWOULDBLOCK != EAGAIN /* @@ -782,18 +779,18 @@ TRANS The values are always the same, on TRANS TRANS C libraries in many older Unix systems have @code{EWOULDBLOCK} as a TRANS separate error code. */ -_S(ERR_MAP(EWOULDBLOCK), N_("Operation would block")) +_S(EWOULDBLOCK, N_("Operation would block")) #endif #ifdef ENEEDAUTH -_S(ERR_MAP(ENEEDAUTH), N_("Need authenticator")) +_S(ENEEDAUTH, N_("Need authenticator")) #endif #ifdef ED /* TRANS The experienced user will know what is wrong. TRANS @c This error code is a joke. Its perror text is part of the joke. TRANS @c Don't change it. */ -_S(ERR_MAP(ED), N_("?")) +_S(ED, N_("?")) #endif #ifdef EPROGUNAVAIL -_S(ERR_MAP(EPROGUNAVAIL), N_("RPC program not available")) +_S(EPROGUNAVAIL, N_("RPC program not available")) #endif diff -pruN glibc-2.32.orig/sysdeps/i386/dl-machine.h glibc-2.32/sysdeps/i386/dl-machine.h --- glibc-2.32.orig/sysdeps/i386/dl-machine.h 2021-09-18 21:02:32.707184853 +1000 +++ glibc-2.32/sysdeps/i386/dl-machine.h 2021-09-18 21:03:05.313302322 +1000 @@ -338,16 +338,22 @@ elf_machine_rel (struct link_map *map, c { # ifndef RTLD_BOOTSTRAP if (sym_map != map - && sym_map->l_type != lt_executable && !sym_map->l_relocated) { const char *strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]); - _dl_error_printf ("\ + if (sym_map->l_type == lt_executable) + _dl_fatal_printf ("\ +%s: IFUNC symbol '%s' referenced in '%s' is defined in the executable \ +and creates an unsatisfiable circular dependency.\n", + RTLD_PROGNAME, strtab + refsym->st_name, + map->l_name); + else + _dl_error_printf ("\ %s: Relink `%s' with `%s' for IFUNC symbol `%s'\n", - RTLD_PROGNAME, map->l_name, - sym_map->l_name, - strtab + refsym->st_name); + RTLD_PROGNAME, map->l_name, + sym_map->l_name, + strtab + refsym->st_name); } # endif value = ((Elf32_Addr (*) (void)) value) (); diff -pruN glibc-2.32.orig/sysdeps/powerpc/powerpc64/backtrace.c glibc-2.32/sysdeps/powerpc/powerpc64/backtrace.c --- glibc-2.32.orig/sysdeps/powerpc/powerpc64/backtrace.c 2021-09-18 21:02:32.723185402 +1000 +++ glibc-2.32/sysdeps/powerpc/powerpc64/backtrace.c 2021-09-18 21:03:05.313302322 +1000 @@ -54,11 +54,22 @@ struct signal_frame_64 { /* We don't care about the rest, since the IP value is at 'uc' field. */ }; +/* Test if the address match to the inside the trampoline code. + Up to and including kernel 5.8, returning from an interrupt or syscall to a + signal handler starts execution directly at the handler's entry point, with + LR set to address of the sigreturn trampoline (the vDSO symbol). + Newer kernels will branch to signal handler from the trampoline instead, so + checking the stacktrace against the vDSO entrypoint does not work in such + case. + The vDSO branches with a 'bctrl' instruction, so checking either the + vDSO address itself and the next instruction should cover all kernel + versions. */ static inline bool is_sigtramp_address (void *nip) { #ifdef HAVE_SIGTRAMP_RT64 - if (nip == GLRO (dl_vdso_sigtramp_rt64)) + if (nip == GLRO (dl_vdso_sigtramp_rt64) || + nip == GLRO (dl_vdso_sigtramp_rt64) + 4) return true; #endif return false; diff -pruN glibc-2.32.orig/sysdeps/s390/configure glibc-2.32/sysdeps/s390/configure --- glibc-2.32.orig/sysdeps/s390/configure 2021-09-18 21:02:32.727185539 +1000 +++ glibc-2.32/sysdeps/s390/configure 2021-09-18 21:03:05.313302322 +1000 @@ -123,7 +123,9 @@ void testinsn (char *buf) __asm__ (".machine \"arch13\" \n\t" ".machinemode \"zarch_nohighgprs\" \n\t" "lghi %%r0,16 \n\t" - "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); + "mvcrl 0(%0),32(%0) \n\t" + "vstrs %%v20,%%v20,%%v20,%%v20,0,2" + : : "a" (buf) : "memory", "r0"); } EOF if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c @@ -271,7 +273,9 @@ else void testinsn (char *buf) { __asm__ ("lghi %%r0,16 \n\t" - "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); + "mvcrl 0(%0),32(%0) \n\t" + "vstrs %%v20,%%v20,%%v20,%%v20,0,2" + : : "a" (buf) : "memory", "r0"); } EOF if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c diff -pruN glibc-2.32.orig/sysdeps/s390/configure.ac glibc-2.32/sysdeps/s390/configure.ac --- glibc-2.32.orig/sysdeps/s390/configure.ac 2021-09-18 21:02:32.727185539 +1000 +++ glibc-2.32/sysdeps/s390/configure.ac 2021-09-18 21:03:05.313302322 +1000 @@ -88,7 +88,9 @@ void testinsn (char *buf) __asm__ (".machine \"arch13\" \n\t" ".machinemode \"zarch_nohighgprs\" \n\t" "lghi %%r0,16 \n\t" - "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); + "mvcrl 0(%0),32(%0) \n\t" + "vstrs %%v20,%%v20,%%v20,%%v20,0,2" + : : "a" (buf) : "memory", "r0"); } EOF dnl test, if assembler supports S390 arch13 instructions @@ -195,7 +197,9 @@ cat > conftest.c <<\EOF void testinsn (char *buf) { __asm__ ("lghi %%r0,16 \n\t" - "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); + "mvcrl 0(%0),32(%0) \n\t" + "vstrs %%v20,%%v20,%%v20,%%v20,0,2" + : : "a" (buf) : "memory", "r0"); } EOF dnl test, if assembler supports S390 arch13 zarch instructions as default diff -pruN glibc-2.32.orig/sysdeps/s390/memmove.c glibc-2.32/sysdeps/s390/memmove.c --- glibc-2.32.orig/sysdeps/s390/memmove.c 2021-09-18 21:02:32.727185539 +1000 +++ glibc-2.32/sysdeps/s390/memmove.c 2021-09-18 21:03:05.313302322 +1000 @@ -43,7 +43,7 @@ extern __typeof (__redirect_memmove) MEM s390_libc_ifunc_expr (__redirect_memmove, memmove, ({ s390_libc_ifunc_expr_stfle_init (); - (HAVE_MEMMOVE_ARCH13 + (HAVE_MEMMOVE_ARCH13 && (hwcap & HWCAP_S390_VXRS_EXT2) && S390_IS_ARCH13_MIE3 (stfle_bits)) ? MEMMOVE_ARCH13 : (HAVE_MEMMOVE_Z13 && (hwcap & HWCAP_S390_VX)) diff -pruN glibc-2.32.orig/sysdeps/s390/multiarch/ifunc-impl-list.c glibc-2.32/sysdeps/s390/multiarch/ifunc-impl-list.c --- glibc-2.32.orig/sysdeps/s390/multiarch/ifunc-impl-list.c 2021-09-18 21:02:32.727185539 +1000 +++ glibc-2.32/sysdeps/s390/multiarch/ifunc-impl-list.c 2021-09-18 21:03:05.313302322 +1000 @@ -171,7 +171,8 @@ __libc_ifunc_impl_list (const char *name IFUNC_IMPL (i, name, memmove, # if HAVE_MEMMOVE_ARCH13 IFUNC_IMPL_ADD (array, i, memmove, - S390_IS_ARCH13_MIE3 (stfle_bits), + ((dl_hwcap & HWCAP_S390_VXRS_EXT2) + && S390_IS_ARCH13_MIE3 (stfle_bits)), MEMMOVE_ARCH13) # endif # if HAVE_MEMMOVE_Z13 diff -pruN glibc-2.32.orig/sysdeps/sh/be/sh4/fpu/Implies glibc-2.32/sysdeps/sh/be/sh4/fpu/Implies --- glibc-2.32.orig/sysdeps/sh/be/sh4/fpu/Implies 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/sysdeps/sh/be/sh4/fpu/Implies 2021-09-18 21:03:05.313302322 +1000 @@ -0,0 +1 @@ +sh/sh4/fpu diff -pruN glibc-2.32.orig/sysdeps/sh/le/sh4/fpu/Implies glibc-2.32/sysdeps/sh/le/sh4/fpu/Implies --- glibc-2.32.orig/sysdeps/sh/le/sh4/fpu/Implies 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/sysdeps/sh/le/sh4/fpu/Implies 2021-09-18 21:03:05.313302322 +1000 @@ -0,0 +1 @@ +sh/sh4/fpu diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/aarch64/cpu-features.h glibc-2.32/sysdeps/unix/sysv/linux/aarch64/cpu-features.h --- glibc-2.32.orig/sysdeps/unix/sysv/linux/aarch64/cpu-features.h 2021-09-18 21:02:32.731185676 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/aarch64/cpu-features.h 2021-09-18 21:03:05.313302322 +1000 @@ -54,6 +54,10 @@ && 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' \ + && MIDR_PARTNUM(midr) == 0xd49) +#define IS_NEOVERSE_V1(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \ + && MIDR_PARTNUM(midr) == 0xd40) #define IS_EMAG(midr) (MIDR_IMPLEMENTOR(midr) == 'P' \ && MIDR_PARTNUM(midr) == 0x000) diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/Makefile glibc-2.32/sysdeps/unix/sysv/linux/Makefile --- glibc-2.32.orig/sysdeps/unix/sysv/linux/Makefile 2021-09-18 21:02:32.731185676 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/Makefile 2021-09-18 21:03:05.313302322 +1000 @@ -100,7 +100,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \ test-errno-linux tst-memfd_create tst-mlock2 tst-pkey \ tst-rlimit-infinity tst-ofdlocks tst-gettid tst-gettid-kill \ - tst-tgkill + tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux tests-internal += tst-ofdlocks-compat tst-sigcontext-get_pc CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/mq_notify.c glibc-2.32/sysdeps/unix/sysv/linux/mq_notify.c --- glibc-2.32.orig/sysdeps/unix/sysv/linux/mq_notify.c 2021-09-18 21:02:32.736185847 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/mq_notify.c 2021-09-18 21:09:50.680196980 +1000 @@ -132,9 +132,12 @@ helper_thread (void *arg) to wait until it is done with it. */ (void) __pthread_barrier_wait (¬ify_barrier); } - else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) - /* The only state we keep is the copy of the thread attributes. */ - free (data.attr); + else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL) + { + /* The only state we keep is the copy of the thread attributes. */ + pthread_attr_destroy (data.attr); + free (data.attr); + } } return NULL; } @@ -255,8 +258,14 @@ mq_notify (mqd_t mqdes, const struct sig if (data.attr == NULL) return -1; - memcpy (data.attr, notification->sigev_notify_attributes, - sizeof (pthread_attr_t)); + int ret = __pthread_attr_copy (data.attr, + notification->sigev_notify_attributes); + if (ret != 0) + { + free (data.attr); + __set_errno (ret); + return -1; + } } /* Construct the new request. */ @@ -269,8 +278,11 @@ mq_notify (mqd_t mqdes, const struct sig int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se); /* If it failed, free the allocated memory. */ - if (__glibc_unlikely (retval != 0)) - free (data.attr); + if (retval != 0 && data.attr != NULL) + { + pthread_attr_destroy (data.attr); + free (data.attr); + } return retval; } diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/msgctl.c glibc-2.32/sysdeps/unix/sysv/linux/msgctl.c --- glibc-2.32.orig/sysdeps/unix/sysv/linux/msgctl.c 2021-09-18 21:02:32.736185847 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/msgctl.c 2021-09-18 21:03:05.313302322 +1000 @@ -90,8 +90,15 @@ __msgctl64 (int msqid, int cmd, struct _ struct kernel_msqid64_ds ksemid, *arg = NULL; if (buf != NULL) { - msqid64_to_kmsqid64 (buf, &ksemid); - arg = &ksemid; + /* This is a Linux extension where kernel returns a 'struct msginfo' + instead. */ + if (cmd == IPC_INFO || cmd == MSG_INFO) + arg = (struct kernel_msqid64_ds *) buf; + else + { + msqid64_to_kmsqid64 (buf, &ksemid); + arg = &ksemid; + } } # ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T if (cmd == IPC_SET) @@ -169,8 +176,15 @@ __msgctl (int msqid, int cmd, struct msq struct __msqid64_ds msqid64, *buf64 = NULL; if (buf != NULL) { - msqid_to_msqid64 (&msqid64, buf); - buf64 = &msqid64; + /* This is a Linux extension where kernel returns a 'struct msginfo' + instead. */ + if (cmd == IPC_INFO || cmd == MSG_INFO) + buf64 = (struct __msqid64_ds *) buf; + else + { + msqid_to_msqid64 (&msqid64, buf); + buf64 = &msqid64; + } } int ret = __msgctl64 (msqid, cmd, buf64); diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/semctl.c glibc-2.32/sysdeps/unix/sysv/linux/semctl.c --- glibc-2.32.orig/sysdeps/unix/sysv/linux/semctl.c 2021-09-18 21:02:32.739185950 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/semctl.c 2021-09-18 21:03:05.313302322 +1000 @@ -102,6 +102,7 @@ semun64_to_ksemun64 (int cmd, union semu r.array = semun64.array; break; case SEM_STAT: + case SEM_STAT_ANY: case IPC_STAT: case IPC_SET: r.buf = buf; @@ -150,6 +151,7 @@ __semctl64 (int semid, int semnum, int c case IPC_STAT: /* arg.buf */ case IPC_SET: case SEM_STAT: + case SEM_STAT_ANY: case IPC_INFO: /* arg.__buf */ case SEM_INFO: va_start (ap, cmd); @@ -238,6 +240,7 @@ semun_to_semun64 (int cmd, union semun s r.array = semun.array; break; case SEM_STAT: + case SEM_STAT_ANY: case IPC_STAT: case IPC_SET: r.buf = semid64; @@ -267,6 +270,7 @@ __semctl (int semid, int semnum, int cmd case IPC_STAT: /* arg.buf */ case IPC_SET: case SEM_STAT: + case SEM_STAT_ANY: case IPC_INFO: /* arg.__buf */ case SEM_INFO: va_start (ap, cmd); @@ -321,6 +325,7 @@ __semctl_mode16 (int semid, int semnum, case IPC_STAT: /* arg.buf */ case IPC_SET: case SEM_STAT: + case SEM_STAT_ANY: case IPC_INFO: /* arg.__buf */ case SEM_INFO: va_start (ap, cmd); @@ -354,6 +359,7 @@ __old_semctl (int semid, int semnum, int case IPC_STAT: /* arg.buf */ case IPC_SET: case SEM_STAT: + case SEM_STAT_ANY: case IPC_INFO: /* arg.__buf */ case SEM_INFO: va_start (ap, cmd); diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/sh/be/sh4/fpu/Implies glibc-2.32/sysdeps/unix/sysv/linux/sh/be/sh4/fpu/Implies --- glibc-2.32.orig/sysdeps/unix/sysv/linux/sh/be/sh4/fpu/Implies 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/sh/be/sh4/fpu/Implies 2021-09-18 21:03:05.313302322 +1000 @@ -0,0 +1 @@ +unix/sysv/linux/sh/sh4/fpu diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/sh/le/sh4/fpu/Implies glibc-2.32/sysdeps/unix/sysv/linux/sh/le/sh4/fpu/Implies --- glibc-2.32.orig/sysdeps/unix/sysv/linux/sh/le/sh4/fpu/Implies 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/sh/le/sh4/fpu/Implies 2021-09-18 21:03:05.313302322 +1000 @@ -0,0 +1 @@ +unix/sysv/linux/sh/sh4/fpu diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/shmctl.c glibc-2.32/sysdeps/unix/sysv/linux/shmctl.c --- glibc-2.32.orig/sysdeps/unix/sysv/linux/shmctl.c 2021-09-18 21:02:32.740185984 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/shmctl.c 2021-09-18 21:03:05.313302322 +1000 @@ -90,8 +90,15 @@ __shmctl64 (int shmid, int cmd, struct _ struct kernel_shmid64_ds kshmid, *arg = NULL; if (buf != NULL) { - shmid64_to_kshmid64 (buf, &kshmid); - arg = &kshmid; + /* This is a Linux extension where kernel expects either a + 'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */ + if (cmd == IPC_INFO || cmd == SHM_INFO) + arg = (struct kernel_shmid64_ds *) buf; + else + { + shmid64_to_kshmid64 (buf, &kshmid); + arg = &kshmid; + } } # ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T if (cmd == IPC_SET) @@ -107,7 +114,6 @@ __shmctl64 (int shmid, int cmd, struct _ switch (cmd) { - case IPC_INFO: case IPC_STAT: case SHM_STAT: case SHM_STAT_ANY: @@ -168,8 +174,15 @@ __shmctl (int shmid, int cmd, struct shm struct __shmid64_ds shmid64, *buf64 = NULL; if (buf != NULL) { - shmid_to_shmid64 (&shmid64, buf); - buf64 = &shmid64; + /* This is a Linux extension where kernel expects either a + 'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */ + if (cmd == IPC_INFO || cmd == SHM_INFO) + buf64 = (struct __shmid64_ds *) buf; + else + { + shmid_to_shmid64 (&shmid64, buf); + buf64 = &shmid64; + } } int ret = __shmctl64 (shmid, cmd, buf64); @@ -178,7 +191,6 @@ __shmctl (int shmid, int cmd, struct shm switch (cmd) { - case IPC_INFO: case IPC_STAT: case SHM_STAT: case SHM_STAT_ANY: diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c --- glibc-2.32.orig/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c 2021-09-18 21:03:05.313302322 +1000 @@ -0,0 +1,177 @@ +/* Basic tests for Linux SYSV message queue extensions. + Copyright (C) 2020 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 + +#define MSGQ_MODE 0644 + +/* These are for the temporary file we generate. */ +static char *name; +static int msqid; + +static void +remove_msq (void) +{ + /* Enforce message queue removal in case of early test failure. + Ignore error since the msg may already have being removed. */ + msgctl (msqid, IPC_RMID, NULL); +} + +static void +do_prepare (int argc, char *argv[]) +{ + TEST_VERIFY_EXIT (create_temp_file ("tst-sysvmsg.", &name) != -1); +} + +#define PREPARE do_prepare + +struct test_msginfo +{ + int msgmax; + int msgmnb; + int msgmni; +}; + +/* It tries to obtain some system-wide SysV messsage queue information from + /proc to check against IPC_INFO/MSG_INFO. The /proc only returns the + tunables value of MSGMAX, MSGMNB, and MSGMNI. + + The kernel also returns constant value for MSGSSZ, MSGSEG and also MSGMAP, + MSGPOOL, and MSGTQL (for IPC_INFO). The issue to check them is they might + change over kernel releases. */ + +static int +read_proc_file (const char *file) +{ + FILE *f = fopen (file, "r"); + if (f == NULL) + FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file); + + int v; + int r = fscanf (f, "%d", & v); + TEST_VERIFY_EXIT (r == 1); + + fclose (f); + return v; +} + + +/* Check if the message queue with IDX (index into the kernel's internal + array) matches the one with KEY. The CMD is either MSG_STAT or + MSG_STAT_ANY. */ + +static bool +check_msginfo (int idx, key_t key, int cmd) +{ + struct msqid_ds msginfo; + int mid = msgctl (idx, cmd, &msginfo); + /* Ignore unused array slot returned by the kernel or information from + unknown message queue. */ + if ((mid == -1 && errno == EINVAL) || mid != msqid) + return false; + + if (mid == -1) + FAIL_EXIT1 ("msgctl with %s failed: %m", + cmd == MSG_STAT ? "MSG_STAT" : "MSG_STAT_ANY"); + + TEST_COMPARE (msginfo.msg_perm.__key, key); + TEST_COMPARE (msginfo.msg_perm.mode, MSGQ_MODE); + TEST_COMPARE (msginfo.msg_qnum, 0); + + return true; +} + +static int +do_test (void) +{ + atexit (remove_msq); + + key_t key = ftok (name, 'G'); + if (key == -1) + FAIL_EXIT1 ("ftok failed: %m"); + + msqid = msgget (key, MSGQ_MODE | IPC_CREAT); + if (msqid == -1) + FAIL_EXIT1 ("msgget failed: %m"); + + struct test_msginfo tipcinfo; + tipcinfo.msgmax = read_proc_file ("/proc/sys/kernel/msgmax"); + tipcinfo.msgmnb = read_proc_file ("/proc/sys/kernel/msgmnb"); + tipcinfo.msgmni = read_proc_file ("/proc/sys/kernel/msgmni"); + + int msqidx; + + { + struct msginfo ipcinfo; + msqidx = msgctl (msqid, IPC_INFO, (struct msqid_ds *) &ipcinfo); + if (msqidx == -1) + FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m"); + + TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax); + TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb); + TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni); + } + + /* Same as before but with MSG_INFO. */ + { + struct msginfo ipcinfo; + msqidx = msgctl (msqid, MSG_INFO, (struct msqid_ds *) &ipcinfo); + if (msqidx == -1) + FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m"); + + TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax); + TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb); + TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni); + } + + /* We check if the created message queue shows in global list. */ + bool found = false; + for (int i = 0; i <= msqidx; i++) + { + /* We can't tell apart if MSG_STAT_ANY is not supported (kernel older + than 4.17) or if the index used is invalid. So it just check if the + value returned from a valid call matches the created message + queue. */ + check_msginfo (i, key, MSG_STAT_ANY); + + if (check_msginfo (i, key, MSG_STAT)) + { + found = true; + break; + } + } + + if (!found) + FAIL_EXIT1 ("msgctl with MSG_STAT/MSG_STAT_ANY could not find the " + "created message queue"); + + if (msgctl (msqid, IPC_RMID, NULL) == -1) + FAIL_EXIT1 ("msgctl failed"); + + return 0; +} + +#include diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c --- glibc-2.32.orig/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c 2021-09-18 21:03:05.314302356 +1000 @@ -0,0 +1,184 @@ +/* Basic tests for Linux SYSV semaphore extensions. + Copyright (C) 2020 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 + +/* These are for the temporary file we generate. */ +static char *name; +static int semid; + +static void +remove_sem (void) +{ + /* Enforce message queue removal in case of early test failure. + Ignore error since the sem may already have being removed. */ + semctl (semid, 0, IPC_RMID, 0); +} + +static void +do_prepare (int argc, char *argv[]) +{ + TEST_VERIFY_EXIT (create_temp_file ("tst-sysvsem.", &name) != -1); +} + +#define PREPARE do_prepare + +#define SEM_MODE 0644 + +union semun +{ + int val; + struct semid_ds *buf; + unsigned short *array; + struct seminfo *__buf; +}; + +struct test_seminfo +{ + int semmsl; + int semmns; + int semopm; + int semmni; +}; + +/* It tries to obtain some system-wide SysV semaphore information from /proc + to check against IPC_INFO/SEM_INFO. The /proc only returns the tunables + value of SEMMSL, SEMMNS, SEMOPM, and SEMMNI. + + The kernel also returns constant value for SEMVMX, SEMMNU, SEMMAP, SEMUME, + and also SEMUSZ and SEMAEM (for IPC_INFO). The issue to check them is they + might change over kernel releases. */ + +static void +read_sem_stat (struct test_seminfo *tseminfo) +{ + FILE *f = fopen ("/proc/sys/kernel/sem", "r"); + if (f == NULL) + FAIL_UNSUPPORTED ("/proc is not mounted or /proc/sys/kernel/sem is not " + "available"); + + int r = fscanf (f, "%d %d %d %d", + &tseminfo->semmsl, &tseminfo->semmns, &tseminfo->semopm, + &tseminfo->semmni); + TEST_VERIFY_EXIT (r == 4); + + fclose (f); +} + + +/* Check if the semaphore with IDX (index into the kernel's internal array) + matches the one with KEY. The CMD is either SEM_STAT or SEM_STAT_ANY. */ + +static bool +check_seminfo (int idx, key_t key, int cmd) +{ + struct semid_ds seminfo; + int sid = semctl (idx, 0, cmd, (union semun) { .buf = &seminfo }); + /* Ignore unused array slot returned by the kernel or information from + unknown semaphores. */ + if ((sid == -1 && errno == EINVAL) || sid != semid) + return false; + + if (sid == -1) + FAIL_EXIT1 ("semctl with SEM_STAT failed (errno=%d)", errno); + + TEST_COMPARE (seminfo.sem_perm.__key, key); + TEST_COMPARE (seminfo.sem_perm.mode, SEM_MODE); + TEST_COMPARE (seminfo.sem_nsems, 1); + + return true; +} + +static int +do_test (void) +{ + atexit (remove_sem); + + key_t key = ftok (name, 'G'); + if (key == -1) + FAIL_EXIT1 ("ftok failed: %m"); + + semid = semget (key, 1, IPC_CREAT | IPC_EXCL | SEM_MODE); + if (semid == -1) + FAIL_EXIT1 ("semget failed: %m"); + + struct test_seminfo tipcinfo; + read_sem_stat (&tipcinfo); + + int semidx; + + { + struct seminfo ipcinfo; + semidx = semctl (semid, 0, IPC_INFO, (union semun) { .__buf = &ipcinfo }); + if (semidx == -1) + FAIL_EXIT1 ("semctl with IPC_INFO failed: %m"); + + TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl); + TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns); + TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm); + TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni); + } + + /* Same as before but with SEM_INFO. */ + { + struct seminfo ipcinfo; + semidx = semctl (semid, 0, SEM_INFO, (union semun) { .__buf = &ipcinfo }); + if (semidx == -1) + FAIL_EXIT1 ("semctl with IPC_INFO failed: %m"); + + TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl); + TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns); + TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm); + TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni); + } + + /* We check if the created semaphore shows in the system-wide status. */ + bool found = false; + for (int i = 0; i <= semidx; i++) + { + /* We can't tell apart if SEM_STAT_ANY is not supported (kernel older + than 4.17) or if the index used is invalid. So it just check if + value returned from a valid call matches the created semaphore. */ + check_seminfo (i, key, SEM_STAT_ANY); + + if (check_seminfo (i, key, SEM_STAT)) + { + found = true; + break; + } + } + + if (!found) + FAIL_EXIT1 ("semctl with SEM_STAT/SEM_STAT_ANY could not find the " + "created semaphore"); + + if (semctl (semid, 0, IPC_RMID, 0) == -1) + FAIL_EXIT1 ("semctl failed: %m"); + + return 0; +} + +#include diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c --- glibc-2.32.orig/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c 2021-09-18 21:03:05.314302356 +1000 @@ -0,0 +1,185 @@ +/* Basic tests for Linux SYSV shared memory extensions. + Copyright (C) 2020 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 + +#define SHM_MODE 0644 + +/* These are for the temporary file we generate. */ +static char *name; +static int shmid; +static long int pgsz; + +static void +remove_shm (void) +{ + /* Enforce message queue removal in case of early test failure. + Ignore error since the shm may already have being removed. */ + shmctl (shmid, IPC_RMID, NULL); +} + +static void +do_prepare (int argc, char *argv[]) +{ + TEST_VERIFY_EXIT (create_temp_file ("tst-sysvshm.", &name) != -1); +} + +#define PREPARE do_prepare + +struct test_shminfo +{ + unsigned long int shmall; + unsigned long int shmmax; + unsigned long int shmmni; +}; + +/* It tries to obtain some system-wide SysV shared memory information from + /proc to check against IPC_INFO/SHM_INFO. The /proc only returns the + tunables value of SHMALL, SHMMAX, and SHMMNI. */ + +static uint64_t +read_proc_file (const char *file) +{ + FILE *f = fopen (file, "r"); + if (f == NULL) + FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file); + + /* Handle 32-bit binaries running on 64-bit kernels. */ + uint64_t v; + int r = fscanf (f, "%" SCNu64, &v); + TEST_VERIFY_EXIT (r == 1); + + fclose (f); + return v; +} + + +/* Check if the message queue with IDX (index into the kernel's internal + array) matches the one with KEY. The CMD is either SHM_STAT or + SHM_STAT_ANY. */ + +static bool +check_shminfo (int idx, key_t key, int cmd) +{ + struct shmid_ds shminfo; + int sid = shmctl (idx, cmd, &shminfo); + /* Ignore unused array slot returned by the kernel or information from + unknown message queue. */ + if ((sid == -1 && errno == EINVAL) || sid != shmid) + return false; + + if (sid == -1) + FAIL_EXIT1 ("shmctl with %s failed: %m", + cmd == SHM_STAT ? "SHM_STAT" : "SHM_STAT_ANY"); + + TEST_COMPARE (shminfo.shm_perm.__key, key); + TEST_COMPARE (shminfo.shm_perm.mode, SHM_MODE); + TEST_COMPARE (shminfo.shm_segsz, pgsz); + + return true; +} + +static int +do_test (void) +{ + atexit (remove_shm); + + pgsz = sysconf (_SC_PAGESIZE); + if (pgsz == -1) + FAIL_EXIT1 ("sysconf (_SC_PAGESIZE) failed: %m"); + + key_t key = ftok (name, 'G'); + if (key == -1) + FAIL_EXIT1 ("ftok failed: %m"); + + shmid = shmget (key, pgsz, IPC_CREAT | IPC_EXCL | SHM_MODE); + if (shmid == -1) + FAIL_EXIT1 ("shmget failed: %m"); + + struct test_shminfo tipcinfo; + { + uint64_t v = read_proc_file ("/proc/sys/kernel/shmmax"); +#if LONG_MAX == INT_MAX + /* Kernel explicit clamp the value for shmmax on compat symbol (32-bit + binaries running on 64-bit kernels). */ + if (v > INT_MAX) + v = INT_MAX; +#endif + tipcinfo.shmmax = v; + } + tipcinfo.shmall = read_proc_file ("/proc/sys/kernel/shmall"); + tipcinfo.shmmni = read_proc_file ("/proc/sys/kernel/shmmni"); + + int shmidx; + + /* Note: SHM_INFO does not return a shminfo, but rather a 'struct shm_info'. + It is tricky to verify its values since the syscall returns system wide + resources consumed by shared memory. The shmctl implementation handles + SHM_INFO as IPC_INFO, so the IPC_INFO test should validate SHM_INFO as + well. */ + + { + struct shminfo ipcinfo; + shmidx = shmctl (shmid, IPC_INFO, (struct shmid_ds *) &ipcinfo); + if (shmidx == -1) + FAIL_EXIT1 ("shmctl with IPC_INFO failed: %m"); + + TEST_COMPARE (ipcinfo.shmall, tipcinfo.shmall); + TEST_COMPARE (ipcinfo.shmmax, tipcinfo.shmmax); + TEST_COMPARE (ipcinfo.shmmni, tipcinfo.shmmni); + } + + /* We check if the created shared memory shows in the global list. */ + bool found = false; + for (int i = 0; i <= shmidx; i++) + { + /* We can't tell apart if SHM_STAT_ANY is not supported (kernel older + than 4.17) or if the index used is invalid. So it just check if + value returned from a valid call matches the created message + queue. */ + check_shminfo (i, key, SHM_STAT_ANY); + + if (check_shminfo (i, key, SHM_STAT)) + { + found = true; + break; + } + } + + if (!found) + FAIL_EXIT1 ("shmctl with SHM_STAT/SHM_STAT_ANY could not find the " + "created shared memory"); + + if (shmctl (shmid, IPC_RMID, NULL) == -1) + FAIL_EXIT1 ("shmctl failed"); + + return 0; +} + +#include diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure --- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:02:32.741186019 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:03:05.314302356 +1000 @@ -4,10 +4,10 @@ test -n "$libc_cv_slibdir" || case "$prefix" in /usr | /usr/) - libc_cv_slibdir='/lib64' - libc_cv_rtlddir='/lib64' + libc_cv_slibdir='/lib' + libc_cv_rtlddir='/lib' if test "$libdir" = '${exec_prefix}/lib'; then - libdir='${exec_prefix}/lib64'; + libdir='${exec_prefix}/lib'; # Locale data can be shared between 32-bit and 64-bit libraries. libc_cv_complocaledir='${exec_prefix}/lib/locale' fi diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h --- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:02:32.742186053 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:03:05.314302356 +1000 @@ -18,9 +18,9 @@ #include #define SYSDEP_KNOWN_INTERPRETER_NAMES \ - { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ + { "/lib32/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ { "/libx32/ld-linux-x32.so.2", FLAG_ELF_LIBC6 }, \ - { "/lib64/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, + { "/lib/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, #define SYSDEP_KNOWN_LIBRARY_NAMES \ { "libc.so.6", FLAG_ELF_LIBC6 }, \ { "libm.so.6", FLAG_ELF_LIBC6 }, diff -pruN glibc-2.32.orig/sysdeps/x86/cacheinfo.c glibc-2.32/sysdeps/x86/cacheinfo.c --- glibc-2.32.orig/sysdeps/x86/cacheinfo.c 2021-09-18 21:02:32.742186053 +1000 +++ glibc-2.32/sysdeps/x86/cacheinfo.c 2021-09-18 21:03:05.314302356 +1000 @@ -808,7 +808,7 @@ init_cacheinfo (void) threads = 1 << ((ecx >> 12) & 0x0f); } - if (threads == 0) + if (threads == 0 || cpu_features->basic.family >= 0x17) { /* If APIC ID width is not available, use logical processor count. */ @@ -823,8 +823,22 @@ init_cacheinfo (void) if (threads > 0) shared /= threads; - /* Account for exclusive L2 and L3 caches. */ - shared += core; + /* Get shared cache per ccx for Zen architectures. */ + if (cpu_features->basic.family >= 0x17) + { + unsigned int eax; + + /* Get number of threads share the L3 cache in CCX. */ + __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); + + unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; + shared *= threads_per_ccx; + } + else + { + /* Account for exclusive L2 and L3 caches. */ + shared += core; + } } } @@ -854,14 +868,20 @@ init_cacheinfo (void) __x86_shared_cache_size = shared; } - /* The large memcpy micro benchmark in glibc shows that 6 times of - shared cache size is the approximate value above which non-temporal - store becomes faster on a 8-core processor. This is the 3/4 of the - total shared 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. */ __x86_shared_non_temporal_threshold = (cpu_features->non_temporal_threshold != 0 ? cpu_features->non_temporal_threshold - : __x86_shared_cache_size * threads * 3 / 4); + : __x86_shared_cache_size * 3 / 4); /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ unsigned int minimum_rep_movsb_threshold; diff -pruN glibc-2.32.orig/sysdeps/x86/dl-cet.c glibc-2.32/sysdeps/x86/dl-cet.c --- glibc-2.32.orig/sysdeps/x86/dl-cet.c 2021-09-18 21:02:32.742186053 +1000 +++ glibc-2.32/sysdeps/x86/dl-cet.c 2021-09-18 21:03:05.314302356 +1000 @@ -47,7 +47,10 @@ dl_cet_check (struct link_map *m, const /* No legacy object check if both IBT and SHSTK are always on. */ if (enable_ibt_type == cet_always_on && enable_shstk_type == cet_always_on) - return; + { + THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)); + return; + } /* Check if IBT is enabled by kernel. */ bool ibt_enabled diff -pruN glibc-2.32.orig/sysdeps/x86/dl-prop.h glibc-2.32/sysdeps/x86/dl-prop.h --- glibc-2.32.orig/sysdeps/x86/dl-prop.h 2021-09-18 21:02:32.742186053 +1000 +++ glibc-2.32/sysdeps/x86/dl-prop.h 2021-09-18 21:03:05.314302356 +1000 @@ -145,15 +145,15 @@ _dl_process_cet_property_note (struct li } static inline void __attribute__ ((unused)) -_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph) +_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph) { const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr); _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align); } static inline int __attribute__ ((always_inline)) -_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz, - void *data) +_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, + uint32_t datasz, void *data) { return 0; } diff -pruN glibc-2.32.orig/sysdeps/x86/Makefile glibc-2.32/sysdeps/x86/Makefile --- glibc-2.32.orig/sysdeps/x86/Makefile 2021-09-18 21:02:32.742186053 +1000 +++ glibc-2.32/sysdeps/x86/Makefile 2021-09-18 21:03:05.314302356 +1000 @@ -12,6 +12,12 @@ endif ifeq ($(subdir),setjmp) gen-as-const-headers += jmp_buf-ssp.sym sysdep_routines += __longjmp_cancel +ifneq ($(enable-cet),no) +ifneq ($(have-tunables),no) +tests += tst-setjmp-cet +tst-setjmp-cet-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on +endif +endif endif ifeq ($(subdir),string) diff -pruN glibc-2.32.orig/sysdeps/x86/tst-setjmp-cet.c glibc-2.32/sysdeps/x86/tst-setjmp-cet.c --- glibc-2.32.orig/sysdeps/x86/tst-setjmp-cet.c 1970-01-01 10:00:00.000000000 +1000 +++ glibc-2.32/sysdeps/x86/tst-setjmp-cet.c 2021-09-18 21:03:05.314302356 +1000 @@ -0,0 +1 @@ +#include diff -pruN glibc-2.32.orig/sysdeps/x86_64/configure glibc-2.32/sysdeps/x86_64/configure --- glibc-2.32.orig/sysdeps/x86_64/configure 2021-09-18 21:02:32.743186087 +1000 +++ glibc-2.32/sysdeps/x86_64/configure 2021-09-18 21:03:05.314302356 +1000 @@ -107,39 +107,6 @@ if test x"$build_mathvec" = xnotset; the build_mathvec=yes fi -if test "$static_pie" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker static PIE support" >&5 -$as_echo_n "checking for linker static PIE support... " >&6; } -if ${libc_cv_ld_static_pie+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat > conftest.s <<\EOF - .text - .global _start - .weak foo -_start: - leaq foo(%rip), %rax -EOF - libc_cv_pie_option="-Wl,-pie" - if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - libc_cv_ld_static_pie=yes - else - libc_cv_ld_static_pie=no - fi -rm -f conftest* -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ld_static_pie" >&5 -$as_echo "$libc_cv_ld_static_pie" >&6; } - if test "$libc_cv_ld_static_pie" != yes; then - as_fn_error $? "linker support for static PIE needed" "$LINENO" 5 - fi -fi - $as_echo "#define PI_STATIC_AND_HIDDEN 1" >>confdefs.h diff -pruN glibc-2.32.orig/sysdeps/x86_64/configure.ac glibc-2.32/sysdeps/x86_64/configure.ac --- glibc-2.32.orig/sysdeps/x86_64/configure.ac 2021-09-18 21:02:32.743186087 +1000 +++ glibc-2.32/sysdeps/x86_64/configure.ac 2021-09-18 21:03:05.314302356 +1000 @@ -53,31 +53,6 @@ if test x"$build_mathvec" = xnotset; the build_mathvec=yes fi -dnl Check if linker supports static PIE with the fix for -dnl -dnl https://sourceware.org/bugzilla/show_bug.cgi?id=21782 -dnl -if test "$static_pie" = yes; then - AC_CACHE_CHECK(for linker static PIE support, libc_cv_ld_static_pie, [dnl -cat > conftest.s <<\EOF - .text - .global _start - .weak foo -_start: - leaq foo(%rip), %rax -EOF - libc_cv_pie_option="-Wl,-pie" - if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&AS_MESSAGE_LOG_FD); then - libc_cv_ld_static_pie=yes - else - libc_cv_ld_static_pie=no - fi -rm -f conftest*]) - if test "$libc_cv_ld_static_pie" != yes; then - AC_MSG_ERROR([linker support for static PIE needed]) - fi -fi - dnl It is always possible to access static and hidden symbols in an dnl position independent way. AC_DEFINE(PI_STATIC_AND_HIDDEN) diff -pruN glibc-2.32.orig/sysdeps/x86_64/dl-machine.h glibc-2.32/sysdeps/x86_64/dl-machine.h --- glibc-2.32.orig/sysdeps/x86_64/dl-machine.h 2021-09-18 21:02:32.743186087 +1000 +++ glibc-2.32/sysdeps/x86_64/dl-machine.h 2021-09-18 21:03:05.314302356 +1000 @@ -315,16 +315,22 @@ elf_machine_rela (struct link_map *map, { # ifndef RTLD_BOOTSTRAP if (sym_map != map - && sym_map->l_type != lt_executable && !sym_map->l_relocated) { const char *strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]); - _dl_error_printf ("\ + if (sym_map->l_type == lt_executable) + _dl_fatal_printf ("\ +%s: IFUNC symbol '%s' referenced in '%s' is defined in the executable \ +and creates an unsatisfiable circular dependency.\n", + RTLD_PROGNAME, strtab + refsym->st_name, + map->l_name); + else + _dl_error_printf ("\ %s: Relink `%s' with `%s' for IFUNC symbol `%s'\n", - RTLD_PROGNAME, map->l_name, - sym_map->l_name, - strtab + refsym->st_name); + RTLD_PROGNAME, map->l_name, + sym_map->l_name, + strtab + refsym->st_name); } # endif value = ((ElfW(Addr) (*) (void)) value) (); diff -pruN glibc-2.32.orig/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h glibc-2.32/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h --- glibc-2.32.orig/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h 2021-09-18 21:02:32.743186087 +1000 +++ glibc-2.32/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h 2021-09-18 21:03:05.314302356 +1000 @@ -32,7 +32,7 @@ IFUNC_SELECTOR (void) && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) return OPTIMIZE (fma); - if (CPU_FEATURE_USABLE_P (cpu_features, FMA)) + if (CPU_FEATURE_USABLE_P (cpu_features, FMA4)) return OPTIMIZE (fma4); return OPTIMIZE (sse2); diff -pruN glibc-2.32.orig/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S glibc-2.32/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S --- glibc-2.32.orig/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S 2021-09-18 21:02:32.745186156 +1000 +++ glibc-2.32/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S 2021-09-18 21:03:05.314302356 +1000 @@ -56,6 +56,13 @@ # endif #endif +/* Avoid short distance rep movsb only with non-SSE vector. */ +#ifndef AVOID_SHORT_DISTANCE_REP_MOVSB +# define AVOID_SHORT_DISTANCE_REP_MOVSB (VEC_SIZE > 16) +#else +# define AVOID_SHORT_DISTANCE_REP_MOVSB 0 +#endif + #ifndef PREFETCH # define PREFETCH(addr) prefetcht0 addr #endif @@ -243,7 +250,21 @@ L(movsb): cmpq %r9, %rdi /* Avoid slow backward REP MOVSB. */ jb L(more_8x_vec_backward) +# if AVOID_SHORT_DISTANCE_REP_MOVSB + movq %rdi, %rcx + subq %rsi, %rcx + jmp 2f +# endif 1: +# if AVOID_SHORT_DISTANCE_REP_MOVSB + movq %rsi, %rcx + subq %rdi, %rcx +2: +/* Avoid "rep movsb" if RCX, the distance between source and destination, + is N*4GB + [1..63] with N >= 0. */ + cmpl $63, %ecx + jbe L(more_2x_vec) /* Avoid "rep movsb" if ECX <= 63. */ +# endif mov %RDX_LP, %RCX_LP rep movsb L(nop): diff -pruN glibc-2.32.orig/sysvipc/test-sysvsem.c glibc-2.32/sysvipc/test-sysvsem.c --- glibc-2.32.orig/sysvipc/test-sysvsem.c 2021-09-18 21:02:32.746186190 +1000 +++ glibc-2.32/sysvipc/test-sysvsem.c 2021-09-18 21:03:05.314302356 +1000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff -pruN glibc-2.32.orig/version.h glibc-2.32/version.h --- glibc-2.32.orig/version.h 2021-09-18 21:02:32.746186190 +1000 +++ glibc-2.32/version.h 2021-09-18 21:03:05.314302356 +1000 @@ -1,4 +1,4 @@ /* This file just defines the current version number of libc. */ -#define RELEASE "release" +#define RELEASE "stable" #define VERSION "2.32"